mbox

[00/15] arm64 kexec kernel patches v11

Message ID cover.1446836442.git.geoff@infradead.org
State New
Headers show

Pull-request

git://git.kernel.org/pub/scm/linux/kernel/git/geoff/linux-kexec.git kexec-v11

Message

Geoff Levand Nov. 6, 2015, 7:14 p.m. UTC
Hi All,

This series adds the core support for kexec re-boot and kdump on ARM64.  This
version of the series combines Takahiro's kdump patches with my kexec patches.

To load a second stage kernel and execute a kexec re-boot or to work with kdump
on ARM64 systems a series of patches to kexec-tools [2], which have not yet been
merged upstream, are needed.

I have tested kexec with the ARM Foundation model, and Takahiro has reported
that kdump is working on the 96boards HiKey developer board.  Kexec on EFI
systems works correctly.  More ACPI + kexec testing is needed.

Patch 1 here moves the macros from proc-macros.S to asm/assembler.h so that the
dcache_line_size macro it defines can be uesd by kexec's relocate kernel
routine.

Patches 2 & 3 rework the ARM64 hcall mechanism to give the CPU reset routines
the ability to switch exception levels from EL1 to EL2 for kernels that were
entered in EL2.

Patch 4 allows KVM to handle a CPU reset.

Patches 5 & 6 add back the ARM64 CPU reset support that was recently removed
from the kernel.

Patches 7 - 9 add kexec support.

Patches 10-15 add kdump support.

Please consider all patches for inclusion.

Changes since v10:

o Move the flush of the new image from arm64_relocate_new_kernel to machine_kexec.
o Pass values to arm64_relocate_new_kernel in registers, not in global variables.
o Fixups to setting the sctlr_el1 and sctlr_el2 flags.

[1]  https://git.kernel.org/cgit/linux/kernel/git/geoff/linux-kexec.git
[2]  https://git.kernel.org/cgit/linux/kernel/git/geoff/kexec-tools.git

-Geoff

