[coreboot-gerrit] New patch to review for coreboot: 0754f5c libpayload: Make it possible to install callbacks for particular exceptions.

Marc Jones (marc.jones@se-eng.com) gerrit at coreboot.org
Fri Dec 5 20:58:36 CET 2014


Marc Jones (marc.jones at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/7656

-gerrit

commit 0754f5c45bab92f1968028929c1b3683b32eb0ea
Author: Gabe Black <gabeblack at google.com>
Date:   Wed Dec 11 00:23:15 2013 -0800

    libpayload: Make it possible to install callbacks for particular exceptions.
    
    To support a GDB stub, it will be necessary to trap various exceptions which
    will be used to implement breakpoints, single stepping, etc.
    
    BUG=None
    TEST=Built and booted on Link with hooks installed and saw that they
    triggered when exceptions occurred. Built and booted on nyan.
    BRANCH=None
    
    Original-Change-Id: Iab659365864a3055159a50b8f6e5c44290d3ba2b
    Original-Signed-off-by: Gabe Black <gabeblack at google.com>
    Original-Reviewed-on: https://chromium-review.googlesource.com/179602
    Original-Reviewed-by: Gabe Black <gabeblack at chromium.org>
    Original-Tested-by: Gabe Black <gabeblack at chromium.org>
    Original-Commit-Queue: Gabe Black <gabeblack at chromium.org>
    (cherry picked from commit 8db0897b1ddad600e247cb4df147c757a8187626)
    Signed-off-by: Marc Jones <marc.jones at se-eng.com>
    
    Change-Id: I5e7f724b99988cd259909dd3bd01166fa52317ec
---
 payloads/libpayload/arch/arm/exception.c         | 100 ++++++---------
 payloads/libpayload/arch/arm/exception_asm.S     |  32 ++---
 payloads/libpayload/arch/arm/main.c              |   2 +-
 payloads/libpayload/arch/x86/exception.c         | 152 +++++++++++------------
 payloads/libpayload/arch/x86/exception_asm.S     |  13 +-
 payloads/libpayload/include/arm/arch/exception.h |  16 ++-
 payloads/libpayload/include/exception.h          |   5 +-
 payloads/libpayload/include/x86/arch/exception.h |  81 ++++++++++++
 8 files changed, 238 insertions(+), 163 deletions(-)

diff --git a/payloads/libpayload/arch/arm/exception.c b/payloads/libpayload/arch/arm/exception.c
index 099d2a4..f0ce0ea 100644
--- a/payloads/libpayload/arch/arm/exception.c
+++ b/payloads/libpayload/arch/arm/exception.c
@@ -29,19 +29,27 @@
 
 #include <arch/cache.h>
 #include <arch/exception.h>
+#include <exception.h>
 #include <libpayload.h>
 #include <stdint.h>
 
-uint8_t exception_stack[0x100] __attribute__((aligned(8)));
+uint8_t exception_stack[0x1000] __attribute__((aligned(8)));
 extern void *exception_stack_end;
 
-void exception_undefined_instruction(uint32_t *);
-void exception_software_interrupt(uint32_t *);
-void exception_prefetch_abort(uint32_t *);
-void exception_data_abort(uint32_t *);
-void exception_not_used(uint32_t *);
-void exception_irq(uint32_t *);
-void exception_fiq(uint32_t *);
+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 void dump_stack(uintptr_t addr, size_t bytes)
 {
@@ -77,59 +85,25 @@ static void print_regs(uint32_t *regs)
 	}
 }
 
