33,7 → 33,6 |
* @brief Exception handlers and exception initialization routines. |
*/ |
|
|
#include <arch/exception.h> |
#include <arch/debug/print.h> |
#include <arch/memstr.h> |
59,7 → 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 |
67,57 → 65,57 |
*/ |
inline static void setup_stack_and_save_regs() |
{ |
asm volatile("ldr r13, =exc_stack \n\ |
stmfd r13!, {r0} \n\ |
mrs r0, spsr \n\ |
and r0, r0, #0x1f \n\ |
cmp r0, #0x10 \n\ |
bne 1f \n\ |
\n\ |
@prev mode was usermode \n\ |
ldmfd r13!, {r0} \n\ |
ldr r13, =supervisor_sp \n\ |
ldr r13, [r13] \n\ |
stmfd r13!, {lr} \n\ |
stmfd r13!, {r0-r12} \n\ |
stmfd r13!, {r13, lr}^ \n\ |
mrs r0, spsr \n\ |
stmfd r13!, {r0} \n\ |
b 2f \n\ |
\n\ |
@prev mode was not usermode \n\ |
1: \n\ |
stmfd r13!, {r1, r2, r3} \n\ |
mrs r1, cpsr \n\ |
mov r2, lr \n\ |
bic r1, r1, #0x1f \n\ |
orr r1, r1, r0 \n\ |
mrs r0, cpsr \n\ |
msr cpsr_c, r1 \n\ |
\n\ |
mov r3, r13 \n\ |
stmfd r13!, {r2} \n\ |
mov r2, lr \n\ |
stmfd r13!, {r4-r12} \n\ |
mov r1, r13 \n\ |
@following two lines are for debugging \n\ |
mov sp, #0 \n\ |
mov lr, #0 \n\ |
msr cpsr_c, r0 \n\ |
\n\ |
ldmfd r13!, {r4, r5, r6, r7} \n\ |
stmfd r1!, {r4, r5, r6} \n\ |
stmfd r1!, {r7} \n\ |
stmfd r1!, {r2} \n\ |
stmfd r1!, {r3} \n\ |
mrs r0, spsr \n\ |
stmfd r1!, {r0} \n\ |
mov r13, r1 \n\ |
2:" |
); |
asm volatile( |
"ldr r13, =exc_stack \n" |
"stmfd r13!, {r0} \n" |
"mrs r0, spsr \n" |
"and r0, r0, #0x1f \n" |
"cmp r0, #0x10 \n" |
"bne 1f \n" |
|
/* prev mode was usermode */ |
"ldmfd r13!, {r0} \n" |
"ldr r13, =supervisor_sp \n" |
"ldr r13, [r13] \n" |
"stmfd r13!, {lr} \n" |
"stmfd r13!, {r0-r12} \n" |
"stmfd r13!, {r13, lr}^ \n" |
"mrs r0, spsr \n" |
"stmfd r13!, {r0} \n" |
"b 2f \n" |
|
/* mode was not usermode */ |
"1:\n" |
"stmfd r13!, {r1, r2, r3} \n" |
"mrs r1, cpsr \n" |
"mov r2, lr \n" |
"bic r1, r1, #0x1f \n" |
"orr r1, r1, r0 \n" |
"mrs r0, cpsr \n" |
"msr cpsr_c, r1 \n" |
|
"mov r3, r13 \n" |
"stmfd r13!, {r2} \n" |
"mov r2, lr \n" |
"stmfd r13!, {r4-r12} \n" |
"mov r1, r13 \n" |
/* the following two lines are for debugging */ |
"mov sp, #0 \n" |
"mov lr, #0 \n" |
"msr cpsr_c, r0 \n" |
|
"ldmfd r13!, {r4, r5, r6, r7} \n" |
"stmfd r1!, {r4, r5, r6} \n" |
"stmfd r1!, {r7} \n" |
"stmfd r1!, {r2} \n" |
"stmfd r1!, {r3} \n" |
"mrs r0, spsr \n" |
"stmfd r1!, {r0} \n" |
"mov r13, r1 \n" |
"2:\n" |
); |
} |
|
|
/** Returns from exception mode. |
* |
* Previously saved state of registers (including control register) |
125,32 → 123,34 |
*/ |
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 3f \n\ |
\n\ |
@return to user mode \n\ |
ldmfd r13!, {r13, lr}^ \n\ |
b 4f \n\ |
\n\ |
@return to non-user mode \n\ |
3: \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\ |
\n\ |
mov r13, r1 \n\ |
mov lr, r2 \n\ |
msr cpsr_c, r0 \n\ |
\n\ |
@actual return \n\ |
4: ldmfd r13, {r0-r12, pc}^" |
); |
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 r13, r1 \n" |
"mov lr, r2 \n" |
"msr cpsr_c, r0 \n" |
|
/* actual return */ |
"2:\n" |
"ldmfd r13, {r0-r12, pc}^\n" |
); |
} |
|
|
159,7 → 159,7 |
* |
* The default mode for interrupt servicing (Interrupt Mode) |
* can not be used because of nested interrupts (which can occur |
* because interrupt are enabled in higher levels of interrupt handler). |
* because interrupts are enabled in higher levels of interrupt handler). |
*/ |
inline static void switch_to_irq_servicing_mode() |
{ |
187,7 → 187,6 |
); |
} |
|
|
/** Calls exception dispatch routine. */ |
#define CALL_EXC_DISPATCH(exception) \ |
asm("mov r0, %0" : : "i" (exception)); \ |
194,7 → 193,6 |
asm("mov r1, r13"); \ |
asm("bl exc_dispatch"); |
|
|
/** General exception handler. |
* |
* Stores registers, dispatches the exception, |
207,7 → 205,6 |
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. |
227,7 → 224,6 |
|
} |
|
|
/** Low-level Reset Exception handler. */ |
static void reset_exception_entry() |
{ |
234,7 → 230,6 |
PROCESS_EXCEPTION(EXC_RESET); |
} |
|
|
/** Low-level Software Interrupt Exception handler. */ |
static void swi_exception_entry() |
{ |
241,7 → 236,6 |
PROCESS_EXCEPTION(EXC_SWI); |
} |
|
|
/** Low-level Undefined Instruction Exception handler. */ |
static void undef_instr_exception_entry() |
{ |
248,7 → 242,6 |
PROCESS_EXCEPTION(EXC_UNDEF_INSTR); |
} |
|
|
/** Low-level Fast Interrupt Exception handler. */ |
static void fiq_exception_entry() |
{ |
255,7 → 248,6 |
PROCESS_EXCEPTION(EXC_FIQ); |
} |
|
|
/** Low-level Prefetch Abort Exception handler. */ |
static void prefetch_abort_exception_entry() |
{ |
263,7 → 255,6 |
PROCESS_EXCEPTION(EXC_PREFETCH_ABORT); |
} |
|
|
/** Low-level Data Abort Exception handler. */ |
static void data_abort_exception_entry() |
{ |
271,7 → 262,6 |
PROCESS_EXCEPTION(EXC_DATA_ABORT); |
} |
|
|
/** Low-level Interrupt Exception handler. |
* |
* CPU is switched to Undefined mode before further interrupt processing |
290,7 → 280,6 |
load_regs(); |
} |
|
|
/** Software Interrupt handler. |
* |
* Dispatches the syscall. |
302,18 → 291,13 |
istate->r1, istate->r2, istate->r3, istate->r4, istate->pc); |
*/ |
|
istate->r0 = syscall_handler( |
istate->r0, |
istate->r1, |
istate->r2, |
istate->r3, |
istate->r4); |
istate->r0 = syscall_handler(istate->r0, istate->r1, istate->r2, |
istate->r3, istate->r4); |
} |
|
|
/** Interrupt Exception handler. |
* |
* Determines the sources of interrupt, and calls their handlers. |
* Determines the sources of interrupt and calls their handlers. |
*/ |
static void irq_exception(int exc_no, istate_t *istate) |
{ |
320,49 → 304,46 |
machine_irq_exception(exc_no, istate); |
} |
|
|
/** Fills exception vectors with appropriate exception handlers. */ |
void install_exception_handlers(void) |
{ |
install_handler((unsigned)reset_exception_entry, |
(unsigned*)EXC_RESET_VEC); |
install_handler((unsigned) reset_exception_entry, |
(unsigned *) EXC_RESET_VEC); |
|
install_handler((unsigned)undef_instr_exception_entry, |
(unsigned*)EXC_UNDEF_INSTR_VEC); |
install_handler((unsigned) undef_instr_exception_entry, |
(unsigned *) EXC_UNDEF_INSTR_VEC); |
|
install_handler((unsigned)swi_exception_entry, |
(unsigned*)EXC_SWI_VEC); |
install_handler((unsigned) swi_exception_entry, |
(unsigned *) EXC_SWI_VEC); |
|
install_handler((unsigned)prefetch_abort_exception_entry, |
(unsigned*)EXC_PREFETCH_ABORT_VEC); |
install_handler((unsigned) prefetch_abort_exception_entry, |
(unsigned *) EXC_PREFETCH_ABORT_VEC); |
|
install_handler((unsigned)data_abort_exception_entry, |
(unsigned*)EXC_DATA_ABORT_VEC); |
install_handler((unsigned) data_abort_exception_entry, |
(unsigned *) EXC_DATA_ABORT_VEC); |
|
install_handler((unsigned)irq_exception_entry, |
(unsigned*)EXC_IRQ_VEC); |
install_handler((unsigned) irq_exception_entry, |
(unsigned *) EXC_IRQ_VEC); |
|
install_handler((unsigned)fiq_exception_entry, |
(unsigned*)EXC_FIQ_VEC); |
(unsigned *) EXC_FIQ_VEC); |
} |
|
|
#ifdef HIGH_EXCEPTION_VECTORS |
/** Activates use of high exception vectors addresses. */ |
static void high_vectors() |
static void high_vectors(void) |
{ |
uint32_t control_reg; |
|
asm volatile( "mrc p15, 0, %0, c1, c1": "=r" (control_reg)); |
asm volatile("mrc p15, 0, %0, c1, c1" : "=r" (control_reg)); |
|
//switch on the high vectors bit |
/* switch on the high vectors bit */ |
control_reg |= CP15_R1_HIGH_VECTORS_BIT; |
|
asm volatile( "mcr p15, 0, %0, c1, c1" : : "r" (control_reg)); |
asm volatile("mcr p15, 0, %0, c1, c1" : : "r" (control_reg)); |
} |
#endif |
|
|
/** Initializes exception handling. |
* |
* Installs low-level exception handlers and then registers |
376,12 → 357,12 |
install_exception_handlers(); |
|
exc_register(EXC_IRQ, "interrupt", (iroutine) irq_exception); |
exc_register(EXC_PREFETCH_ABORT, "prefetch abort", (iroutine) prefetch_abort); |
exc_register(EXC_PREFETCH_ABORT, "prefetch abort", |
(iroutine) prefetch_abort); |
exc_register(EXC_DATA_ABORT, "data abort", (iroutine) data_abort); |
exc_register(EXC_SWI, "software interrupt", (iroutine) swi_exception); |
} |
|
|
/** Prints #istate_t structure content. |
* |
* @param istate Structure to be printed. |
391,17 → 372,16 |
dprintf("istate dump:\n"); |
|
dprintf(" r0: %x r1: %x r2: %x r3: %x\n", |
istate->r0, istate->r1, istate->r2, istate->r3); |
istate->r0, istate->r1, istate->r2, istate->r3); |
dprintf(" r4: %x r5: %x r6: %x r7: %x\n", |
istate->r4, istate->r5, istate->r6, istate->r7); |
istate->r4, istate->r5, istate->r6, istate->r7); |
dprintf(" r8: %x r8: %x r10: %x r11: %x\n", |
istate->r8, istate->r9, istate->r10, istate->r11); |
istate->r8, istate->r9, istate->r10, istate->r11); |
dprintf(" r12: %x sp: %x lr: %x spsr: %x\n", |
istate->r12, istate->sp, istate->lr, istate->spsr); |
istate->r12, istate->sp, istate->lr, istate->spsr); |
|
dprintf(" pc: %x\n", istate->pc); |
} |
|
|
/** @} |
*/ |