[v2 06/12] powerpc/mce: Add fixup address to UE events
From: Santosh Sivaraj <hidden>
Date: 2019-07-02 05:25:34
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Linus Torvalds
From: Reza Arbab <redacted> If the instruction causing a UE has an exception table entry with fixup address, save it in the machine_check_event struct. If a machine check notifier callback returns NOTIFY_STOP to indicate it has handled the error, set nip to continue execution from the fixup address. Signed-off-by: Reza Arbab <redacted> --- arch/powerpc/include/asm/mce.h | 5 +++-- arch/powerpc/kernel/mce.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 240dd1fdfe35..9d9661747adf 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h@@ -122,11 +122,12 @@ struct machine_check_event { enum MCE_UeErrorType ue_error_type:8; u8 effective_address_provided; u8 physical_address_provided; + u8 fixup_address_provided; u8 process_event; - u8 reserved_1[4]; + u8 reserved_1[3]; u64 effective_address; u64 physical_address; - u8 reserved_2[8]; + u64 fixup_address; } ue_error; struct {
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index 4a37928ab30e..0233c0ee45ab 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c@@ -15,10 +15,12 @@ #include <linux/percpu.h> #include <linux/export.h> #include <linux/irq_work.h> +#include <linux/extable.h> #include <asm/machdep.h> #include <asm/mce.h> #include <asm/nmi.h> +#include <asm/extable.h> static DEFINE_PER_CPU(int, mce_nest_count); static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event);
@@ -151,6 +153,8 @@ void save_mce_event(struct pt_regs *regs, long handled, mce->u.link_error.effective_address_provided = true; mce->u.link_error.effective_address = addr; } else if (mce->error_type == MCE_ERROR_TYPE_UE) { + const struct exception_table_entry *entry; + mce->u.ue_error.effective_address_provided = true; mce->u.ue_error.effective_address = addr; if (phys_addr != ULONG_MAX) {
@@ -158,6 +162,12 @@ void save_mce_event(struct pt_regs *regs, long handled, mce->u.ue_error.physical_address = phys_addr; } + entry = search_exception_tables(regs->nip); + if (entry) { + mce->u.ue_error.fixup_address_provided = true; + mce->u.ue_error.fixup_address = extable_fixup(entry); + } + mce->u.ue_error.process_event = true; } return;
@@ -666,8 +676,12 @@ long machine_check_notify(struct pt_regs *regs) rc = blocking_notifier_call_chain(&mce_notifier_list, 0, evt); if (rc & NOTIFY_STOP_MASK) { - if (evt->error_type == MCE_ERROR_TYPE_UE) + if (evt->error_type == MCE_ERROR_TYPE_UE) { + if (evt->u.ue_error.fixup_address_provided) + regs->nip = evt->u.ue_error.fixup_address; + evt->u.ue_error.process_event = false; + } if ((rc & NOTIFY_STOP_MASK) && (regs->msr & MSR_RI)) evt->disposition = MCE_DISPOSITION_RECOVERED;
--
2.20.1