-void exception_undefined_instruction(uint32_t *regs)
-{
-	printf("exception _undefined_instruction\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_software_interrupt(uint32_t *regs)
-{
-	printf("exception _software_interrupt\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_prefetch_abort(uint32_t *regs)
-{
-	printf("exception _prefetch_abort\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_data_abort(uint32_t *regs)
-{
-	printf("exception _data_abort\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_not_used(uint32_t *regs)
-{
-	printf("exception _not_used\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_irq(uint32_t *regs)
+void exception_dispatch(struct exception_state *state, int idx);
+void exception_dispatch(struct exception_state *state, int idx)
 {
-	printf("exception _irq\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
-	halt();
-}
-
-void exception_fiq(uint32_t *regs)
-{
-	printf("exception _fiq\n");
-	print_regs(regs);
-	dump_stack(regs[13], 512);
+	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;
+		}
+
+		if (info->name)
+			printf("exception %s\n", info->name);
+		else
+			printf("exception _not_used.\n");
+	}
+	print_regs(state->regs);
+	dump_stack(state->regs[13], 512);
 	halt();
 }
 
@@ -146,3 +120,9 @@ void exception_init(void)
 	set_vbar((uintptr_t)exception_table);
 	exception_stack_end = exception_stack + sizeof(exception_stack);
 }
+
+void exception_install_hook(int type, exception_hook hook)
+{
+	die_if(type >= EXC_COUNT, "Out of bounds exception index %d.\n", type);
+	exceptions[type].hook = hook;
+}
diff --git a/payloads/libpayload/arch/arm/exception_asm.S b/payloads/libpayload/arch/arm/exception_asm.S
index 1f369bc..6a28c5c 100644
--- a/payloads/libpayload/arch/arm/exception_asm.S
+++ b/payloads/libpayload/arch/arm/exception_asm.S
@@ -43,59 +43,51 @@ exception_table:
 	b	8f
 
 1:
-	ldr	sp, _not_used
+	mov	sp, $0
 	b	exception_common
 2:
-	ldr	sp, _undefined_instruction
+	mov	sp, $1
 	b	exception_common
 3:
-	ldr	sp, _software_interrupt
+	mov	sp, $2
 	b	exception_common
 4:
-	ldr	sp, _prefetch_abort
+	mov	sp, $3
 	b	exception_common
 5:
-	ldr	sp, _data_abort
+	mov	sp, $4
 	b	exception_common
 6:
-	ldr	sp, _not_used
+	mov	sp, $5
 	b	exception_common
 7:
-	ldr	sp, _irq
+	mov	sp, $6
 	b	exception_common
 8:
-	ldr	sp, _fiq
+	mov	sp, $7
 	b	exception_common
 
 exception_common:
-	str	sp, exception_handler
+	str	sp, exception_idx
 	ldr	sp, exception_stack_end
 	push	{ lr }
 	stmfd	sp, { sp, lr }^
 	sub	sp, sp, $8
 	push	{ r0 - r12 }
 	mov	r0, sp
-	mov	lr, pc
-	ldr	pc, exception_handler
+	ldr	r1, exception_idx
+	blx	exception_dispatch
 	pop	{ r0 - r12 }
 	add	sp, sp, $8
 	ldmfd	sp!, { pc }^
 
 
 	.align 2
-_undefined_instruction:	.word exception_undefined_instruction
-_software_interrupt:	.word exception_software_interrupt
-_prefetch_abort:	.word exception_prefetch_abort
-_data_abort:		.word exception_data_abort
-_not_used:		.word exception_not_used
-_irq:			.word exception_irq
-_fiq:			.word exception_fiq
-
 	.global exception_stack_end
 exception_stack_end:
 	.word 0
 
-exception_handler:
+exception_idx:
 	.word 0
 
 	.thumb
diff --git a/payloads/libpayload/arch/arm/main.c b/payloads/libpayload/arch/arm/main.c
index 4e7c05d..cff992f 100644
--- a/payloads/libpayload/arch/arm/main.c
+++ b/payloads/libpayload/arch/arm/main.c
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#include <arch/exception.h>
+#include <exception.h>
 #include <libpayload.h>
 
 unsigned int main_argc;    /**< The argc value to pass to main() */
diff --git a/payloads/libpayload/arch/x86/exception.c b/payloads/libpayload/arch/x86/exception.c
index a9a65ca..33bef71 100644
--- a/payloads/libpayload/arch/x86/exception.c
+++ b/payloads/libpayload/arch/x86/exception.c
@@ -27,39 +27,27 @@
  * SUCH DAMAGE.
  */
 
+#include <arch/exception.h>
 #include <exception.h>
 #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_state
+struct exception_handler_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;
+	struct exception_state regs;
 	u32 error_code;
 	u32 vector;
 } __attribute__((packed));
 
-struct exception_info
+struct exception_handler_info
 {
 	const char *name;
 	void (*error_code_printer)(u32 code);
+	exception_hook hook;
 };
 
 static void print_segment_error_code(u32 code)
@@ -105,34 +93,34 @@ 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 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)
@@ -150,16 +138,9 @@ static void dump_stack(uintptr_t addr, size_t bytes)
 	}
 }
 
-void exception_handler(void);
-void exception_handler(void)
+static void dump_exception_state(struct exception_handler_state *state,
+				 struct exception_handler_info *info)
 {
-	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
@@ -169,31 +150,50 @@ void exception_handler(void)
 		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();
+	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);
+}
+
+void exception_dispatch(void)
+{
+	struct exception_handler_state *state =
+		exception_handler_state_handoff;
+
+	struct exception_handler_info *info = NULL;
+	if (state->vector < EXC_COUNT)
+		info = &exceptions[state->vector];
+
+	if (info && info->hook) {
+		info->hook(state->vector, &state->regs);
+	} else {
+		dump_exception_state(state, info);
+		dump_stack(state->regs.esp, 512);
+		halt();
+	}
 }
 
-void exception_init_asm(void);
 void exception_init(void)
 {
 	exception_stack_end = exception_stack + sizeof(exception_stack);
 	exception_init_asm();
 }
+
+void exception_install_hook(int type, exception_hook hook)
+{
+	die_if(type >= EXC_COUNT, "Out of bound exception type %d.\n", type);
+	exceptions[type].hook = hook;
+}
diff --git a/payloads/libpayload/arch/x86/exception_asm.S b/payloads/libpayload/arch/x86/exception_asm.S
index c56a7a0..de612ba 100644
--- a/payloads/libpayload/arch/x86/exception_asm.S
+++ b/payloads/libpayload/arch/x86/exception_asm.S
@@ -31,6 +31,9 @@
 	.global exception_stack_end
 exception_stack_end:
 	.long 0
+	.global exception_handler_state_handoff
+exception_handler_state_handoff:
+	.long 0
 
 /* Some temporary variables which are used while saving exception state. */
 vector:
@@ -134,11 +137,13 @@ exception_common:
 	pushl	old_eax
 
 	/*
-	 * Call the C exception handler. It will find the exception state on
-	 * the exception stack. Not passing parameters means we don't have to
-	 * worry about what ABI is being used.
+	 * Call the C exception handler. It will find the exception state
+	 * using the exception_handler_state_handoff global pointer. Not
+	 * passing parameters means we don't have to worry about what ABI
+	 * is being used.
 	 */
-	call	exception_handler
+	mov	%esp, exception_handler_state_handoff
+	call	exception_dispatch
 
 	/*
 	 * Restore state from the exception state structure, including any
diff --git a/payloads/libpayload/include/arm/arch/exception.h b/payloads/libpayload/include/arm/arch/exception.h
index a0d9413..13fda57 100644
--- a/payloads/libpayload/include/arm/arch/exception.h
+++ b/payloads/libpayload/include/arm/arch/exception.h
@@ -30,9 +30,23 @@
 #ifndef _ARCH_EXCEPTION_H
 #define _ARCH_EXCEPTION_H
 
-#include <exception.h>
 #include <stdint.h>
 
 void set_vbar(uint32_t vbar);
 
+struct exception_state
+{
+	uint32_t regs[16];
+} __attribute__((packed));
+
+enum {
+	EXC_UNDEF = 1,
+	EXC_SWI = 2,
+	EXC_PABORT = 3,
+	EXC_DABORT = 4,
+	EXC_IRQ = 6,
+	EXC_FIQ = 7,
+	EXC_COUNT
+};
+
 #endif
diff --git a/payloads/libpayload/include/exception.h b/payloads/libpayload/include/exception.h
index 6d118e7..1d9b832 100644
--- a/payloads/libpayload/include/exception.h
+++ b/payloads/libpayload/include/exception.h
@@ -30,8 +30,11 @@
 #ifndef _EXCEPTION_H
 #define _EXCEPTION_H
 
-#include <stdint.h>
+#include <arch/exception.h>
+
+typedef void (*exception_hook)(int type, struct exception_state *state);
 
 void exception_init(void);
+void exception_install_hook(int type, exception_hook hook);
 
 #endif
diff --git a/payloads/libpayload/include/x86/arch/exception.h b/payloads/libpayload/include/x86/arch/exception.h
new file mode 100644
index 0000000..82f2ca0
--- /dev/null
+++ b/payloads/libpayload/include/x86/arch/exception.h
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#ifndef _ARCH_EXCEPTION_H
+#define _ARCH_EXCEPTION_H
+
+#include <stdint.h>
+
+void exception_dispatch(void);
+void exception_init_asm(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;
+} __attribute__((packed));
+
+enum {
+	EXC_DE = 0, /* Divide by zero */
+	EXC_DB = 1, /* Debug */
+	EXC_NMI = 2, /* Non maskable interrupt */
+	EXC_BP = 3, /* Breakpoint */
+	EXC_OF = 4, /* Overflow */
+	EXC_BR = 5, /* Bound range */
+	EXC_UD = 6, /* Invalid opcode */
+	EXC_NM = 7, /* Device not available */
+	EXC_DF = 8, /* Double fault */
+	EXC_TS = 10, /* Invalid TSS */
+	EXC_NP = 11, /* Segment not present */
+	EXC_SS = 12, /* Stack */
+	EXC_GP = 13, /* General protection */
+	EXC_PF = 14, /* Page fault */
+	EXC_MF = 16, /* x87 floating point */
+	EXC_AC = 17, /* Alignment check */
+	EXC_MC = 18, /* Machine check */
+	EXC_XF = 19, /* SIMD floating point */
+	EXC_SX = 30, /* Security */
+	EXC_COUNT
+};
+
+#endif



More information about the coreboot-gerrit mailing list