Messages in this thread | | | Subject | Re: [PATCH 1/3] LoongArch: Add kexec support | From | Youling Tang <> | Date | Mon, 5 Sep 2022 09:01:06 +0800 |
| |
On 08/29/2022 12:37 PM, Youling Tang wrote: > 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 | 7 +- > arch/loongarch/kernel/machine_kexec.c | 178 ++++++++++++++++++++++++ > arch/loongarch/kernel/relocate_kernel.S | 125 +++++++++++++++++ > 6 files changed, 380 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 45364cffc793..903c82fa958d 100644 > --- a/arch/loongarch/Kconfig > +++ b/arch/loongarch/Kconfig > @@ -409,6 +409,17 @@ config FORCE_MAX_ZONEORDER > The page size is not necessarily 4KB. Keep this in mind > when choosing a value for this option. > > +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..5c9e7b5eccb8 > --- /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 boot_flag; > + unsigned long fdt_addr; > +}; > + > +typedef void (*do_kexec_t)(unsigned long boot_flag, > + unsigned long fdt_addr, > + unsigned long first_ind_entry, > + unsigned long jump_addr); > + > +struct kimage; > +extern const unsigned char relocate_new_kernel[]; > +extern const size_t relocate_new_kernel_size; > + > +#ifdef CONFIG_SMP > +extern atomic_t kexec_ready_to_reboot; > +extern const unsigned char kexec_smp_wait[]; > +extern void kexec_reboot(void); > +#endif > + > +#endif /* !_ASM_KEXEC_H */ > diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile > index a213e994db68..20b64ac3f128 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 01bac62a6442..22bdf4928325 100644 > --- a/arch/loongarch/kernel/head.S > +++ b/arch/loongarch/kernel/head.S > @@ -20,7 +20,12 @@ > > _head: > .word MZ_MAGIC /* "MZ", MS-DOS header */ > - .org 0x3c /* 0x04 ~ 0x3b reserved */ > + .org 0x8 > + .quad 0 /* Image load offset from start of RAM */ > + .dword _end - _text /* Effective size of kernel image */ > + .quad 0 > + .dword kernel_entry /* Kernel entry point */ > + .org 0x3c /* 0x28 ~ 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..4ffcd4cd9c8c > --- /dev/null > +++ b/arch/loongarch/kernel/machine_kexec.c > @@ -0,0 +1,178 @@ > +// 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 > +void (*relocated_kexec_smp_wait)(void *); > +atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); > +#endif > + > +static unsigned long jump_addr; > +static unsigned long first_ind_entry; > +static unsigned long boot_flag; > +static unsigned long fdt_addr; > + > +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.boot_flag = 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); > + > + /* 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); > + > + return 0; > +} > + > +void machine_kexec_cleanup(struct kimage *kimage) > +{ > +} > + > +#ifdef CONFIG_SMP > +void kexec_reboot(void) > +{ > + do_kexec_t do_kexec = NULL; > + > + /* All secondary cpus go to kexec_smp_wait */ > + if (smp_processor_id() > 0) { > + relocated_kexec_smp_wait(NULL); > + unreachable(); > + } > + > + do_kexec = (void *)reboot_code_buffer; > + do_kexec(boot_flag, fdt_addr, first_ind_entry, jump_addr); > + > + unreachable(); > +}
self-check, kexec_reboot() is in! SMP needs to be used, modified as follows:
void kexec_reboot(void) { do_kexec_t do_kexec = NULL;
#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(boot_flag, fdt_addr, first_ind_entry, jump_addr);
unreachable(); }
Youling
| |