The following changes since commit 6a13feb9c82803e2b815eca72fa7a9f5561d7861:

  Linux 4.3 (2015-11-01 16:05:25 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/geoff/linux-kexec.git kexec-v11

for you to fetch changes up to 2b09b58c7586a4ca929400327d394fec3135fdd0:

  arm64: kdump: relax BUG_ON() if more than one cpus are still active (2015-11-06 10:38:13 -0800)

----------------------------------------------------------------
AKASHI Takahiro (7):
      arm64: kvm: allows kvm cpu hotplug
      arm64: kdump: reserve memory for crash dump kernel
      arm64: kdump: implement machine_crash_shutdown()
      arm64: kdump: add kdump support
      arm64: kdump: update a kernel doc
      arm64: kdump: enable kdump in the arm64 defconfig
      arm64: kdump: relax BUG_ON() if more than one cpus are still active

Geoff Levand (8):
      arm64: Fold proc-macros.S into assembler.h
      arm64: Convert hcalls to use HVC immediate value
      arm64: Add new hcall HVC_CALL_FUNC
      arm64: Add back cpu_reset routines
      Revert "arm64: remove dead code"
      arm64/kexec: Add core kexec support
      arm64/kexec: Add pr_devel output
      arm64/kexec: Enable kexec in the arm64 defconfig

 Documentation/kdump/kdump.txt       |  32 ++++-
 arch/arm/include/asm/kvm_host.h     |  10 +-
 arch/arm/include/asm/kvm_mmu.h      |   1 +
 arch/arm/kvm/arm.c                  |  79 ++++++------
 arch/arm/kvm/mmu.c                  |   5 +
 arch/arm64/Kconfig                  |  22 ++++
 arch/arm64/configs/defconfig        |   2 +
 arch/arm64/include/asm/assembler.h  |  48 ++++++-
 arch/arm64/include/asm/kexec.h      |  80 ++++++++++++
 arch/arm64/include/asm/kvm_host.h   |  16 ++-
 arch/arm64/include/asm/kvm_mmu.h    |   1 +
 arch/arm64/include/asm/mmu.h        |   1 +
 arch/arm64/include/asm/virt.h       |  49 +++++++
 arch/arm64/kernel/Makefile          |   3 +
 arch/arm64/kernel/cpu-reset.S       |  84 ++++++++++++
 arch/arm64/kernel/cpu-reset.h       |  22 ++++
 arch/arm64/kernel/crash_dump.c      |  71 +++++++++++
 arch/arm64/kernel/head.S            |   1 -
 arch/arm64/kernel/hyp-stub.S        |  43 +++++--
 arch/arm64/kernel/machine_kexec.c   | 248 ++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/relocate_kernel.S | 131 +++++++++++++++++++
 arch/arm64/kernel/setup.c           |   7 +-
 arch/arm64/kernel/smp.c             |  16 ++-
 arch/arm64/kvm/hyp-init.S           |  34 ++++-
 arch/arm64/kvm/hyp.S                |  44 +++++--
 arch/arm64/mm/cache.S               |   2 -
 arch/arm64/mm/init.c                |  83 ++++++++++++
 arch/arm64/mm/mmu.c                 |  11 ++
 arch/arm64/mm/proc-macros.S         |  64 ----------
 arch/arm64/mm/proc.S                |   3 -
 include/uapi/linux/kexec.h          |   1 +
 31 files changed, 1074 insertions(+), 140 deletions(-)
 create mode 100644 arch/arm64/include/asm/kexec.h
 create mode 100644 arch/arm64/kernel/cpu-reset.S
 create mode 100644 arch/arm64/kernel/cpu-reset.h
 create mode 100644 arch/arm64/kernel/crash_dump.c
 create mode 100644 arch/arm64/kernel/machine_kexec.c
 create mode 100644 arch/arm64/kernel/relocate_kernel.S
 delete mode 100644 arch/arm64/mm/proc-macros.S

Comments

AKASHI Takahiro Nov. 10, 2015, 1:23 a.m. UTC | #1
On 11/07/2015 04:14 AM, Geoff Levand wrote:
> From: AKASHI Takahiro <takahiro.akashi@linaro.org>
>
> kdump calls machine_crash_shutdown() to shut down non-boot cpus and
> save registers' status in per-cpu ELF notes before starting the crash
> dump kernel. See kernel_kexec().
>
> ipi_cpu_stop() is a bit modified and used to support this behavior.

I've got some concerns of using ipi_cpu_stop().

> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> ---
>   arch/arm64/include/asm/kexec.h    | 34 +++++++++++++++++++++++++++++++++-
>   arch/arm64/kernel/machine_kexec.c | 31 +++++++++++++++++++++++++++++--
>   arch/arm64/kernel/smp.c           | 16 ++++++++++++++--
>   3 files changed, 76 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
> index 46d63cd..555a955 100644
> --- a/arch/arm64/include/asm/kexec.h
> +++ b/arch/arm64/include/asm/kexec.h
> @@ -30,6 +30,8 @@
>
>   #if !defined(__ASSEMBLY__)
>
> +extern bool in_crash_kexec;
> +
>   /**
>    * crash_setup_regs() - save registers for the panic kernel
>    *
> @@ -40,7 +42,37 @@
>   static inline void crash_setup_regs(struct pt_regs *newregs,
>   				    struct pt_regs *oldregs)
>   {
> -	/* Empty routine needed to avoid build errors. */
> +	if (oldregs) {
> +		memcpy(newregs, oldregs, sizeof(*newregs));
> +	} else {
> +		__asm__ __volatile__ (
> +			"stp	 x0,   x1, [%3, #16 *  0]\n"
> +			"stp	 x2,   x3, [%3, #16 *  1]\n"
> +			"stp	 x4,   x5, [%3, #16 *  2]\n"
> +			"stp	 x6,   x7, [%3, #16 *  3]\n"
> +			"stp	 x8,   x9, [%3, #16 *  4]\n"
> +			"stp	x10,  x11, [%3, #16 *  5]\n"
> +			"stp	x12,  x13, [%3, #16 *  6]\n"
> +			"stp	x14,  x15, [%3, #16 *  7]\n"
> +			"stp	x16,  x17, [%3, #16 *  8]\n"
> +			"stp	x18,  x19, [%3, #16 *  9]\n"
> +			"stp	x20,  x21, [%3, #16 * 10]\n"
> +			"stp	x22,  x23, [%3, #16 * 11]\n"
> +			"stp	x24,  x25, [%3, #16 * 12]\n"
> +			"stp	x26,  x27, [%3, #16 * 13]\n"
> +			"stp	x28,  x29, [%3, #16 * 14]\n"
> +			"str	x30,	   [%3, #16 * 15]\n"
> +			"mov	%0, sp\n"
> +			"adr	%1, 1f\n"
> +			"mrs	%2, spsr_el1\n"
> +		"1:"
> +			: "=r" (newregs->sp),
> +			  "=r" (newregs->pc),
> +			  "=r" (newregs->pstate)
> +			: "r"  (&newregs->regs)
> +			: "memory"
> +		);
> +	}
>   }
>
>   #endif /* !defined(__ASSEMBLY__) */
> diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c
> index da28a26..d2d7e90 100644
> --- a/arch/arm64/kernel/machine_kexec.c
> +++ b/arch/arm64/kernel/machine_kexec.c
> @@ -9,6 +9,7 @@
>    * published by the Free Software Foundation.
>    */
>
> +#include <linux/kernel.h>
>   #include <linux/kexec.h>
>   #include <linux/of_fdt.h>
>   #include <linux/slab.h>
> @@ -23,6 +24,7 @@
>   extern const unsigned char arm64_relocate_new_kernel[];
>   extern const unsigned long arm64_relocate_new_kernel_size;
>
> +bool in_crash_kexec;
>   static unsigned long kimage_start;
>
>   /**
> @@ -203,13 +205,38 @@ void machine_kexec(struct kimage *kimage)
>   	 */
>
>   	cpu_soft_restart(virt_to_phys(cpu_reset),
> -		is_hyp_mode_available(),
> +		in_crash_kexec ? 0 : is_hyp_mode_available(),
>   		reboot_code_buffer_phys, kimage->head, kimage_start);
>
>   	BUG(); /* Should never get here. */
>   }
>
> +/**
> + * machine_crash_shutdown - shutdown non-boot cpus and save registers
> + */
>   void machine_crash_shutdown(struct pt_regs *regs)
>   {
> -	/* Empty routine needed to avoid build errors. */
> +	struct pt_regs dummy_regs;
> +	int cpu;
> +
> +	local_irq_disable();
> +
> +	in_crash_kexec = true;
> +
> +	/*
> +	 * clear and initialize the per-cpu info. This is necessary
> +	 * because, otherwise, slots for offline cpus would never be
> +	 * filled up. See smp_send_stop().
> +	 */
> +	memset(&dummy_regs, 0, sizeof(dummy_regs));
> +	for_each_possible_cpu(cpu)
> +		crash_save_cpu(&dummy_regs, cpu);
> +
> +	/* shutdown non-boot cpus */
> +	smp_send_stop();
> +
> +	/* for boot cpu */
> +	crash_save_cpu(regs, smp_processor_id());
> +
> +	pr_info("Starting crashdump kernel...\n");
>   }
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index dbdaacd..88aec66 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -37,6 +37,7 @@
>   #include <linux/completion.h>
>   #include <linux/of.h>
>   #include <linux/irq_work.h>
> +#include <linux/kexec.h>
>
>   #include <asm/alternative.h>
>   #include <asm/atomic.h>
> @@ -54,6 +55,8 @@
>   #include <asm/ptrace.h>
>   #include <asm/virt.h>
>
> +#include "cpu-reset.h"
> +
>   #define CREATE_TRACE_POINTS
>   #include <trace/events/ipi.h>
>
> @@ -679,8 +682,12 @@ static DEFINE_RAW_SPINLOCK(stop_lock);
>   /*
>    * ipi_cpu_stop - handle IPI from smp_send_stop()
>    */
> -static void ipi_cpu_stop(unsigned int cpu)
> +static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
>   {
> +#ifdef CONFIG_KEXEC
> +	/* printing messages may slow down the shutdown. */
> +	if (!in_crash_kexec)
> +#endif
>   	if (system_state == SYSTEM_BOOTING ||
>   	    system_state == SYSTEM_RUNNING) {
>   		raw_spin_lock(&stop_lock);
> @@ -693,6 +700,11 @@ static void ipi_cpu_stop(unsigned int cpu)
>
>   	local_irq_disable();
>
> +#ifdef CONFIG_KEXEC
> +	if (in_crash_kexec)
> +		crash_save_cpu(regs, cpu);
> +#endif /* CONFIG_KEXEC */
> +
>   	while (1)
>   		cpu_relax();
>   }

cpu_relax() is defined as asm("yield"), and this puts all but boot cpu into
a infinite loop of nop (actually, whether nop or other depends on hw implementation).
Thus all the secondary cpus are still running busy loop even after crash dump kernel
has started up, and the chip can potentially get overheated.
I ran into this situation when I tested the code on Hikey, and the system was
forced to be shut down by thermal driver.

So I'd like to modify the code a bit like:
if (in_crash_kernel {
     crash_save_cpu(regs, cpu);
     while (1)
         asm("wfi"); /* irq is disabled here. */
}

Does this make sense?

-Takahiro AKASHI

> @@ -723,7 +735,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
>
>   	case IPI_CPU_STOP:
>   		irq_enter();
> -		ipi_cpu_stop(cpu);
> +		ipi_cpu_stop(cpu, regs);
>   		irq_exit();
>   		break;
>
>
Will Deacon Nov. 10, 2015, 9:54 a.m. UTC | #2
On Tue, Nov 10, 2015 at 10:23:56AM +0900, AKASHI Takahiro wrote:
> On 11/07/2015 04:14 AM, Geoff Levand wrote:
> >From: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >
> >kdump calls machine_crash_shutdown() to shut down non-boot cpus and
> >save registers' status in per-cpu ELF notes before starting the crash
> >dump kernel. See kernel_kexec().
> >
> >ipi_cpu_stop() is a bit modified and used to support this behavior.
> 
> I've got some concerns of using ipi_cpu_stop().
> 
> >Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
> >---
> >  arch/arm64/include/asm/kexec.h    | 34 +++++++++++++++++++++++++++++++++-
> >  arch/arm64/kernel/machine_kexec.c | 31 +++++++++++++++++++++++++++++--
> >  arch/arm64/kernel/smp.c           | 16 ++++++++++++++--
> >  3 files changed, 76 insertions(+), 5 deletions(-)

[...]

> >diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> >index dbdaacd..88aec66 100644
> >--- a/arch/arm64/kernel/smp.c
> >+++ b/arch/arm64/kernel/smp.c
> >@@ -37,6 +37,7 @@
> >  #include <linux/completion.h>
> >  #include <linux/of.h>
> >  #include <linux/irq_work.h>
> >+#include <linux/kexec.h>
> >
> >  #include <asm/alternative.h>
> >  #include <asm/atomic.h>
> >@@ -54,6 +55,8 @@
> >  #include <asm/ptrace.h>
> >  #include <asm/virt.h>
> >
> >+#include "cpu-reset.h"
> >+
> >  #define CREATE_TRACE_POINTS
> >  #include <trace/events/ipi.h>
> >
> >@@ -679,8 +682,12 @@ static DEFINE_RAW_SPINLOCK(stop_lock);
> >  /*
> >   * ipi_cpu_stop - handle IPI from smp_send_stop()
> >   */
> >-static void ipi_cpu_stop(unsigned int cpu)
> >+static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
> >  {
> >+#ifdef CONFIG_KEXEC
> >+	/* printing messages may slow down the shutdown. */
> >+	if (!in_crash_kexec)
> >+#endif
> >  	if (system_state == SYSTEM_BOOTING ||
> >  	    system_state == SYSTEM_RUNNING) {
> >  		raw_spin_lock(&stop_lock);
> >@@ -693,6 +700,11 @@ static void ipi_cpu_stop(unsigned int cpu)
> >
> >  	local_irq_disable();
> >
> >+#ifdef CONFIG_KEXEC
> >+	if (in_crash_kexec)
> >+		crash_save_cpu(regs, cpu);
> >+#endif /* CONFIG_KEXEC */
> >+
> >  	while (1)
> >  		cpu_relax();
> >  }
> 
> cpu_relax() is defined as asm("yield"), and this puts all but boot cpu into
> a infinite loop of nop (actually, whether nop or other depends on hw implementation).
> Thus all the secondary cpus are still running busy loop even after crash dump kernel
> has started up, and the chip can potentially get overheated.
> I ran into this situation when I tested the code on Hikey, and the system was
> forced to be shut down by thermal driver.
> 
> So I'd like to modify the code a bit like:
> if (in_crash_kernel {
>     crash_save_cpu(regs, cpu);
>     while (1)
>         asm("wfi"); /* irq is disabled here. */
> }
> 
> Does this make sense?

It would be even better if we could hotplug them off.

Will