summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/arch/arm/exception.c66
-rw-r--r--payloads/libpayload/arch/arm/exception_asm.S56
-rw-r--r--payloads/libpayload/arch/arm64/exception.c15
-rw-r--r--payloads/libpayload/arch/x86/exception.c163
-rw-r--r--payloads/libpayload/arch/x86/exception_asm.S8
-rw-r--r--payloads/libpayload/include/arm/arch/exception.h10
-rw-r--r--payloads/libpayload/include/arm64/arch/exception.h2
-rw-r--r--payloads/libpayload/include/exception.h5
-rw-r--r--payloads/libpayload/include/x86/arch/exception.h43
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 &regs[13] + 2 */
mrs r0, SPSR
- push { r0 }
- mov r0, sp
- ldr r1, exception_idx
+ str r0, [sp, #(4 * 3)] /* Save SPSR to &regs[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 &regs[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 */