44,18 → 44,37 |
#include <print.h> |
#include <syscall/syscall.h> |
|
/** Offset used in calculation of exception handler's relative address. |
* |
* @see install_handler() |
*/ |
#define PREFETCH_OFFSET 0x8 |
|
#define PREFETCH_OFFSET 0x8 |
#define BRANCH_OPCODE 0xea000000 |
/** LDR instruction's code */ |
#define LDR_OPCODE 0xe59ff000 |
#define VALID_BRANCH_MASK 0xff000000 |
#define EXC_VECTORS_SIZE 0x20 |
#define EXC_VECTORS 0x8 |
|
/** Number of exception vectors. */ |
#define EXC_VECTORS 8 |
|
/** Size of memory block occupied by exception vectors. */ |
#define EXC_VECTORS_SIZE (EXC_VECTORS * 4) |
|
|
/** Kernel stack pointer. |
* |
* It is set when thread switches to user mode, |
* and then used for exception handling. |
*/ |
extern uintptr_t supervisor_sp; |
|
/** Temporary exception stack pointer. |
* |
* Temporary stack is used in exceptions handling routines |
* before switching to thread's kernel stack. |
*/ |
extern uintptr_t exc_stack; |
|
|
/** Switches to kernel stack and saves all registers there. |
* |
* Temporary exception stack is used to save a few registers |
113,6 → 132,7 |
); |
} |
|
|
/** Returns from exception mode. |
* |
* Previously saved state of registers (including control register) |
148,6 → 168,39 |
); |
} |
|
/** Switch CPU to mode in which interrupts are serviced (currently it |
* is Undefined mode). |
* |
* 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). |
*/ |
inline static void switchToIrqServicingMode() |
{ |
/* switch to Undefined mode */ |
asm volatile( |
/* save regs used during switching */ |
"stmfd sp!, {r0-r3} \n" |
|
/* save stack pointer and link register to r1, r2 */ |
"mov r1, sp \n" |
"mov r2, lr \n" |
|
/* mode switch */ |
"mrs r0, cpsr \n" |
"bic r0, r0, #0x1f \n" |
"orr r0, r0, #0x1b \n" |
"msr cpsr_c, r0 \n" |
|
/* restore saved sp and lr */ |
"mov sp, r1 \n" |
"mov lr, r2 \n" |
|
/* restore original regs */ |
"ldmfd sp!, {r0-r3} \n" |
); |
} |
|
/** Calls exception dispatch routine. */ |
#define CALL_EXC_DISPATCH(exception) \ |
asm("mov r0, %0" : : "i" (exception)); \ |
154,7 → 207,7 |
asm("mov r1, r13"); \ |
asm("bl exc_dispatch"); |
|
|
|
/** General exception handler. |
* |
* Stores registers, dispatches the exception, |
242,19 → 295,9 |
{ |
asm("sub lr, lr, #4"); |
setup_stack_and_save_regs(); |
|
/* switch to Undefined mode */ |
asm("stmfd sp!, {r0-r3}"); |
asm("mov r1, sp"); |
asm("mov r2, lr"); |
asm("mrs r0, cpsr"); |
asm("bic r0, r0, #0x1f"); |
asm("orr r0, r0, #0x1b"); |
asm("msr cpsr_c, r0"); |
asm("mov sp, r1"); |
asm("mov lr, r2"); |
asm("ldmfd sp!, {r0-r3}"); |
|
|
switchToIrqServicingMode(); |
|
CALL_EXC_DISPATCH(EXC_IRQ) |
|
load_regs(); |