aboutsummaryrefslogtreecommitdiff
path: root/payloads/libpayload/arch/x86/exception.c
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload/arch/x86/exception.c')
-rw-r--r--payloads/libpayload/arch/x86/exception.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/payloads/libpayload/arch/x86/exception.c b/payloads/libpayload/arch/x86/exception.c
new file mode 100644
index 0000000000..a9a65ca5a2
--- /dev/null
+++ b/payloads/libpayload/arch/x86/exception.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of the libpayload project.
+ *
+ * Copyright 2013 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <exception.h>
+#include <libpayload.h>
+#include <stdint.h>
+
+uint8_t exception_stack[0x1000] __attribute__((aligned(8)));
+extern void *exception_stack_end;
+
+struct exception_state
+{
+ 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;
+ u32 error_code;
+ u32 vector;
+} __attribute__((packed));
+
+struct exception_info
+{
+ const char *name;
+ void (*error_code_printer)(u32 code);
+};
+
+static void print_segment_error_code(u32 code)
+{
+ printf("%#x - descriptor %#x in the ", code, (code >> 3) & 0x1f);
+ if (code & (0x1 << 1)) {
+ printf("IDT");
+ } else {
+ if (code & 0x04)
+ printf("LDT");
+ else
+ printf("GDT");
+ }
+ if (code & (0x1 << 0))
+ printf(", external to the CPU");
+ else
+ printf(", internal to the CPU");
+}
+
+static void print_page_fault_error_code(u32 code)
+{
+ printf("%#x -", code);
+ if (code & (0x1 << 0))
+ printf(" page protection");
+ else
+ printf(" page not present");
+ if (code & (0x1 << 1))
+ printf(", write");
+ else
+ printf(", read");
+ if (code & (0x1 << 2))
+ printf(", user");
+ else
+ printf(", supervisor");
+ if (code & (0x1 << 3))
+ printf(", reserved bits set");
+ if (code & (0x1 << 4))
+ printf(", instruction fetch");
+}
+
+static void print_raw_error_code(u32 code)
+{
+ printf("%#x", code);
+}
+
+static struct exception_info exceptions[] = {
+ [0] = { .name = "divide by zero" },
+ [1] = { .name = "debug" },
+ [2] = { .name = "non-maskable-interrupt" },
+ [3] = { .name = "breakpoint" },
+ [4] = { .name = "overflow" },
+ [5] = { .name = "bound range" },
+ [6] = { .name = "invalid opcode" },
+ [7] = { .name = "device not available" },
+ [8] = { .name = "double fault",
+ .error_code_printer = &print_raw_error_code },
+ [10] = { .name = "invalid tss",
+ .error_code_printer = &print_segment_error_code },
+ [11] = { .name = "segment not present",
+ .error_code_printer = &print_segment_error_code },
+ [12] = { .name = "stack",
+ .error_code_printer = &print_segment_error_code },
+ [13] = { .name = "general protection",
+ .error_code_printer = &print_segment_error_code },
+ [14] = { .name = "page fault",
+ .error_code_printer = &print_page_fault_error_code },
+ [16] = { .name = "x87 floating point" },
+ [17] = { .name = "alignment check",
+ .error_code_printer = &print_raw_error_code },
+ [18] = { .name = "machine check" },
+ [19] = { .name = "SIMD floating point" },
+ [30] = { .name = "security",
+ .error_code_printer = &print_raw_error_code },
+};
+
+static void dump_stack(uintptr_t addr, size_t bytes)
+{
+ int i, j;
+ const int line = 8;
+ uint32_t *ptr = (uint32_t *)(addr & ~(line * sizeof(*ptr) - 1));
+
+ printf("Dumping stack:\n");
+ for (i = bytes / sizeof(*ptr); i >= 0; i -= line) {
+ printf("%p: ", ptr + i);
+ for (j = i; j < i + line; j++)
+ printf("%08x ", *(ptr + j));
+ printf("\n");
+ }
+}
+
+void exception_handler(void);
+void exception_handler(void)
+{
+ struct exception_state *state =
+ (void *)((u8 *)exception_stack_end - sizeof(*state));
+
+ struct exception_info *info = NULL;
+ if (state->vector < ARRAY_SIZE(exceptions))
+ info = &exceptions[state->vector];
+
+ if (info)
+ printf("Exception %d (%s)\n", state->vector, info->name);
+ else
+ printf("Unrecognized exception %d\n", state->vector);
+ if (info->error_code_printer) {
+ printf("Error code: ");
+ info->error_code_printer(state->error_code);
+ printf("\n");
+ }
+ printf("EIP: 0x%08x\n", state->eip);
+ printf("CS: 0x%04x\n", state->cs);
+ printf("EFLAGS: 0x%08x\n", state->eflags);
+ printf("EAX: 0x%08x\n", state->eax);
+ printf("ECX: 0x%08x\n", state->ecx);
+ printf("EDX: 0x%08x\n", state->edx);
+ printf("EBX: 0x%08x\n", state->ebx);
+ printf("ESP: 0x%08x\n", state->esp);
+ printf("EBP: 0x%08x\n", state->ebp);
+ printf("ESI: 0x%08x\n", state->esi);
+ printf("EDI: 0x%08x\n", state->edi);
+ printf("DS: 0x%04x\n", state->ds);
+ printf("ES: 0x%04x\n", state->es);
+ printf("SS: 0x%04x\n", state->ss);
+ printf("FS: 0x%04x\n", state->fs);
+ printf("GS: 0x%04x\n", state->gs);
+
+ dump_stack(state->esp, 512);
+
+ halt();
+}
+
+void exception_init_asm(void);
+void exception_init(void)
+{
+ exception_stack_end = exception_stack + sizeof(exception_stack);
+ exception_init_asm();
+}