| From foo@baz Sun Jun 17 12:07:34 CEST 2018 |
| From: Russell King <rmk+kernel@armlinux.org.uk> |
| Date: Wed, 11 Apr 2018 18:24:01 +0100 |
| Subject: ARM: kexec: fix kdump register saving on panic() |
| |
| From: Russell King <rmk+kernel@armlinux.org.uk> |
| |
| [ Upstream commit 2d7b3c64431245c95b05a441669c074da10db943 ] |
| |
| When a panic() occurs, the kexec code uses smp_send_stop() to stop |
| the other CPUs, but this results in the CPU register state not being |
| saved, and gdb is unable to inspect the state of other CPUs. |
| |
| Commit 0ee59413c967 ("x86/panic: replace smp_send_stop() with kdump |
| friendly version in panic path") addressed the issue on x86, but |
| ignored other architectures. Address the issue on ARM by splitting |
| out the crash stop implementation to crash_smp_send_stop() and |
| adding the necessary protection. |
| |
| Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/arm/kernel/machine_kexec.c | 34 ++++++++++++++++++++++------------ |
| 1 file changed, 22 insertions(+), 12 deletions(-) |
| |
| --- a/arch/arm/kernel/machine_kexec.c |
| +++ b/arch/arm/kernel/machine_kexec.c |
| @@ -95,6 +95,27 @@ void machine_crash_nonpanic_core(void *u |
| cpu_relax(); |
| } |
| |
| +void crash_smp_send_stop(void) |
| +{ |
| + static int cpus_stopped; |
| + unsigned long msecs; |
| + |
| + if (cpus_stopped) |
| + return; |
| + |
| + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); |
| + smp_call_function(machine_crash_nonpanic_core, NULL, false); |
| + msecs = 1000; /* Wait at most a second for the other cpus to stop */ |
| + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { |
| + mdelay(1); |
| + msecs--; |
| + } |
| + if (atomic_read(&waiting_for_crash_ipi) > 0) |
| + pr_warn("Non-crashing CPUs did not react to IPI\n"); |
| + |
| + cpus_stopped = 1; |
| +} |
| + |
| static void machine_kexec_mask_interrupts(void) |
| { |
| unsigned int i; |
| @@ -120,19 +141,8 @@ static void machine_kexec_mask_interrupt |
| |
| void machine_crash_shutdown(struct pt_regs *regs) |
| { |
| - unsigned long msecs; |
| - |
| local_irq_disable(); |
| - |
| - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); |
| - smp_call_function(machine_crash_nonpanic_core, NULL, false); |
| - msecs = 1000; /* Wait at most a second for the other cpus to stop */ |
| - while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { |
| - mdelay(1); |
| - msecs--; |
| - } |
| - if (atomic_read(&waiting_for_crash_ipi) > 0) |
| - pr_warn("Non-crashing CPUs did not react to IPI\n"); |
| + crash_smp_send_stop(); |
| |
| crash_save_cpu(regs, smp_processor_id()); |
| machine_kexec_mask_interrupts(); |