OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [src/] [arch/] [arm/] [v6/] [exception.c] - Rev 6

Go to most recent revision | Compare with Previous | Blame | View Log

/*
 * Memory exception handling in process context.
 *
 * Copyright (C) 2007, 2008 Bahadir Balban
 */
#include <l4/generic/scheduler.h>
#include <l4/generic/thread.h>
#include <l4/api/thread.h>
#include <l4/generic/space.h>
#include <l4/generic/tcb.h>
#include <l4/generic/platform.h>
#include <l4/lib/printk.h>
#include <l4/api/ipc.h>
#include <l4/api/kip.h>
#include <l4/api/errno.h>
#include INC_ARCH(exception.h)
#include INC_GLUE(memlayout.h)
#include INC_GLUE(memory.h)
#include INC_GLUE(mapping.h)
#include INC_GLUE(message.h)
#include INC_GLUE(ipc.h)
#include INC_SUBARCH(mm.h)
 
int check_abort_type(u32 faulted_pc, u32 fsr, u32 far, u32 spsr)
{
	int ret = 0;
 
	/*
	 * On ARMv5, prefetch aborts dont have different
	 * status values. We validate them here and return.
	 */
	if (is_prefetch_abort(fsr)) {
		dbg_abort("Prefetch abort @ ", faulted_pc);
 
		/* Happened in any mode other than user */
		if (!is_user_mode(spsr)) {
			dprintk("Unhandled kernel prefetch "
				"abort at address ", far);
			return -EABORT;
		}
		return 0;
	}
 
	switch (fsr & FSR_FS_MASK) {
	/* Aborts that are expected on page faults: */
	case DABT_PERM_PAGE:
		dbg_abort("Page permission fault @ ", far);
		ret = 0;
		break;
	case DABT_XLATE_PAGE:
		dbg_abort("Page translation fault @ ", far);
		ret = 0;
		break;
	case DABT_XLATE_SECT:
		dbg_abort("Section translation fault @ ", far);
		ret = 0;
		break;
 
	/* Aborts that can't be handled by a pager yet: */
	case DABT_TERMINAL:
		dprintk("Terminal fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_VECTOR:
		dprintk("Vector abort (obsolete!) @ ", far);
		ret = -EABORT;
		break;
	case DABT_ALIGN:
		dprintk("Alignment fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_XLATE_LEVEL1:
		dprintk("External LVL1 translation fault @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_XLATE_LEVEL2:
		dprintk("External LVL2 translation fault @ ", far);
		ret = -EABORT;
		break;
	case DABT_DOMAIN_SECT:
		dprintk("Section domain fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_DOMAIN_PAGE:
		dprintk("Page domain fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_PERM_SECT:
		dprintk("Section permission fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_LFETCH_SECT:
		dprintk("External section linefetch "
			"fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_LFETCH_PAGE:
		dprintk("Page perm fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_NON_LFETCH_SECT:
		dprintk("External section non-linefetch "
			"fault dabt @ ", far);
		ret = -EABORT;
		break;
	case DABT_EXT_NON_LFETCH_PAGE:
		dprintk("External page non-linefetch "
			"fault dabt @ ", far);
		ret = -EABORT;
		break;
	default:
		dprintk("FATAL: Unrecognised/Unknown "
			"data abort @ ", far);
		dprintk("FATAL: FSR code: ", fsr);
		ret = -EABORT;
	}
 
	/*
	 * Check validity of data abort's source.
	 *
	 * FIXME: Why not use spsr to do this?
	 */
	if (is_kernel_address(faulted_pc)) {
		dprintk("Unhandled kernel data "
			"abort at address ",
			faulted_pc);
		ret = -EABORT;
	}
 
	return ret;
}
 
#if 0
void data_abort_handler(u32 faulted_pc, u32 fsr, u32 far)
{
	set_abort_type(fsr, ARM_DABT);
 
	dbg_abort("Data abort @ PC: ", faulted_pc);
 
	//printk("Data abort: %d, PC: 0x%x\n",
	//current->tid, faulted_pc);
 
	/* Check for more details */
	if (check_aborts(faulted_pc, fsr, far) < 0) {
		printascii("This abort can't be handled by "
			   "any pager.\n");
		goto error;
	}
 
	/* This notifies the pager */
	fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT);
 
	if (current->flags & TASK_SUSPENDING) {
		BUG_ON(current->nlocks);
		sched_suspend_sync();
	} else if (current->flags & TASK_EXITING) {
		BUG_ON(current->nlocks);
		sched_exit_sync();
	}
 
	return;
 
error:
	disable_irqs();
	dprintk("Unhandled data abort @ PC address: ", faulted_pc);
	dprintk("FAR:", far);
	dprintk("FSR:", fsr);
	printascii("Kernel panic.\n");
	printascii("Halting system...\n");
	while (1)
		;
}
 
void prefetch_abort_handler(u32 faulted_pc, u32 fsr, u32 far, u32 spsr)
{
	set_abort_type(fsr, ARM_PABT);
 
	if (check_aborts(faulted_pc, fsr, far) < 0) {
		printascii("This abort can't be handled by any pager.\n");
		goto error;
	}
 
	/* Did the abort occur in kernel mode? */
	if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC)
		goto error;
 
	fault_ipc_to_pager(faulted_pc, fsr, far, L4_IPC_TAG_PFAULT);
 
	if (current->flags & TASK_SUSPENDING) {
		BUG_ON(current->nlocks);
		sched_suspend_sync();
	} else if (current->flags & TASK_EXITING) {
		BUG_ON(current->nlocks);
		sched_exit_sync();
	}
 
	return;
 
error:
	disable_irqs();
	dprintk("Unhandled prefetch abort @ address: ", faulted_pc);
	dprintk("FAR:", far);
	dprintk("FSR:", fsr);
	dprintk("Aborted PSR:", spsr);
	printascii("Kernel panic.\n");
	printascii("Halting system...\n");
	while (1)
		;
}
 
void undef_handler(u32 undef_addr, u32 spsr, u32 lr)
{
	dbg_abort("Undefined instruction @ PC: ", undef_addr);
 
	//printk("Undefined instruction: tid: %d, PC: 0x%x, Mode: %s\n",
	//       current->tid, undef_addr,
	//       (spsr & ARM_MODE_MASK) == ARM_MODE_SVC ? "SVC" : "User");
 
	if ((spsr & ARM_MODE_MASK) == ARM_MODE_SVC) {
		printk("Panic: Undef in Kernel\n");
		goto error;
	}
 
	fault_ipc_to_pager(undef_addr, 0, undef_addr, L4_IPC_TAG_UNDEF_FAULT);
 
	if (current->flags & TASK_SUSPENDING) {
		BUG_ON(current->nlocks);
		sched_suspend_sync();
	} else if (current->flags & TASK_EXITING) {
		BUG_ON(current->nlocks);
		sched_exit_sync();
	}
 
	return;
 
error:
	disable_irqs();
	dprintk("SPSR:", spsr);
	dprintk("LR:", lr);
	printascii("Kernel panic.\n");
	printascii("Halting system...\n");
	while(1)
		;
}
#endif
 
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.