diff options
Diffstat (limited to 'payloads/libpayload/arch/arm')
-rw-r--r-- | payloads/libpayload/arch/arm/exception.c | 66 | ||||
-rw-r--r-- | payloads/libpayload/arch/arm/exception_asm.S | 56 |
2 files changed, 57 insertions, 65 deletions
diff --git a/payloads/libpayload/arch/arm/exception.c b/payloads/libpayload/arch/arm/exception.c index 45b77a7460..d100937295 100644 --- a/payloads/libpayload/arch/arm/exception.c +++ b/payloads/libpayload/arch/arm/exception.c @@ -33,22 +33,17 @@ #include <libpayload.h> #include <stdint.h> -uint8_t exception_stack[0x1000] __attribute__((aligned(8))); -extern void *exception_stack_end; +u32 exception_stack[0x400] __attribute__((aligned(8))); +struct exception_state exception_state; -struct exception_handler_info -{ - const char *name; - exception_hook hook; -}; - -static struct exception_handler_info exceptions[EXC_COUNT] = { - [EXC_UNDEF] = { "_undefined_instruction" }, - [EXC_SWI] = { "_software_interrupt" }, - [EXC_PABORT] = { "_prefetch_abort" }, - [EXC_DABORT] = { "_data_abort" }, - [EXC_IRQ] = { "_irq" }, - [EXC_FIQ] = { "_fiq" }, +static exception_hook hook; +static const char *names[EXC_COUNT] = { + [EXC_UNDEF] = "Undefined Instruction", + [EXC_SWI] = "Software Interrupt", + [EXC_PABORT] = "Prefetch Abort", + [EXC_DABORT] = "Data Abort", + [EXC_IRQ] = "Interrupt", + [EXC_FIQ] = "Fast Interrupt", }; static void dump_stack(uintptr_t addr, size_t bytes) @@ -66,7 +61,7 @@ static void dump_stack(uintptr_t addr, size_t bytes) } } -static void print_regs(struct exception_state *state) +static void print_regs(void) { int i; @@ -81,30 +76,21 @@ static void print_regs(struct exception_state *state) printf("IP"); else printf("R%d", i); - printf(" = 0x%08x\n", state->regs[i]); + printf(" = 0x%08x\n", exception_state.regs[i]); } - printf("CPSR = 0x%08x\n", state->cpsr); + printf("CPSR = 0x%08x\n", exception_state.cpsr); } -void exception_dispatch(struct exception_state *state, int idx); -void exception_dispatch(struct exception_state *state, int idx) +void exception_dispatch(u32 idx) { - if (idx >= EXC_COUNT) { - printf("Bad exception index %d.\n", idx); - } else { - struct exception_handler_info *info = &exceptions[idx]; - if (info->hook) { - info->hook(idx, state); - return; - } + die_if(idx >= EXC_COUNT || !names[idx], "Bad exception index %u!", idx); - if (info->name) - printf("exception %s\n", info->name); - else - printf("exception _not_used.\n"); - } - print_regs(state); - dump_stack(state->regs[13], 512); + if (hook && hook(idx)) + return; + + printf("%s Exception\n", names[idx]); + print_regs(); + dump_stack(exception_state.regs[13], 512); halt(); } @@ -119,11 +105,13 @@ void exception_init(void) extern uint32_t exception_table[]; set_vbar((uintptr_t)exception_table); - exception_stack_end = exception_stack + sizeof(exception_stack); + + exception_stack_end = exception_stack + ARRAY_SIZE(exception_stack); + exception_state_ptr = &exception_state; } -void exception_install_hook(int type, exception_hook hook) +void exception_install_hook(exception_hook h) { - die_if(type >= EXC_COUNT, "Out of bounds exception index %d.\n", type); - exceptions[type].hook = hook; + die_if(hook, "Implement support for a list of hooks if you need it."); + hook = h; } diff --git a/payloads/libpayload/arch/arm/exception_asm.S b/payloads/libpayload/arch/arm/exception_asm.S index 7b722cb86f..8715955de2 100644 --- a/payloads/libpayload/arch/arm/exception_asm.S +++ b/payloads/libpayload/arch/arm/exception_asm.S @@ -43,72 +43,76 @@ exception_table: b 8f 1: - mov sp, $0 + mov sp, #0 b exception_common /* Undefined Instruction (CAREFUL: the PC offset is specific to thumb mode!) */ 2: - sub lr, lr, $2 - mov sp, $1 + sub lr, lr, #2 + mov sp, #1 b exception_common /* Software Interrupt (no PC offset necessary) */ 3: - mov sp, $2 + mov sp, #2 b exception_common /* Prefetch Abort */ 4: - sub lr, lr, $4 - mov sp, $3 + sub lr, lr, #4 + mov sp, #3 b exception_common /* Data Abort */ 5: - sub lr, lr, $8 - mov sp, $4 + sub lr, lr, #8 + mov sp, #4 b exception_common /* (not used) */ 6: - mov sp, $5 + mov sp, #5 b exception_common /* Interrupt */ 7: - sub lr, lr, $4 - mov sp, $6 + sub lr, lr, #4 + mov sp, #6 b exception_common /* Fast Interrupt */ 8: - sub lr, lr, $4 - mov sp, $7 + sub lr, lr, #4 + mov sp, #7 b exception_common exception_common: str sp, exception_idx - ldr sp, exception_stack_end - push { lr } - stmfd sp, { sp, lr }^ - sub sp, sp, $8 - push { r0 - r12 } + ldr sp, exception_state_ptr + stmia sp!, { r0 - r12 } /* Save regs from bottom to top */ + stmia sp, { sp, lr }^ /* Save banked SP/LR (no writeback) */ + str lr, [sp, #(4 * 2)] /* Save PC to ®s[13] + 2 */ mrs r0, SPSR - push { r0 } - mov r0, sp - ldr r1, exception_idx + str r0, [sp, #(4 * 3)] /* Save SPSR to ®s[13] + 3 */ + ldr sp, exception_stack_end /* Point SP to the stack for C code */ + ldr r0, exception_idx blx exception_dispatch - pop { r0 } - msr SPSR_cxsf, r0 - pop { r0 - r12 } - add sp, sp, $8 - ldmfd sp!, { pc }^ + ldr sp, exception_state_ptr + ldr r0, [sp, #(4 * 16)] /* Load SPSR from ®s[0] + 16... */ + msr SPSR_cxsf, r0 /* ...and get it out of the way */ + ldmia sp!, { r0 - r12 } /* Restore regs from bottom to top */ + ldmia sp, { sp, lr }^ /* Restore SP/LR to banked location */ + add sp, sp, #8 /* Adjust SP (no writeback allowed) */ + ldmia sp!, { pc }^ /* Do exception return (mode switch) */ .align 2 .global exception_stack_end exception_stack_end: .word 0 + .global exception_state_ptr +exception_state_ptr: + .word 0 exception_idx: .word 0 |