[PATCH 07/13] powerpc/mce: Add fixup address to UE events

Santosh Sivaraj santosh at fossix.org
Fri Jun 21 14:55:49 AEST 2019


From: Reza Arbab <arbab at linux.ibm.com>

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 <arbab at linux.ibm.com>
---
 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 2616f1f71734..8afda1ab7358 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;
+		}
 
 		evt->disposition = MCE_DISPOSITION_RECOVERED;
 		regs->msr |= MSR_RI;
-- 
2.20.1



More information about the Linuxppc-dev mailing list