kexec on pseries disables AIL (reloc_on_exc), required for scv
instruction support, before other CPUs have been shut down. This means
they can execute scv instructions after AIL is disabled, which causes an
interrupt at an unexpected entry location that crashes the kernel.

Change the kexec sequence to disable AIL after other CPUs have been
brought down.

As a refresher, the real-mode scv interrupt vector is 0x17000, and the
fixed-location head code probably couldn't easily deal with implementing
such high addresses so it was just decided not to support that interrupt
at all.

Reported-by: Sourabh Jain <sourabhj...@linux.ibm.com>
Fixes: 7fa95f9adaee7 ("powerpc/64s: system call support for scv/rfscv 
instructions")
Signed-off-by: Nicholas Piggin <npig...@gmail.com>
---
 arch/powerpc/kexec/core_64.c             | 11 +++++++++++
 arch/powerpc/platforms/pseries/kexec.c   |  8 --------
 arch/powerpc/platforms/pseries/pseries.h |  1 -
 arch/powerpc/platforms/pseries/setup.c   |  1 -
 4 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c
index 85050be08a23..72b12bc10f90 100644
--- a/arch/powerpc/kexec/core_64.c
+++ b/arch/powerpc/kexec/core_64.c
@@ -27,6 +27,7 @@
 #include <asm/paca.h>
 #include <asm/mmu.h>
 #include <asm/sections.h>      /* _end */
+#include <asm/setup.h>
 #include <asm/smp.h>
 #include <asm/hw_breakpoint.h>
 #include <asm/svm.h>
@@ -317,6 +318,16 @@ void default_machine_kexec(struct kimage *image)
        if (!kdump_in_progress())
                kexec_prepare_cpus();
 
+#ifdef CONFIG_PPC_PSERIES
+       /*
+        * This must be done after other CPUs have shut down, otherwise they
+        * could execute the 'scv' instruction, which is not supported with
+        * reloc disabled (see configure_exceptions()).
+        */
+       if (firmware_has_feature(FW_FEATURE_SET_MODE))
+               pseries_disable_reloc_on_exc();
+#endif
+
        printk("kexec: Starting switchover sequence.\n");
 
        /* switch to a staticly allocated stack.  Based on irq stack code.
diff --git a/arch/powerpc/platforms/pseries/kexec.c 
b/arch/powerpc/platforms/pseries/kexec.c
index 096d09ed89f6..431be156ca9b 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -61,11 +61,3 @@ void pseries_kexec_cpu_down(int crash_shutdown, int 
secondary)
        } else
                xics_kexec_teardown_cpu(secondary);
 }
-
-void pseries_machine_kexec(struct kimage *image)
-{
-       if (firmware_has_feature(FW_FEATURE_SET_MODE))
-               pseries_disable_reloc_on_exc();
-
-       default_machine_kexec(image);
-}
diff --git a/arch/powerpc/platforms/pseries/pseries.h 
b/arch/powerpc/platforms/pseries/pseries.h
index bba4ad192b0f..3968a6970fa8 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -38,7 +38,6 @@ static inline void smp_init_pseries(void) { }
 #endif
 
 extern void pseries_kexec_cpu_down(int crash_shutdown, int secondary);
-void pseries_machine_kexec(struct kimage *image);
 
 extern void pSeries_final_fixup(void);
 
diff --git a/arch/powerpc/platforms/pseries/setup.c 
b/arch/powerpc/platforms/pseries/setup.c
index 284a6fa04b0c..b44de0f0822f 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -1159,7 +1159,6 @@ define_machine(pseries) {
        .machine_check_exception = pSeries_machine_check_exception,
        .machine_check_log_err  = pSeries_machine_check_log_err,
 #ifdef CONFIG_KEXEC_CORE
-       .machine_kexec          = pseries_machine_kexec,
        .kexec_cpu_down         = pseries_kexec_cpu_down,
 #endif
 #ifdef CONFIG_MEMORY_HOTPLUG
-- 
2.45.1

Reply via email to