From: Andrew Cooper Date: Wed, 16 Dec 2015 19:04:03 +0000 (+0000) Subject: Exception table infrastructure X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=06c8ae1b8821e76959ebf3b6ea6ce611b759919e;p=people%2Froyger%2Fxen-test-framework.git Exception table infrastructure To redirect control flow if a fault occurs. Entries are registered with the _ASM_EXTABLE() and placed in the .ex_table section, which is collected together by the linker. The .ex_table section is sorted on boot (to facilitate fast searching), and searched in do_exception() when a fault or abort is encountered. If a matching entry is found, control flow is redirected and the exception returned from. Some of the changes are to make the two asm_macros.h files safe to include in C code. In addition, an extra selftest is added, making use of the exception table infrastructure. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/link.lds.S b/arch/x86/link.lds.S index 4ad6864..75324f5 100644 --- a/arch/x86/link.lds.S +++ b/arch/x86/link.lds.S @@ -40,6 +40,11 @@ SECTIONS .rodata : { *(.rodata) *(.rodata.*) + + . = ALIGN(8); + __start_ex_table = .; + *(.ex_table) + __stop_ex_table = .; } .note : { diff --git a/arch/x86/setup.c b/arch/x86/setup.c index 773bcd9..3cd40c6 100644 --- a/arch/x86/setup.c +++ b/arch/x86/setup.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,8 @@ void arch_setup(void) init_hypercalls(); + sort_extable(); + setup_pv_console(); } diff --git a/arch/x86/traps.c b/arch/x86/traps.c index 61a2cd2..c28becb 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -56,8 +56,16 @@ static bool is_trap_or_interrupt(const struct cpu_regs *regs) */ void do_exception(struct cpu_regs *regs) { + unsigned long fixup_addr; bool safe = is_trap_or_interrupt(regs); + /* Look in the exception table to see if a redirection has been set up. */ + if ( !safe && (fixup_addr = search_extable(regs->ip)) ) + { + regs->ip = fixup_addr; + safe = true; + } + if ( !safe ) panic("Unhandled exception: vec %u at %04x:%p\n", regs->entry_vector, regs->cs, _p(regs->ip)); diff --git a/build/files.mk b/build/files.mk index 6d93772..28fea2b 100644 --- a/build/files.mk +++ b/build/files.mk @@ -5,6 +5,7 @@ # obj-$(env) are objects unique to a specific environment obj-perarch += $(ROOT)/common/console.o +obj-perarch += $(ROOT)/common/extable.o obj-perarch += $(ROOT)/common/heapsort.o obj-perarch += $(ROOT)/common/lib.o obj-perarch += $(ROOT)/common/libc/string.o diff --git a/common/extable.c b/common/extable.c new file mode 100644 index 0000000..d5b47c9 --- /dev/null +++ b/common/extable.c @@ -0,0 +1,65 @@ +#include +#include + +struct extable_entry +{ + unsigned long fault; + unsigned long cont; +}; + +extern struct extable_entry __start_ex_table[], __stop_ex_table[]; + +unsigned long search_extable(unsigned long addr) +{ + const struct extable_entry *start = __start_ex_table, + *stop = __stop_ex_table, *mid; + + while ( start <= stop ) + { + mid = start + (stop - start) / 2; + + if ( addr == mid->fault ) + return mid->cont; + else if ( addr > mid->fault ) + start = mid + 1; + else + stop = mid - 1; + } + + return 0; +} + +static int compare_extable_entry(const void *_l, const void *_r) +{ + const struct extable_entry *l = _l, *r = _r; + + return l->fault - r->fault; +} + +static void swap_extable_entry(void *_l, void *_r) +{ + struct extable_entry tmp, *l = _l, *r = _r; + + tmp = *l; + *l = *r; + *r = tmp; +} + +void sort_extable(void) +{ + heapsort(__start_ex_table, + __stop_ex_table - __start_ex_table, + sizeof(__start_ex_table[0]), + compare_extable_entry, + swap_extable_entry); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/arch/x86/asm_macros.h b/include/arch/x86/asm_macros.h index f0da23d..f436a9a 100644 --- a/include/arch/x86/asm_macros.h +++ b/include/arch/x86/asm_macros.h @@ -6,15 +6,23 @@ #ifndef XTF_X86_ASM_MACROS_H #define XTF_X86_ASM_MACROS_H +#ifdef __ASSEMBLY__ /* Declare data at the architectures width. */ -#if defined(__x86_64__) -# define _WORD .quad -#elif defined(__i386__) -# define _WORD .long +# if defined(__x86_64__) +# define _WORD .quad +# elif defined(__i386__) +# define _WORD .long +# endif #else -# error Bad architecture for _WORD +# if defined(__x86_64__) +# define _WORD ".quad " +# elif defined(__i386__) +# define _WORD ".long " +# endif #endif +#ifdef __ASSEMBLY__ + .macro SAVE_ALL cld #if defined(__x86_64__) @@ -76,6 +84,8 @@ #endif .endm +#endif /* __ASSEMBLY__ */ + #endif /* XTF_X86_ASM_MACROS_H */ /* diff --git a/include/xtf/asm_macros.h b/include/xtf/asm_macros.h index 96a5fec..ace3168 100644 --- a/include/xtf/asm_macros.h +++ b/include/xtf/asm_macros.h @@ -10,6 +10,8 @@ #include +#ifdef __ASSEMBLY__ + /** * Declare a global symbol. * @param name Symbol name. @@ -60,6 +62,8 @@ name: 4:.align 4 ; \ .popsection +#endif /* __ASSEMBLY__ */ + #endif /* XTF_ASM_MACROS_H */ /* diff --git a/include/xtf/extable.h b/include/xtf/extable.h new file mode 100644 index 0000000..3fe6658 --- /dev/null +++ b/include/xtf/extable.h @@ -0,0 +1,48 @@ +#ifndef XTF_EXTABLE_H +#define XTF_EXTABLE_H + +#include +#include + +#ifdef __ASSEMBLY__ + +/* Exception Table entry for asm code. */ +#define _ASM_EXTABLE(fault, fixup) \ + .pushsection .ex_table, "a"; \ + _WORD fault, fixup; \ + .popsection + +#else + +/* Exception Table entry for C inline assembly. */ +#define _ASM_EXTABLE(fault, fixup) \ + ".pushsection .ex_table, \"a\";\n" \ + _WORD #fault ", " #fixup ";\n" \ + ".popsection;\n" + +/* + * Sort the exception table. Required to be called once on boot to make + * searching efficient. + */ +void sort_extable(void); + +/* + * Search the exception table to see whether an entry has been registered for + * the provided fault address. If so, returns the fixup address. If not, + * returns zero. + */ +unsigned long search_extable(unsigned long fault_addr); + +#endif /* __ASSEMBLY__ */ + +#endif /* XTF_EXTABLE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xtf/traps.h b/include/xtf/traps.h index 38108b8..7f3ba30 100644 --- a/include/xtf/traps.h +++ b/include/xtf/traps.h @@ -1,6 +1,8 @@ #ifndef XTF_TRAPS_H #define XTF_TRAPS_H +#include + #include #endif /* XTF_TRAPS_H */ diff --git a/tests/selftest/main.c b/tests/selftest/main.c index d8f5a96..fed4c22 100644 --- a/tests/selftest/main.c +++ b/tests/selftest/main.c @@ -14,11 +14,24 @@ static void test_int3_breakpoint(void) asm volatile ("int3"); } +static void test_extable(void) +{ + printk("Test: Exception Table\n"); + + /* + * Check that control flow is successfully redirected with a ud2a + * instruction and appropriate extable entry. + */ + asm volatile ("1: ud2a; 2:" + _ASM_EXTABLE(1b, 2b)); +} + void test_main(void) { printk("XTF Selftests\n"); test_int3_breakpoint(); + test_extable(); xtf_success(); }