* [PATCH v3 1/3] LoongArch: Add kexec support
2022-09-15 2:53 [PATCH v3 0/3] LoongArch: Add kexec/kdump support Youling Tang
@ 2022-09-15 2:53 ` Youling Tang
2022-09-22 10:00 ` Xi Ruoyao
2022-09-15 2:53 ` [PATCH v3 2/3] LoongArch: Add kdump support Youling Tang
2022-09-15 2:53 ` [PATCH v3 3/3] LoongArch: Enable CONFIG_KEXEC Youling Tang
2 siblings, 1 reply; 6+ messages in thread
From: Youling Tang @ 2022-09-15 2:53 UTC (permalink / raw)
To: Huacai Chen, Baoquan He, Eric Biederman
Cc: WANG Xuerui, Vivek Goyal, Dave Young, Guo Ren, Jiaxun Yang, kexec,
loongarch, linux-kernel
Add three new files, kexec.h, machine_kexec.c and relocate_kernel.S to the
LoongArch architecture that add support for the kexec re-boot mechanis
(CONFIG_KEXEC) on LoongArch platforms.
Supports loading vmlinux (vmlinux.elf) in ELF format and vmlinux.efi in
PE format.
I tested this on LoongArch 3A5000 machine and works as expected,
$ sudo kexec -l /boot/vmlinux.efi --reuse-cmdline
$ sudo kexec -e
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
---
arch/loongarch/Kconfig | 11 ++
arch/loongarch/include/asm/kexec.h | 58 +++++++
arch/loongarch/kernel/Makefile | 2 +
arch/loongarch/kernel/head.S | 6 +-
arch/loongarch/kernel/machine_kexec.c | 209 ++++++++++++++++++++++++
arch/loongarch/kernel/relocate_kernel.S | 105 ++++++++++++
6 files changed, 390 insertions(+), 1 deletion(-)
create mode 100644 arch/loongarch/include/asm/kexec.h
create mode 100644 arch/loongarch/kernel/machine_kexec.c
create mode 100644 arch/loongarch/kernel/relocate_kernel.S
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 9b1f2ab878e9..08e063aaf847 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -422,6 +422,17 @@ config ARCH_IOREMAP
protection support. However, you can enable LoongArch DMW-based
ioremap() for better performance.
+config KEXEC
+ bool "Kexec system call"
+ select KEXEC_CORE
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is independent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similarity to the exec system call.
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
new file mode 100644
index 000000000000..e5b022d335c7
--- /dev/null
+++ b/arch/loongarch/include/asm/kexec.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * kexec.h for kexec
+ *
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#ifndef _ASM_KEXEC_H
+#define _ASM_KEXEC_H
+
+#include <asm/stacktrace.h>
+#include <asm/page.h>
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+ /* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+/* Reserve a page for the control code buffer */
+#define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_LOONGARCH
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs)
+{
+ if (oldregs)
+ memcpy(newregs, oldregs, sizeof(*newregs));
+ else
+ prepare_frametrace(newregs);
+}
+
+#define ARCH_HAS_KIMAGE_ARCH
+
+struct kimage_arch {
+ unsigned long efi_boot;
+ unsigned long fdt_addr;
+};
+
+typedef void (*do_kexec_t)(unsigned long efi_boot,
+ unsigned long fdt_addr,
+ unsigned long jump_addr,
+ unsigned long first_ind_entry);
+
+struct kimage;
+extern const unsigned char relocate_new_kernel[];
+extern const size_t relocate_new_kernel_size;
+extern void kexec_reboot(void);
+
+#ifdef CONFIG_SMP
+extern atomic_t kexec_ready_to_reboot;
+extern const unsigned char kexec_smp_wait[];
+#endif
+
+#endif /* !_ASM_KEXEC_H */
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 7225916dd378..17dc8ce6b5ce 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -17,6 +17,8 @@ obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
obj-$(CONFIG_MODULES) += module.o module-sections.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index eb3f641d5915..c0d61b29fcaa 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -20,7 +20,11 @@
_head:
.word MZ_MAGIC /* "MZ", MS-DOS header */
- .org 0x3c /* 0x04 ~ 0x3b reserved */
+ .org 0x8
+ .dword kernel_entry /* Kernel entry point */
+ .dword _end - _text /* Effective size of kernel image */
+ .quad 0 /* Image load offset from start of RAM */
+ .org 0x3c /* 0x20 ~ 0x3b reserved */
.long pe_header - _head /* Offset to the PE header */
pe_header:
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
new file mode 100644
index 000000000000..a2f3c3e65130
--- /dev/null
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * machine_kexec.c for kexec
+ *
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+#include <linux/compiler.h>
+#include <linux/cpu.h>
+#include <linux/kexec.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+
+#include <asm/bootinfo.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+
+/* 0x100000 ~ 0x200000 is safe */
+#define KEXEC_CTRL_CODE TO_CACHE(0x100000UL)
+#define KEXEC_BLOB_ADDR TO_CACHE(0x108000UL)
+
+static unsigned long reboot_code_buffer;
+
+#ifdef CONFIG_SMP
+static void (*relocated_kexec_smp_wait)(void *);
+atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+#endif
+
+static unsigned long efi_boot;
+static unsigned long fdt_addr;
+static unsigned long jump_addr;
+static unsigned long first_ind_entry;
+
+static void kexec_image_info(const struct kimage *kimage)
+{
+ unsigned long i;
+
+ pr_debug("kexec kimage info:\n");
+ pr_debug("\ttype: %d\n", kimage->type);
+ pr_debug("\tstart: %lx\n", kimage->start);
+ pr_debug("\thead: %lx\n", kimage->head);
+ pr_debug("\tnr_segments: %lu\n", kimage->nr_segments);
+
+ for (i = 0; i < kimage->nr_segments; i++) {
+ pr_debug("\t segment[%lu]: %016lx - %016lx", i,
+ kimage->segment[i].mem,
+ kimage->segment[i].mem + kimage->segment[i].memsz);
+ pr_debug("\t\t0x%lx bytes, %lu pages\n",
+ (unsigned long)kimage->segment[i].memsz,
+ (unsigned long)kimage->segment[i].memsz / PAGE_SIZE);
+ }
+}
+
+int machine_kexec_prepare(struct kimage *kimage)
+{
+ int i;
+ void *dtb = (void *)KEXEC_BLOB_ADDR;
+
+ kexec_image_info(kimage);
+
+ /* Find the Flattened Device Tree */
+ for (i = 0; i < kimage->nr_segments; i++) {
+ if (!fdt_check_header(kimage->segment[i].buf)) {
+ memcpy(dtb, kimage->segment[i].buf, SZ_64K);
+ kimage->arch.efi_boot = fw_arg0;
+ kimage->arch.fdt_addr = (unsigned long) dtb;
+ break;
+ }
+ continue;
+ }
+
+ /* kexec need a safe page to save reboot_code_buffer */
+ kimage->control_code_page = virt_to_page((void *)KEXEC_CTRL_CODE);
+
+ reboot_code_buffer =
+ (unsigned long)page_address(kimage->control_code_page);
+ memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+#ifdef CONFIG_SMP
+ /* All secondary cpus now may jump to kexec_smp_wait cycle */
+ relocated_kexec_smp_wait = reboot_code_buffer +
+ (void *)(kexec_smp_wait - relocate_new_kernel);
+#endif
+
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *kimage)
+{
+}
+
+void kexec_reboot(void)
+{
+ do_kexec_t do_kexec = NULL;
+
+ /*
+ * We know we were online, and there will be no incoming IPIs at
+ * this point.
+ */
+ set_cpu_online(smp_processor_id(), true);
+
+ /* Ensure remote CPUs observe that we're online before rebooting. */
+ smp_mb__after_atomic();
+
+ /*
+ * Make sure we get correct instructions written by the
+ * machine_kexec_prepare() CPU.
+ */
+ asm volatile ("\tibar 0\n"::);
+
+#ifdef CONFIG_SMP
+ /* All secondary cpus go to kexec_smp_wait */
+ if (smp_processor_id() > 0) {
+ relocated_kexec_smp_wait(NULL);
+ unreachable();
+ }
+#endif
+
+ do_kexec = (void *)reboot_code_buffer;
+ do_kexec(efi_boot, fdt_addr, jump_addr, first_ind_entry);
+
+ unreachable();
+}
+
+
+#ifdef CONFIG_SMP
+static void kexec_shutdown_secondary(void *)
+{
+ int cpu = smp_processor_id();
+
+ if (!cpu_online(cpu))
+ return;
+
+ /* We won't be sent IPIs any more. */
+ set_cpu_online(cpu, false);
+
+ local_irq_disable();
+ while (!atomic_read(&kexec_ready_to_reboot))
+ cpu_relax();
+
+ kexec_reboot();
+}
+#endif
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
+void machine_shutdown(void)
+{
+ int cpu;
+
+ /* All CPUs go to reboot_code_buffer */
+ for_each_possible_cpu(cpu)
+ if (!cpu_online(cpu))
+ cpu_device_up(get_cpu_device(cpu));
+
+#ifdef CONFIG_SMP
+ smp_call_function(kexec_shutdown_secondary, NULL, 0);
+#endif
+}
+
+void machine_kexec(struct kimage *image)
+{
+ unsigned long entry;
+ unsigned long *ptr;
+ struct kimage_arch *internal = &image->arch;
+
+ efi_boot = internal->efi_boot;
+ fdt_addr = internal->fdt_addr;
+
+ jump_addr = (unsigned long)phys_to_virt(image->start);
+
+ first_ind_entry = (unsigned long)phys_to_virt(image->head & PAGE_MASK);
+
+ /*
+ * The generic kexec code builds a page list with physical
+ * addresses. they are directly accessible through XKPRANGE
+ * hence the phys_to_virt() call.
+ */
+ for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+ ptr = (entry & IND_INDIRECTION) ?
+ phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+ if (*ptr & IND_SOURCE || *ptr & IND_INDIRECTION ||
+ *ptr & IND_DESTINATION)
+ *ptr = (unsigned long) phys_to_virt(*ptr);
+ }
+
+ /* Mark offline before disabling local irq. */
+ set_cpu_online(smp_processor_id(), false);
+
+ /* we do not want to be bothered. */
+ local_irq_disable();
+
+ pr_notice("Will call new kernel at %lx\n", jump_addr);
+ pr_notice("FDT image at %lx\n", fdt_addr);
+ pr_notice("Bye ...\n");
+
+ /* Make reboot code buffer available to the boot CPU. */
+ flush_cache_all();
+
+#ifdef CONFIG_SMP
+ atomic_set(&kexec_ready_to_reboot, 1);
+#endif
+
+ kexec_reboot();
+}
diff --git a/arch/loongarch/kernel/relocate_kernel.S b/arch/loongarch/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..0ea8b29242e6
--- /dev/null
+++ b/arch/loongarch/kernel/relocate_kernel.S
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * relocate_kernel.S for kexec
+ *
+ * Copyright (C) 2022 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kexec.h>
+
+#include <asm/asm.h>
+#include <asm/asmmacro.h>
+#include <asm/regdef.h>
+#include <asm/loongarch.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+
+SYM_CODE_START(relocate_new_kernel)
+ /*
+ * a0: Boot flag passed to the new kernel
+ * a1: Virt address of the FDT image
+ * a2: Virt address to jump to after relocation
+ * a3: Pointer to the current indirection page entry
+ */
+
+ move s0, a3
+
+process_entry:
+ PTR_L s1, s0, 0
+ PTR_ADDI s0, s0, SZREG
+
+ /* destination page */
+ andi s2, s1, IND_DESTINATION
+ beqz s2, 1f
+ li.w t0, ~0x1
+ and s3, s1, t0 /* store destination addr in s3 */
+ b process_entry
+
+1:
+ /* indirection page, update s0 */
+ andi s2, s1, IND_INDIRECTION
+ beqz s2, 1f
+ li.w t0, ~0x2
+ and s0, s1, t0
+ b process_entry
+
+1:
+ /* done page */
+ andi s2, s1, IND_DONE
+ beqz s2, 1f
+ b done
+1:
+ /* source page */
+ andi s2, s1, IND_SOURCE
+ beqz s2, process_entry
+ li.w t0, ~0x8
+ and s1, s1, t0
+ li.w s5, (1 << _PAGE_SHIFT) / SZREG
+
+copy_word:
+ /* copy page word by word */
+ REG_L s4, s1, 0
+ REG_S s4, s3, 0
+ PTR_ADDI s3, s3, SZREG
+ PTR_ADDI s1, s1, SZREG
+ LONG_ADDI s5, s5, -1
+ beqz s5, process_entry
+ b copy_word
+ b process_entry
+
+done:
+ ibar 0
+ dbar 0
+
+ /*
+ * Jump to the new kernel,
+ * make sure the values of a0, a1 and a2 are not changed.
+ */
+ jr a2
+SYM_CODE_END(relocate_new_kernel)
+
+#ifdef CONFIG_SMP
+/*
+ * Other CPUs should wait until code is relocated and
+ * then start at entry (?) point.
+ */
+SYM_CODE_START(kexec_smp_wait)
+1: li.w t0, 0x100 /* wait for init loop */
+2: addi.w t0, t0, -1 /* limit mailbox access */
+ bnez t0, 2b
+ li.w t1, LOONGARCH_IOCSR_MBUF0
+ iocsrrd.w s0, t1 /* check PC as an indicator */
+ beqz s0, 1b
+ iocsrrd.d s0, t1 /* get PC via mailbox */
+
+ li.d t0, CACHE_BASE
+ or s0, s0, t0 /* s0 = TO_CACHE(s0) */
+ jr s0 /* jump to initial PC */
+SYM_CODE_END(kexec_smp_wait)
+#endif
+
+relocate_new_kernel_end:
+
+SYM_DATA_START(relocate_new_kernel_size)
+ PTR relocate_new_kernel_end - relocate_new_kernel
+SYM_DATA_END(relocate_new_kernel_size)
--
2.36.0
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH v3 1/3] LoongArch: Add kexec support
2022-09-15 2:53 ` [PATCH v3 1/3] LoongArch: Add kexec support Youling Tang
@ 2022-09-22 10:00 ` Xi Ruoyao
2022-09-22 10:30 ` Youling Tang
0 siblings, 1 reply; 6+ messages in thread
From: Xi Ruoyao @ 2022-09-22 10:00 UTC (permalink / raw)
To: Youling Tang, Huacai Chen, Baoquan He, Eric Biederman
Cc: WANG Xuerui, Vivek Goyal, Dave Young, Guo Ren, Jiaxun Yang, kexec,
loongarch, linux-kernel
On Thu, 2022-09-15 at 10:53 +0800, Youling Tang wrote:
> +int machine_kexec_prepare(struct kimage *kimage)
> +{
> + int i;
> + void *dtb = (void *)KEXEC_BLOB_ADDR;
> +
> + kexec_image_info(kimage);
> +
> + /* Find the Flattened Device Tree */
> + for (i = 0; i < kimage->nr_segments; i++) {
> + if (!fdt_check_header(kimage->segment[i].buf)) {
Hi Youling,
When I build Huacai's tree
(https://github.com/loongson/linux/commits/loongarch-next), there is a
strange error linking vmlinux:
ld: arch/loongarch/kernel/machine_kexec.o: in function `machine_kexec_prepare':
/home/xry111/git-repos/linux/arch/loongarch/kernel/machine_kexec.c:70: undefined reference to `fdt_check_header'
Not sure why...
--
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v3 1/3] LoongArch: Add kexec support
2022-09-22 10:00 ` Xi Ruoyao
@ 2022-09-22 10:30 ` Youling Tang
0 siblings, 0 replies; 6+ messages in thread
From: Youling Tang @ 2022-09-22 10:30 UTC (permalink / raw)
To: Xi Ruoyao, Huacai Chen, Baoquan He, Eric Biederman
Cc: WANG Xuerui, Vivek Goyal, Dave Young, Guo Ren, Jiaxun Yang, kexec,
loongarch, linux-kernel
Hi, Ruoyao
On 09/22/2022 06:00 PM, Xi Ruoyao wrote:
> On Thu, 2022-09-15 at 10:53 +0800, Youling Tang wrote:
>> +int machine_kexec_prepare(struct kimage *kimage)
>> +{
>> + int i;
>> + void *dtb = (void *)KEXEC_BLOB_ADDR;
>> +
>> + kexec_image_info(kimage);
>> +
>> + /* Find the Flattened Device Tree */
>> + for (i = 0; i < kimage->nr_segments; i++) {
>> + if (!fdt_check_header(kimage->segment[i].buf)) {
>
> Hi Youling,
>
> When I build Huacai's tree
> (https://github.com/loongson/linux/commits/loongarch-next), there is a
> strange error linking vmlinux:
>
> ld: arch/loongarch/kernel/machine_kexec.o: in function `machine_kexec_prepare':
> /home/xry111/git-repos/linux/arch/loongarch/kernel/machine_kexec.c:70: undefined reference to `fdt_check_header'
>
> Not sure why...
This is because of the problem after efistub removes the fdt
modification, I will reimplement kexec/kdump. This build error can be
avoided by turning off CONFIG_KEXEC temporarily, tomorrow I will submit
a new kexec/kdump implementation.
Thanks,
Youling.
>
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] LoongArch: Add kdump support
2022-09-15 2:53 [PATCH v3 0/3] LoongArch: Add kexec/kdump support Youling Tang
2022-09-15 2:53 ` [PATCH v3 1/3] LoongArch: Add kexec support Youling Tang
@ 2022-09-15 2:53 ` Youling Tang
2022-09-15 2:53 ` [PATCH v3 3/3] LoongArch: Enable CONFIG_KEXEC Youling Tang
2 siblings, 0 replies; 6+ messages in thread
From: Youling Tang @ 2022-09-15 2:53 UTC (permalink / raw)
To: Huacai Chen, Baoquan He, Eric Biederman
Cc: WANG Xuerui, Vivek Goyal, Dave Young, Guo Ren, Jiaxun Yang, kexec,
loongarch, linux-kernel
This patch adds support for kdump, the kernel will reserve a region
for the crash kernel and jump there on panic.
Arch-specific functions are added to allow for implementing a crash
dump file interface, /proc/vmcore, which can be viewed as a ELF file.
A user space tool, like kexec-tools, is responsible for allocating a
separate region for the core's ELF header within crash kdump kernel
memory and filling it in when executing kexec_load().
Then, its location will be advertised to crash dump kernel via a new
device-tree property, "linux,elfcorehdr", and crash dump kernel preserves
the region for later use with fdt_reserve_elfcorehdr() at boot time.
At the same time, it will also limit the crash kdump kernel to the
crashkernel area via a new device-tree property, "linux, usable-memory-range",
so as not to destroy the original kernel dump data.
On crash dump kernel, /proc/vmcore will access the primary kernel's memory
with copy_oldmem_page().
I tested this on LoongArch 3A5000 machine and works as expected (Suggest
crashkernel parameter is "crashkernel=512M@2560M"), you may test it by
triggering a crash through /proc/sysrq_trigger:
$ sudo kexec -p /boot/vmlinux-kdump --reuse-cmdline --append="nr_cpus=1"
# echo c > /proc/sysrq_trigger
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
---
arch/loongarch/Kconfig | 22 ++++++
arch/loongarch/Makefile | 4 +
arch/loongarch/kernel/Makefile | 1 +
arch/loongarch/kernel/crash_dump.c | 19 +++++
arch/loongarch/kernel/machine_kexec.c | 98 +++++++++++++++++++++++--
arch/loongarch/kernel/mem.c | 6 ++
arch/loongarch/kernel/relocate_kernel.S | 6 ++
arch/loongarch/kernel/setup.c | 49 +++++++++++++
arch/loongarch/kernel/traps.c | 4 +
9 files changed, 203 insertions(+), 6 deletions(-)
create mode 100644 arch/loongarch/kernel/crash_dump.c
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index 08e063aaf847..4eeeebf888c1 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -433,6 +433,28 @@ config KEXEC
The name comes from the similarity to the exec system call.
+config CRASH_DUMP
+ bool "Build kdump crash kernel"
+ help
+ Generate crash dump after being started by kexec. This should
+ be normally only set in special crash dump kernels which are
+ loaded in the main kernel with kexec-tools into a specially
+ reserved region and then later executed after a crash by
+ kdump/kexec.
+
+ For more details see Documentation/admin-guide/kdump/kdump.rst
+
+config PHYSICAL_START
+ hex "Physical address where the kernel is loaded"
+ default "0x90000000a0000000" if 64BIT
+ depends on CRASH_DUMP
+ help
+ This gives the XKPRANGE address where the kernel is loaded.
+ If you plan to use kernel for capturing the crash dump change
+ this value to start of the reserved region (the "X" value as
+ specified in the "crashkernel=YM@XM" command line boot parameter
+ passed to the panic-ed kernel).
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 69b39ba3a09d..224274c1644e 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -66,7 +66,11 @@ endif
cflags-y += -ffreestanding
cflags-y += $(call cc-option, -mno-check-zero-division)
+ifdef CONFIG_PHYSICAL_START
+load-y = $(CONFIG_PHYSICAL_START)
+else
load-y = 0x9000000000200000
+endif
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y)
drivers-$(CONFIG_PCI) += arch/loongarch/pci/
diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile
index 17dc8ce6b5ce..79eee7db1414 100644
--- a/arch/loongarch/kernel/Makefile
+++ b/arch/loongarch/kernel/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_MODULES) += module.o module-sections.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/arch/loongarch/kernel/crash_dump.c b/arch/loongarch/kernel/crash_dump.c
new file mode 100644
index 000000000000..13e5d2f7870d
--- /dev/null
+++ b/arch/loongarch/kernel/crash_dump.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
+#include <linux/io.h>
+
+ssize_t copy_oldmem_page(struct iov_iter *iter, unsigned long pfn,
+ size_t csize, unsigned long offset)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+
+ vaddr = kmap_local_pfn(pfn);
+ csize = copy_to_iter(vaddr + offset, csize, iter);
+ kunmap_local(vaddr);
+
+ return csize;
+}
diff --git a/arch/loongarch/kernel/machine_kexec.c b/arch/loongarch/kernel/machine_kexec.c
index a2f3c3e65130..c042d5e3bcfd 100644
--- a/arch/loongarch/kernel/machine_kexec.c
+++ b/arch/loongarch/kernel/machine_kexec.c
@@ -6,11 +6,16 @@
*/
#include <linux/compiler.h>
#include <linux/cpu.h>
-#include <linux/kexec.h>
-#include <linux/mm.h>
+#include <linux/crash_dump.h>
#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/kexec.h>
#include <linux/libfdt.h>
+#include <linux/mm.h>
#include <linux/of_fdt.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/sched/task_stack.h>
#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
@@ -21,6 +26,7 @@
#define KEXEC_BLOB_ADDR TO_CACHE(0x108000UL)
static unsigned long reboot_code_buffer;
+static cpumask_t cpus_in_crash = CPU_MASK_NONE;
#ifdef CONFIG_SMP
static void (*relocated_kexec_smp_wait)(void *);
@@ -70,7 +76,7 @@ int machine_kexec_prepare(struct kimage *kimage)
continue;
}
- /* kexec need a safe page to save reboot_code_buffer */
+ /* kexec/kdump need a safe page to save reboot_code_buffer */
kimage->control_code_page = virt_to_page((void *)KEXEC_CTRL_CODE);
reboot_code_buffer =
@@ -97,7 +103,8 @@ void kexec_reboot(void)
/*
* We know we were online, and there will be no incoming IPIs at
- * this point.
+ * this point. Mark online again before rebooting so that the crash
+ * analysis tool will see us correctly.
*/
set_cpu_online(smp_processor_id(), true);
@@ -142,10 +149,88 @@ static void kexec_shutdown_secondary(void *)
kexec_reboot();
}
-#endif
+
+static void crash_shutdown_secondary(void *passed_regs)
+{
+ struct pt_regs *regs = passed_regs;
+ int cpu = smp_processor_id();
+
+ /*
+ * If we are passed registers, use those. Otherwise get the
+ * regs from the last interrupt, which should be correct, as
+ * we are in an interrupt. But if the regs are not there,
+ * pull them from the top of the stack. They are probably
+ * wrong, but we need something to keep from crashing again.
+ */
+ if (!regs)
+ regs = get_irq_regs();
+ if (!regs)
+ regs = task_pt_regs(current);
+
+ /* We won't be sent IPIs any more. */
+ set_cpu_online(cpu, false);
+
+ local_irq_disable();
+ if (!cpumask_test_cpu(cpu, &cpus_in_crash))
+ crash_save_cpu(regs, cpu);
+ cpumask_set_cpu(cpu, &cpus_in_crash);
+
+ while (!atomic_read(&kexec_ready_to_reboot))
+ cpu_relax();
+
+ kexec_reboot();
+}
+
+void crash_smp_send_stop(void)
+{
+ static int cpus_stopped;
+ unsigned long timeout;
+ unsigned int ncpus;
+
+ /*
+ * This function can be called twice in panic path, but obviously
+ * we execute this only once.
+ */
+ if (cpus_stopped)
+ return;
+
+ cpus_stopped = 1;
+
+ /* Excluding the panic cpu */
+ ncpus = num_online_cpus() - 1;
+
+ smp_call_function(crash_shutdown_secondary, NULL, 0);
+ smp_wmb();
+
+ /*
+ * The crash CPU sends an IPI and wait for other CPUs to
+ * respond. Delay of at least 10 seconds.
+ */
+ pr_emerg("Sending IPI to other cpus...\n");
+ timeout = USEC_PER_SEC * 10;
+ while ((cpumask_weight(&cpus_in_crash) < ncpus) && timeout--) {
+ cpu_relax();
+ udelay(1);
+ }
+}
+#endif /* defined(CONFIG_SMP) */
void machine_crash_shutdown(struct pt_regs *regs)
{
+ int crashing_cpu;
+
+ local_irq_disable();
+
+ crashing_cpu = smp_processor_id();
+ crash_save_cpu(regs, crashing_cpu);
+
+#ifdef CONFIG_SMP
+ /* shutdown non-crashing cpus */
+ crash_smp_send_stop();
+#endif
+ cpumask_set_cpu(crashing_cpu, &cpus_in_crash);
+
+ pr_info("Starting crashdump kernel...\n");
}
void machine_shutdown(void)
@@ -173,7 +258,8 @@ void machine_kexec(struct kimage *image)
jump_addr = (unsigned long)phys_to_virt(image->start);
- first_ind_entry = (unsigned long)phys_to_virt(image->head & PAGE_MASK);
+ if (image->type == KEXEC_TYPE_DEFAULT)
+ first_ind_entry = (unsigned long)phys_to_virt(image->head & PAGE_MASK);
/*
* The generic kexec code builds a page list with physical
diff --git a/arch/loongarch/kernel/mem.c b/arch/loongarch/kernel/mem.c
index 7423361b0ebc..c6def6ff81c8 100644
--- a/arch/loongarch/kernel/mem.c
+++ b/arch/loongarch/kernel/mem.c
@@ -5,6 +5,7 @@
#include <linux/efi.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
+#include <linux/of_fdt.h>
#include <asm/bootinfo.h>
#include <asm/loongson.h>
@@ -61,4 +62,9 @@ void __init memblock_init(void)
/* Reserve the initrd */
reserve_initrd_mem();
+
+ /* Mainly reserved memory for the elf core head */
+ early_init_fdt_scan_reserved_mem();
+ /* Parse linux,usable-memory-range is for crash dump kernel */
+ early_init_dt_check_for_usable_mem_range();
}
diff --git a/arch/loongarch/kernel/relocate_kernel.S b/arch/loongarch/kernel/relocate_kernel.S
index 0ea8b29242e6..a4176f2ae402 100644
--- a/arch/loongarch/kernel/relocate_kernel.S
+++ b/arch/loongarch/kernel/relocate_kernel.S
@@ -24,6 +24,12 @@ SYM_CODE_START(relocate_new_kernel)
move s0, a3
+ /*
+ * In case of a kdump/crash kernel, the indirection page is not
+ * populated as the kernel is directly copied to a reserved location
+ */
+ beqz s0, done
+
process_entry:
PTR_L s1, s0, 0
PTR_ADDI s0, s0, SZREG
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 058c232c11e8..6974b88446a8 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -19,6 +19,8 @@
#include <linux/memblock.h>
#include <linux/initrd.h>
#include <linux/ioport.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
#include <linux/root_dev.h>
#include <linux/console.h>
#include <linux/pfn.h>
@@ -185,6 +187,50 @@ static int __init early_parse_mem(char *p)
}
early_param("mem", early_parse_mem);
+static void __init loongarch_parse_crashkernel(void)
+{
+#ifdef CONFIG_KEXEC
+ unsigned long long start;
+ unsigned long long total_mem;
+ unsigned long long crash_size, crash_base;
+ int ret;
+
+ total_mem = memblock_phys_mem_size();
+ ret = parse_crashkernel(boot_command_line, total_mem,
+ &crash_size, &crash_base);
+ if (ret != 0 || crash_size <= 0)
+ return;
+
+
+ start = memblock_phys_alloc_range(crash_size, 1, crash_base,
+ crash_base + crash_size);
+ if (start != crash_base) {
+ pr_warn("Invalid memory region reserved for crash kernel\n");
+ return;
+ }
+
+ crashk_res.start = crash_base;
+ crashk_res.end = crash_base + crash_size - 1;
+#endif
+}
+
+static void __init request_crashkernel(struct resource *res)
+{
+#ifdef CONFIG_KEXEC
+ int ret;
+
+ if (crashk_res.start == crashk_res.end)
+ return;
+
+ ret = request_resource(res, &crashk_res);
+ if (!ret)
+ pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
+ (unsigned long)((crashk_res.end -
+ crashk_res.start + 1) >> 20),
+ (unsigned long)(crashk_res.start >> 20));
+#endif
+}
+
void __init platform_init(void)
{
efi_init();
@@ -228,6 +274,8 @@ static void __init arch_mem_init(char **cmdline_p)
check_kernel_sections_mem();
+ loongarch_parse_crashkernel();
+
/*
* In order to reduce the possibility of kernel panic when failed to
* get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
@@ -289,6 +337,7 @@ static void __init resource_init(void)
request_resource(res, &code_resource);
request_resource(res, &data_resource);
request_resource(res, &bss_resource);
+ request_crashkernel(res);
}
}
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index aa1c95aaf595..0e610872f3f4 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -10,6 +10,7 @@
#include <linux/entry-common.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/extable.h>
#include <linux/mm.h>
@@ -246,6 +247,9 @@ void __noreturn die(const char *str, struct pt_regs *regs)
oops_exit();
+ if (regs && kexec_should_crash(current))
+ crash_kexec(regs);
+
if (in_interrupt())
panic("Fatal exception in interrupt");
--
2.36.0
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v3 3/3] LoongArch: Enable CONFIG_KEXEC
2022-09-15 2:53 [PATCH v3 0/3] LoongArch: Add kexec/kdump support Youling Tang
2022-09-15 2:53 ` [PATCH v3 1/3] LoongArch: Add kexec support Youling Tang
2022-09-15 2:53 ` [PATCH v3 2/3] LoongArch: Add kdump support Youling Tang
@ 2022-09-15 2:53 ` Youling Tang
2 siblings, 0 replies; 6+ messages in thread
From: Youling Tang @ 2022-09-15 2:53 UTC (permalink / raw)
To: Huacai Chen, Baoquan He, Eric Biederman
Cc: WANG Xuerui, Vivek Goyal, Dave Young, Guo Ren, Jiaxun Yang, kexec,
loongarch, linux-kernel
Defaults enable CONFIG_KEXEC to convenient kexec operations.
Signed-off-by: Youling Tang <tangyouling@loongson.cn>
---
arch/loongarch/configs/loongson3_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig
index 573f7a41f735..1ae85e797858 100644
--- a/arch/loongarch/configs/loongson3_defconfig
+++ b/arch/loongarch/configs/loongson3_defconfig
@@ -46,6 +46,7 @@ CONFIG_SMP=y
CONFIG_HOTPLUG_CPU=y
CONFIG_NR_CPUS=64
CONFIG_NUMA=y
+CONFIG_KEXEC=y
CONFIG_PAGE_SIZE_16KB=y
CONFIG_HZ_250=y
CONFIG_ACPI=y
--
2.36.0
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
^ permalink raw reply related [flat|nested] 6+ messages in thread