]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Extend exception table support to include custom handlers
authorAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 6 May 2016 16:40:02 +0000 (17:40 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 6 May 2016 16:40:02 +0000 (17:40 +0100)
Provide additional documentation, and a selftest.  Introduce __used to
indicate to the compiler that an object is referenced, even if the reference
isn't visible.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Doxyfile
arch/x86/traps.c
common/extable.c
include/xtf/compiler.h
include/xtf/extable.h
tests/selftest/main.c

index ebf0e92b8d7bc671ef32ca25841d613d929b86aa..c669a6e7e56e4f2a34ef5f56ea07608899f4627c 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -2031,6 +2031,7 @@ PREDEFINED             = __aligned(x)= \
                          __printf(x,y)= \
                          __noinline \
                          __noreturn \
+                         __used \
 
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
index a54f6726914ede0b8425e66dce0ac911ba19ae77..e101b56412abd7fb42231e3b7adaaf704d64bc8a 100644 (file)
@@ -60,16 +60,21 @@ static bool is_trap_or_interrupt(const struct cpu_regs *regs)
  */
 void do_exception(struct cpu_regs *regs)
 {
-    unsigned long fixup_addr;
+    const struct extable_entry *ex;
     bool safe = is_trap_or_interrupt(regs);
 
     xtf_exlog_log_exception(regs);
 
     /* Look in the exception table to see if a redirection has been set up. */
-    if ( !safe && (fixup_addr = search_extable(regs->ip)) )
+    if ( !safe && (ex = search_extable(regs->ip)) )
     {
-        regs->ip = fixup_addr;
-        safe = true;
+        if ( ex->handler )
+            safe = ex->handler(regs, ex);
+        else
+        {
+            regs->ip = ex->fixup;
+            safe = true;
+        }
     }
 
     /*
index b28dd78dc45b762100d8a67e74ea5bde9457be80..3501484d3f1c137e74477d0ebfd966d04c85baca 100644 (file)
@@ -1,15 +1,14 @@
+/**
+ * @file common/extable.c
+ *
+ * Exception table support.
+ */
 #include <xtf/lib.h>
 #include <xtf/extable.h>
 
-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 *search_extable(unsigned long addr)
 {
     const struct extable_entry *start = __start_ex_table,
         *stop = __stop_ex_table, *mid;
@@ -19,7 +18,7 @@ unsigned long search_extable(unsigned long addr)
         mid = start + (stop - start) / 2;
 
         if ( addr == mid->fault )
-            return mid->cont;
+            return mid;
         else if ( addr > mid->fault )
             start = mid + 1;
         else
index 251b853ddcb00852c9d7b8f90c143abb2008dd6d..74dec31b70fef331ab4c0427e25ae3216fb2c99d 100644 (file)
@@ -3,6 +3,7 @@
 
 #define __aligned(x)          __attribute__((__aligned__(x)))
 #define __packed              __attribute__((__packed__))
+#define __used                __attribute__((__used__))
 
 #ifndef __noinline /* Avoid conflicting with cdefs.h */
 #define __noinline            __attribute__((__noinline__))
index 3fe6658a79b8c999ad4177ec5cb81f5e92b6fb2f..5585181034b2391d8b51ae104e43517f47e03a0f 100644 (file)
@@ -1,3 +1,12 @@
+/**
+ * @file include/xtf/extable.h
+ *
+ * Exception table support.
+ *
+ * Allows code to tag an instruction which might fault, and where to jump to
+ * in order to recover.  For more complicated recovery, a cusom handler
+ * handler can be registerd.
+ */
 #ifndef XTF_EXTABLE_H
 #define XTF_EXTABLE_H
 
 
 #ifdef __ASSEMBLY__
 
-/* Exception Table entry for asm code. */
+/**
+ * Create an exception table entry.
+ * @param fault Faulting address.
+ * @param fixup Fixup address.
+ */
 #define _ASM_EXTABLE(fault, fixup)              \
     .pushsection .ex_table, "a";                \
-    _WORD fault, fixup;                         \
+    _WORD fault, fixup, 0;                      \
+    .popsection
+
+/**
+ * Create an exception table entry with custom handler.
+ * @param fault Faulting address.
+ * @param fixup Fixup address.
+ * @param handler Handler to call.
+ */
+#define _ASM_EXTABLE_HANDLER(fault, fixup, handler) \
+    .pushsection .ex_table, "a";                    \
+    _WORD fault, fixup, handler;                    \
     .popsection
 
 #else
 
-/* Exception Table entry for C inline assembly. */
+/**
+ * Create an exception table entry.
+ * @param fault Faulting address.
+ * @param fixup Fixup address.
+ */
 #define _ASM_EXTABLE(fault, fixup)              \
     ".pushsection .ex_table, \"a\";\n"          \
-    _WORD #fault ", " #fixup ";\n"              \
+    _WORD #fault ", " #fixup ", 0;\n"           \
     ".popsection;\n"
 
-/*
+/**
+ * Create an exception table entry with custom handler.
+ * @param fault Faulting address.
+ * @param fixup Fixup address.
+ * @param handler Handler to call.
+ */
+#define _ASM_EXTABLE_HANDLER(fault, fixup, handler) \
+    ".pushsection .ex_table, \"a\";\n"              \
+    _WORD #fault ", " #fixup ", " #handler ";\n"    \
+    ".popsection;\n"
+
+struct cpu_regs;
+
+/** Exception table entry. */
+struct extable_entry
+{
+    unsigned long fault; /**< Faulting address. */
+    unsigned long fixup; /**< Fixup address. */
+
+    /**
+     * Optional custom handler.
+     *
+     * If provided, the handler is responsible for altering regs->ip to avoid
+     * the fault.
+     *
+     * @param regs Register state from the fault.
+     * @param ex extable_entry for the fault.
+     * @return true if the fault was successfully handled.  false otherwise.
+     */
+    bool (*handler)(struct cpu_regs *regs,
+                    const struct extable_entry *ex);
+};
+
+/**
  * 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.
+/**
+ * Search the exception table to find the entry associated with a specific
+ * faulting address.
+ * @param addr Faulting address.
+ * @returns Appropriate extable_entry, or NULL if no entry.
  */
-unsigned long search_extable(unsigned long fault_addr);
+const struct extable_entry *search_extable(unsigned long addr);
 
 #endif /* __ASSEMBLY__ */
 
index 553b05a04270496761c09e9bed9a502d129cb410..f46dce1bd65a5d5c9d9c53fe2a8729f082aaa85f 100644 (file)
@@ -222,6 +222,27 @@ static void test_unhandled_exception_hook(void)
     xtf_unhandled_exception_hook = NULL;
 }
 
+static bool test_extable_handler_handler_run;
+static bool __used test_extable_handler_handler(struct cpu_regs *regs,
+                                                const struct extable_entry *ex)
+{
+    test_extable_handler_handler_run = true;
+    regs->ip = ex->fixup;
+    return true;
+}
+
+static void test_extable_handler(void)
+{
+    printk("Test: Exception Table Handler\n");
+
+    asm volatile ("1: ud2a; 2:"
+                  _ASM_EXTABLE_HANDLER(1b, 2b,
+                                       test_extable_handler_handler));
+
+    if ( !test_extable_handler_handler_run )
+        xtf_failure("Fail: Custom handler didn't run\n");
+}
+
 void test_main(void)
 {
     printk("XTF Selftests\n");
@@ -233,6 +254,7 @@ void test_main(void)
     if ( CONFIG_PAGING_LEVELS > 0 )
         test_NULL_unmapped();
     test_unhandled_exception_hook();
+    test_extable_handler();
 
     xtf_success(NULL);
 }