diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h index c320f3bf6c57..8c64bf7d2387 100644 --- a/arch/arm64/include/asm/traps.h +++ b/arch/arm64/include/asm/traps.h @@ -120,4 +120,12 @@ static inline u32 arm64_ras_serror_get_severity(u32 esr) bool arm64_is_fatal_ras_serror(struct pt_regs *regs, unsigned int esr); void __noreturn arm64_serror_panic(struct pt_regs *regs, u32 esr); + +extern int (*do_tlb_conf_fault_cb)(unsigned long addr, + unsigned int esr, + struct pt_regs *regs); +extern int do_tlb_conf_fault(unsigned long addr, + unsigned int esr, + struct pt_regs *regs); + #endif diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index fe6eca4ca4de..d44543c445d3 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -613,6 +613,26 @@ no_context: return 0; } +int __weak do_tlb_conf_fault(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + return 1; /* do_bad default */ +} + +int (*do_tlb_conf_fault_cb)(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) + = do_tlb_conf_fault; /* initialization saves us a branch */ +EXPORT_SYMBOL_GPL(do_tlb_conf_fault_cb); + +static int _do_tlb_conf_fault(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + return (*do_tlb_conf_fault_cb)(addr, esr, regs); +} + static int __kprobes do_translation_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) @@ -720,7 +740,7 @@ static const struct fault_info fault_info[] = { { do_bad, SIGKILL, SI_KERNEL, "unknown 45" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 46" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 47" }, - { do_bad, SIGKILL, SI_KERNEL, "TLB conflict abort" }, + { _do_tlb_conf_fault, SIGKILL, SI_KERNEL, "TLB conflict abort" }, { do_bad, SIGKILL, SI_KERNEL, "Unsupported atomic hardware update fault" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 50" }, { do_bad, SIGKILL, SI_KERNEL, "unknown 51" },