+/**
+ * @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__ */
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");
if ( CONFIG_PAGING_LEVELS > 0 )
test_NULL_unmapped();
test_unhandled_exception_hook();
+ test_extable_handler();
xtf_success(NULL);
}