@@ -18,6 +18,7 @@
#include <asm/cpufeature.h>
#include <asm/cputype.h>
#include <asm/debug-monitors.h>
+#include <asm/extable.h>
#include <asm/page.h>
#include <asm/pgtable-hwdef.h>
#include <asm/ptrace.h>
@@ -142,6 +143,14 @@ alternative_endif
.popsection
.endm
+/*
+ * Emit an entry into the exception table.
+ * The fixup handler will receive the faulting address in x15
+ */
+ .macro _asm_extable_faultaddr, from, to
+ _asm_extable \from, \to + FIXUP_WITH_ADDR
+ .endm
+
#define USER(l, x...) \
9999: x; \
_asm_extable 9999b, l
@@ -2,6 +2,12 @@
#ifndef __ASM_EXTABLE_H
#define __ASM_EXTABLE_H
+#include <linux/const.h>
+
+#define FIXUP_WITH_ADDR UL(1)
+
+#ifndef __ASSEMBLY__
+
/*
* The exception table consists of pairs of relative offsets: the first
* is the relative offset to an instruction that is allowed to fault,
@@ -22,5 +28,7 @@ struct exception_table_entry
#define ARCH_HAS_RELATIVE_EXTABLE
-extern int fixup_exception(struct pt_regs *regs);
+extern int fixup_exception(struct pt_regs *regs, unsigned long addr);
+
+#endif
#endif
@@ -6,13 +6,18 @@
#include <linux/extable.h>
#include <linux/uaccess.h>
-int fixup_exception(struct pt_regs *regs)
+int fixup_exception(struct pt_regs *regs, unsigned long addr)
{
const struct exception_table_entry *fixup;
fixup = search_exception_tables(instruction_pointer(regs));
- if (fixup)
- regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
-
+ if (fixup) {
+ unsigned long offset = fixup->fixup;
+ if (offset & FIXUP_WITH_ADDR) {
+ regs->regs[15] = addr;
+ offset &= ~FIXUP_WITH_ADDR;
+ }
+ regs->pc = (unsigned long)&fixup->fixup + offset;
+ }
return fixup != NULL;
}
@@ -295,7 +295,7 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
* Are we prepared to handle this kernel fault?
* We are almost certainly not prepared to handle instruction faults.
*/
- if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
+ if (!is_el1_instruction_abort(esr) && fixup_exception(regs, addr))
return;
if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs),