Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 4665 → Rev 4666

/branches/arm/kernel/arch/arm32/src/exception.c
58,159 → 58,6
/** Size of memory block occupied by exception vectors. */
#define EXC_VECTORS_SIZE (EXC_VECTORS * 4)
 
/** Switches to kernel stack and saves all registers there.
*
* Temporary exception stack is used to save a few registers
* before stack switch takes place.
*
* The stack fram created by the function looks like:
*
* |_________________|
* | |
* | SPSR |
* | |
* |_________________|
* | Stack Pointer |
* | of |
* | Previous Mode |
* |_________________|
* | Return address |
* | of |
* | Previous Mode |
* |_________________|
* | R0 - R12 |
* | of |
* | Previous Mode |
* |_________________|
* | Return address |
* | from |
* |Exception Handler|
* |_________________|
* | |
*
*/
inline static void setup_stack_and_save_regs()
{
asm volatile (
"ldr r13, =exc_stack\n"
"stmfd r13!, {r0-r3}\n"
"mrs r1, cpsr\n"
"bic r1, r1, #0x1f\n"
"mrs r2, spsr\n"
"and r0, r2, #0x1f\n"
"cmp r0, #0x10\n"
"bne 1f\n"
/* prev mode was usermode */
"mov r0, sp\n"
"mov r3, lr\n"
 
/* Switch to supervisor mode */
"orr r1, r1, #0x13\n"
"msr cpsr_c, r1\n"
 
/* Load sp with [supervisor_sp] */
"ldr r13, =supervisor_sp\n"
"ldr r13, [r13]\n"
 
/* Populate the stack frame */
"msr spsr, r2\n"
"mov lr, r3\n"
"stmfd r13!, {lr}\n"
"stmfd r13!, {r4-r12}\n"
"ldmfd r0!, {r4-r7}\n"
"stmfd r13!, {r4-r7}\n"
"stmfd r13!, {r13, lr}^\n"
"stmfd r13!, {r2}\n"
"b 2f\n"
 
/* mode was not usermode */
"1:\n"
/* Switch to previous mode which is undoubtedly the supervisor mode */
"orr r1, r1, r0\n"
"mov r0, lr\n"
"mov r3, sp\n"
"msr cpsr_c, r1\n"
 
/* Populate the stack frame */
"mov r1, sp\n"
"stmfd r13!, {r0}\n"
"stmfd r13!, {r4-r12}\n"
 
/* Store r0-r3 in r4-r7 and then push it on to stack */
"ldmfd r3!, {r4-r7}\n"
"stmfd r13!, {r4-r7}\n"
 
/* Push return address and stack pointer on to stack */
"stmfd r13!, {lr}\n"
"stmfd r13!, {r1}\n"
"mov lr, r0\n"
"msr spsr, r2\n"
"stmfd r13!, {r2}\n"
 
"2:\n"
);
}
 
/** Returns from exception mode.
*
* Previously saved state of registers (including control register)
* is restored from the stack.
*/
inline static void load_regs()
{
asm volatile(
"ldmfd r13!, {r0} \n"
"msr spsr, r0 \n"
"and r0, r0, #0x1f \n"
"cmp r0, #0x10 \n"
"bne 1f \n"
 
/* return to user mode */
"ldmfd r13!, {r13, lr}^ \n"
"b 2f \n"
 
/* return to non-user mode */
"1:\n"
"ldmfd r13!, {r1, r2} \n"
"mrs r3, cpsr \n"
"bic r3, r3, #0x1f \n"
"orr r3, r3, r0 \n"
"mrs r0, cpsr \n"
"msr cpsr_c, r3 \n"
 
"mov lr, r2 \n"
"msr cpsr_c, r0 \n"
 
/* actual return */
"2:\n"
"ldmfd r13!, {r0-r12, pc}^\n"
);
}
 
 
/** Calls exception dispatch routine. */
#define CALL_EXC_DISPATCH(exception) \
asm volatile ( \
"mov r0, %[exc]\n" \
"mov r1, r13\n" \
"bl exc_dispatch\n" \
:: [exc] "i" (exception) \
);\
 
/** General exception handler.
*
* Stores registers, dispatches the exception,
* and finally restores registers and returns from exception processing.
*
* @param exception Exception number.
*/
#define PROCESS_EXCEPTION(exception) \
setup_stack_and_save_regs(); \
CALL_EXC_DISPATCH(exception) \
load_regs();
 
/** Updates specified exception vector to jump to given handler.
*
* Addresses of handlers are stored in memory following exception vectors.
232,65 → 79,6
 
}
 
/** Low-level Reset Exception handler. */
static void reset_exception_entry(void)
{
PROCESS_EXCEPTION(EXC_RESET);
}
 
/** Low-level Software Interrupt Exception handler. */
static void swi_exception_entry(void)
{
PROCESS_EXCEPTION(EXC_SWI);
}
 
/** Low-level Undefined Instruction Exception handler. */
static void undef_instr_exception_entry(void)
{
PROCESS_EXCEPTION(EXC_UNDEF_INSTR);
}
 
/** Low-level Fast Interrupt Exception handler. */
static void fiq_exception_entry(void)
{
PROCESS_EXCEPTION(EXC_FIQ);
}
 
/** Low-level Prefetch Abort Exception handler. */
static void prefetch_abort_exception_entry(void)
{
asm volatile (
"sub lr, lr, #4"
);
PROCESS_EXCEPTION(EXC_PREFETCH_ABORT);
}
 
/** Low-level Data Abort Exception handler. */
static void data_abort_exception_entry(void)
{
asm volatile (
"sub lr, lr, #8"
);
PROCESS_EXCEPTION(EXC_DATA_ABORT);
}
 
/** Low-level Interrupt Exception handler.
*
* CPU is switched to Undefined mode before further interrupt processing
* because of possible occurence of nested interrupt exception, which
* would overwrite (and thus spoil) stack pointer.
*/
static void irq_exception_entry(void)
{
asm volatile (
"sub lr, lr, #4"
);
PROCESS_EXCEPTION(EXC_IRQ)
}
 
/** Software Interrupt handler.
*
* Dispatches the syscall.