diff options
-rw-r--r-- | payloads/libpayload/arch/arm/exception.c | 66 | ||||
-rw-r--r-- | payloads/libpayload/arch/arm/exception_asm.S | 56 | ||||
-rw-r--r-- | payloads/libpayload/arch/arm64/exception.c | 15 | ||||
-rw-r--r-- | payloads/libpayload/arch/x86/exception.c | 163 | ||||
-rw-r--r-- | payloads/libpayload/arch/x86/exception_asm.S | 8 | ||||
-rw-r--r-- | payloads/libpayload/include/arm/arch/exception.h | 10 | ||||
-rw-r--r-- | payloads/libpayload/include/arm64/arch/exception.h | 2 | ||||
-rw-r--r-- | payloads/libpayload/include/exception.h | 5 | ||||
-rw-r--r-- | payloads/libpayload/include/x86/arch/exception.h | 43 |
9 files changed, 181 insertions, 187 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 diff --git a/payloads/libpayload/arch/arm64/exception.c b/payloads/libpayload/arch/arm64/exception.c index 988bef9ed4..226f5ca27d 100644 --- a/payloads/libpayload/arch/arm64/exception.c +++ b/payloads/libpayload/arch/arm64/exception.c @@ -36,9 +36,10 @@ extern unsigned int test_exc; struct exception_handler_info { const char *name; - exception_hook hook; }; +static exception_hook hook; +struct exception_state *exception_state; static struct exception_handler_info exceptions[EXC_COUNT] = { [EXC_INV] = { "_invalid_exception" }, [EXC_SYNC] = { "_sync" }, @@ -61,14 +62,14 @@ static void print_regs(struct exception_state *state) void exception_dispatch(struct exception_state *state, int idx); void exception_dispatch(struct exception_state *state, int idx) { + exception_state = state; + 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); + if (hook && hook(idx)) return; - } if (info->name) printf("exception %s\n", info->name); @@ -89,8 +90,8 @@ void exception_init(void) set_vbar(exception_table); } -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/x86/exception.c b/payloads/libpayload/arch/x86/exception.c index e1ff3a54c6..f6bb8c9ccf 100644 --- a/payloads/libpayload/arch/x86/exception.c +++ b/payloads/libpayload/arch/x86/exception.c @@ -32,22 +32,29 @@ #include <libpayload.h> #include <stdint.h> -uint8_t exception_stack[0x1000] __attribute__((aligned(8))); -extern void *exception_stack_end; -extern struct exception_handler_state *exception_handler_state_handoff; - -struct exception_handler_state -{ - struct exception_state regs; - u32 error_code; - u32 vector; -} __attribute__((packed)); - -struct exception_handler_info -{ - const char *name; - void (*error_code_printer)(u32 code); - exception_hook hook; +u32 exception_stack[0x400] __attribute__((aligned(8))); + +static exception_hook hook; +static const char *names[EXC_COUNT] = { + [EXC_DE] = "Divide by Zero", + [EXC_DB] = "Debug", + [EXC_NMI] = "Non-Maskable-Interrupt", + [EXC_BP] = "Breakpoint", + [EXC_OF] = "Overflow", + [EXC_BR] = "Bound Range", + [EXC_UD] = "Invalid Opcode", + [EXC_NM] = "Device Not Available", + [EXC_DF] = "Double Fault", + [EXC_TS] = "Invalid TSS", + [EXC_NP] = "Segment Not Present", + [EXC_SS] = "Stack Fault", + [EXC_GP] = "General Protection Fault", + [EXC_PF] = "Page Fault", + [EXC_MF] = "x87 Floating Point", + [EXC_AC] = "Alignment Check", + [EXC_MC] = "Machine Check", + [EXC_XF] = "SIMD Floating Point", + [EXC_SX] = "Security", }; static void print_segment_error_code(u32 code) @@ -93,36 +100,6 @@ static void print_raw_error_code(u32 code) printf("%#x", code); } -static struct exception_handler_info exceptions[EXC_COUNT] = { - [EXC_DE] = { .name = "divide by zero" }, - [EXC_DB] = { .name = "debug" }, - [EXC_NMI] = { .name = "non-maskable-interrupt" }, - [EXC_BP] = { .name = "breakpoint" }, - [EXC_OF] = { .name = "overflow" }, - [EXC_BR] = { .name = "bound range" }, - [EXC_UD] = { .name = "invalid opcode" }, - [EXC_NM] = { .name = "device not available" }, - [EXC_DF] = { .name = "double fault", - .error_code_printer = &print_raw_error_code }, - [EXC_TS] = { .name = "invalid tss", - .error_code_printer = &print_segment_error_code }, - [EXC_NP] = { .name = "segment not present", - .error_code_printer = &print_segment_error_code }, - [EXC_SS] = { .name = "stack", - .error_code_printer = &print_segment_error_code }, - [EXC_GP] = { .name = "general protection", - .error_code_printer = &print_segment_error_code }, - [EXC_PF] = { .name = "page fault", - .error_code_printer = &print_page_fault_error_code }, - [EXC_MF] = { .name = "x87 floating point" }, - [EXC_AC] = { .name = "alignment check", - .error_code_printer = &print_raw_error_code }, - [EXC_MC] = { .name = "machine check" }, - [EXC_XF] = { .name = "SIMD floating point" }, - [EXC_SX] = { .name = "security", - .error_code_printer = &print_raw_error_code }, -}; - static void dump_stack(uintptr_t addr, size_t bytes) { int i, j; @@ -138,64 +115,70 @@ static void dump_stack(uintptr_t addr, size_t bytes) } } -static void dump_exception_state(struct exception_handler_state *state, - struct exception_handler_info *info) +static void dump_exception_state(void) { - if (info) { - printf("Exception %d (%s)\n", state->vector, info->name); - - if (info->error_code_printer) { - printf("Error code: "); - info->error_code_printer(state->error_code); - printf("\n"); - } - } else { - printf("Unrecognized exception %d\n", state->vector); + printf("%s Exception\n", names[exception_state->vector]); + + printf("Error code: "); + switch (exception_state->vector) { + case EXC_PF: + print_page_fault_error_code(exception_state->error_code); + break; + case EXC_TS: + case EXC_NP: + case EXC_SS: + case EXC_GP: + print_segment_error_code(exception_state->error_code); + break; + case EXC_DF: + case EXC_AC: + case EXC_SX: + print_raw_error_code(exception_state->error_code); + break; + default: + printf("n/a"); + break; } - printf("EIP: 0x%08x\n", state->regs.eip); - printf("CS: 0x%04x\n", state->regs.cs); - printf("EFLAGS: 0x%08x\n", state->regs.eflags); - printf("EAX: 0x%08x\n", state->regs.eax); - printf("ECX: 0x%08x\n", state->regs.ecx); - printf("EDX: 0x%08x\n", state->regs.edx); - printf("EBX: 0x%08x\n", state->regs.ebx); - printf("ESP: 0x%08x\n", state->regs.esp); - printf("EBP: 0x%08x\n", state->regs.ebp); - printf("ESI: 0x%08x\n", state->regs.esi); - printf("EDI: 0x%08x\n", state->regs.edi); - printf("DS: 0x%04x\n", state->regs.ds); - printf("ES: 0x%04x\n", state->regs.es); - printf("SS: 0x%04x\n", state->regs.ss); - printf("FS: 0x%04x\n", state->regs.fs); - printf("GS: 0x%04x\n", state->regs.gs); + printf("\n"); + printf("EIP: 0x%08x\n", exception_state->regs.eip); + printf("CS: 0x%04x\n", exception_state->regs.cs); + printf("EFLAGS: 0x%08x\n", exception_state->regs.eflags); + printf("EAX: 0x%08x\n", exception_state->regs.eax); + printf("ECX: 0x%08x\n", exception_state->regs.ecx); + printf("EDX: 0x%08x\n", exception_state->regs.edx); + printf("EBX: 0x%08x\n", exception_state->regs.ebx); + printf("ESP: 0x%08x\n", exception_state->regs.esp); + printf("EBP: 0x%08x\n", exception_state->regs.ebp); + printf("ESI: 0x%08x\n", exception_state->regs.esi); + printf("EDI: 0x%08x\n", exception_state->regs.edi); + printf("DS: 0x%04x\n", exception_state->regs.ds); + printf("ES: 0x%04x\n", exception_state->regs.es); + printf("SS: 0x%04x\n", exception_state->regs.ss); + printf("FS: 0x%04x\n", exception_state->regs.fs); + printf("GS: 0x%04x\n", exception_state->regs.gs); } void exception_dispatch(void) { - struct exception_handler_state *state = - exception_handler_state_handoff; + u32 vec = exception_state->vector; + die_if(vec >= EXC_COUNT || !names[vec], "Bad exception vector %u", vec); - struct exception_handler_info *info = NULL; - if (state->vector < EXC_COUNT) - info = &exceptions[state->vector]; + if (hook && hook(vec)) + return; - if (info && info->hook) { - info->hook(state->vector, &state->regs); - } else { - dump_exception_state(state, info); - dump_stack(state->regs.esp, 512); - halt(); - } + dump_exception_state(); + dump_stack(exception_state->regs.esp, 512); + halt(); } void exception_init(void) { - exception_stack_end = exception_stack + sizeof(exception_stack); + exception_stack_end = exception_stack + ARRAY_SIZE(exception_stack); exception_init_asm(); } -void exception_install_hook(int type, exception_hook hook) +void exception_install_hook(exception_hook h) { - die_if(type >= EXC_COUNT, "Out of bound exception type %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/x86/exception_asm.S b/payloads/libpayload/arch/x86/exception_asm.S index de612ba057..a8f9a1d254 100644 --- a/payloads/libpayload/arch/x86/exception_asm.S +++ b/payloads/libpayload/arch/x86/exception_asm.S @@ -31,8 +31,8 @@ .global exception_stack_end exception_stack_end: .long 0 - .global exception_handler_state_handoff -exception_handler_state_handoff: + .global exception_state +exception_state: .long 0 /* Some temporary variables which are used while saving exception state. */ @@ -138,11 +138,11 @@ exception_common: /* * Call the C exception handler. It will find the exception state - * using the exception_handler_state_handoff global pointer. Not + * using the exception_state global pointer. Not * passing parameters means we don't have to worry about what ABI * is being used. */ - mov %esp, exception_handler_state_handoff + mov %esp, exception_state call exception_dispatch /* diff --git a/payloads/libpayload/include/arm/arch/exception.h b/payloads/libpayload/include/arm/arch/exception.h index c6864a5ad2..fbbce5ed3d 100644 --- a/payloads/libpayload/include/arm/arch/exception.h +++ b/payloads/libpayload/include/arm/arch/exception.h @@ -32,13 +32,19 @@ #include <stdint.h> +void exception_dispatch(u32 idx); void set_vbar(uint32_t vbar); struct exception_state { - uint32_t cpsr; - uint32_t regs[16]; + u32 regs[16]; + u32 cpsr; } __attribute__((packed)); +extern struct exception_state exception_state; + +extern u32 exception_stack[]; +extern u32 *exception_stack_end; +extern struct exception_state *exception_state_ptr; enum { EXC_UNDEF = 1, diff --git a/payloads/libpayload/include/arm64/arch/exception.h b/payloads/libpayload/include/arm64/arch/exception.h index f4a7552db9..44a4e5998d 100644 --- a/payloads/libpayload/include/arm64/arch/exception.h +++ b/payloads/libpayload/include/arm64/arch/exception.h @@ -41,6 +41,8 @@ struct exception_state uint64_t regs[31]; } __attribute__((packed)); +extern struct exception_state *exception_state; + enum { EXC_INV = 0, EXC_SYNC = 1, diff --git a/payloads/libpayload/include/exception.h b/payloads/libpayload/include/exception.h index 1d9b832c07..67923ea9af 100644 --- a/payloads/libpayload/include/exception.h +++ b/payloads/libpayload/include/exception.h @@ -32,9 +32,10 @@ #include <arch/exception.h> -typedef void (*exception_hook)(int type, struct exception_state *state); +/* Return 1 if the exception was handled, 0 to proceed to the next handler. */ +typedef int (*exception_hook)(u32 type); void exception_init(void); -void exception_install_hook(int type, exception_hook hook); +void exception_install_hook(exception_hook h); #endif diff --git a/payloads/libpayload/include/x86/arch/exception.h b/payloads/libpayload/include/x86/arch/exception.h index 82f2ca0a32..fe222aa4f2 100644 --- a/payloads/libpayload/include/x86/arch/exception.h +++ b/payloads/libpayload/include/x86/arch/exception.h @@ -32,28 +32,37 @@ #include <stdint.h> -void exception_dispatch(void); void exception_init_asm(void); +void exception_dispatch(void); struct exception_state { - uint32_t eax; - uint32_t ecx; - uint32_t edx; - uint32_t ebx; - uint32_t esp; - uint32_t ebp; - uint32_t esi; - uint32_t edi; - uint32_t eip; - uint32_t eflags; - uint32_t cs; - uint32_t ss; - uint32_t ds; - uint32_t es; - uint32_t fs; - uint32_t gs; + /* Careful: x86/gdb.c currently relies on the size and order of regs. */ + struct { + u32 eax; + u32 ecx; + u32 edx; + u32 ebx; + u32 esp; + u32 ebp; + u32 esi; + u32 edi; + u32 eip; + u32 eflags; + u32 cs; + u32 ss; + u32 ds; + u32 es; + u32 fs; + u32 gs; + } regs; + u32 error_code; + u32 vector; } __attribute__((packed)); +extern struct exception_state *exception_state; + +extern u32 exception_stack[]; +extern u32 *exception_stack_end; enum { EXC_DE = 0, /* Divide by zero */ |