Message ID | 159371966340.21555.11937124937064648539.stgit@hbathini.in.ibm.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | ppc64: enable kdump support for kexec_file_load syscall | expand |
Le 02/07/2020 à 21:54, Hari Bathini a écrit : > Some of the kexec_file_load code isn't PPC64 specific. Move PPC64 > specific code from kexec/file_load.c to kexec/file_load_64.c. Also, > rename purgatory/trampoline.S to purgatory/trampoline_64.S in the > same spirit. FWIW and despite a minor comment below, Reviewed-by: Laurent Dufour <ldufour@linux.ibm.com> > Signed-off-by: Hari Bathini <hbathini@linux.ibm.com> > --- > > Changes in v2: > * No changes. > > > arch/powerpc/include/asm/kexec.h | 11 +++ > arch/powerpc/kexec/Makefile | 2 - > arch/powerpc/kexec/elf_64.c | 7 +- > arch/powerpc/kexec/file_load.c | 37 ++-------- > arch/powerpc/kexec/file_load_64.c | 108 ++++++++++++++++++++++++++++++ > arch/powerpc/purgatory/Makefile | 4 + > arch/powerpc/purgatory/trampoline.S | 117 -------------------------------- > arch/powerpc/purgatory/trampoline_64.S | 117 ++++++++++++++++++++++++++++++++ > 8 files changed, 248 insertions(+), 155 deletions(-) > create mode 100644 arch/powerpc/kexec/file_load_64.c > delete mode 100644 arch/powerpc/purgatory/trampoline.S > create mode 100644 arch/powerpc/purgatory/trampoline_64.S > > diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h > index c684768..7008ea1 100644 > --- a/arch/powerpc/include/asm/kexec.h > +++ b/arch/powerpc/include/asm/kexec.h > @@ -114,8 +114,17 @@ int setup_purgatory(struct kimage *image, const void *slave_code, > unsigned long fdt_load_addr); > int setup_new_fdt(const struct kimage *image, void *fdt, > unsigned long initrd_load_addr, unsigned long initrd_len, > - const char *cmdline); > + const char *cmdline, int *node); > int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size); > + > +#ifdef CONFIG_PPC64 > +int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, > + const void *fdt, unsigned long kernel_load_addr, > + unsigned long fdt_load_addr); > +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, > + unsigned long initrd_load_addr, > + unsigned long initrd_len, const char *cmdline); > +#endif /* CONFIG_PPC64 */ > #endif /* CONFIG_KEXEC_FILE */ > > #else /* !CONFIG_KEXEC_CORE */ > diff --git a/arch/powerpc/kexec/Makefile b/arch/powerpc/kexec/Makefile > index 86380c6..67c3553 100644 > --- a/arch/powerpc/kexec/Makefile > +++ b/arch/powerpc/kexec/Makefile > @@ -7,7 +7,7 @@ obj-y += core.o crash.o core_$(BITS).o > > obj-$(CONFIG_PPC32) += relocate_32.o > > -obj-$(CONFIG_KEXEC_FILE) += file_load.o elf_$(BITS).o > +obj-$(CONFIG_KEXEC_FILE) += file_load.o file_load_$(BITS).o elf_$(BITS).o > > ifdef CONFIG_HAVE_IMA_KEXEC > ifdef CONFIG_IMA > diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c > index 3072fd6..23ad04c 100644 > --- a/arch/powerpc/kexec/elf_64.c > +++ b/arch/powerpc/kexec/elf_64.c > @@ -88,7 +88,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, > goto out; > } > > - ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline); > + ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, > + initrd_len, cmdline); > if (ret) > goto out; > > @@ -107,8 +108,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, > pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); > > slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; > - ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, > - fdt_load_addr); > + ret = setup_purgatory_ppc64(image, slave_code, fdt, kernel_load_addr, > + fdt_load_addr); > if (ret) > pr_err("Error setting up the purgatory.\n"); > > diff --git a/arch/powerpc/kexec/file_load.c b/arch/powerpc/kexec/file_load.c > index 143c917..99a2c4d 100644 > --- a/arch/powerpc/kexec/file_load.c > +++ b/arch/powerpc/kexec/file_load.c > @@ -1,6 +1,6 @@ > // SPDX-License-Identifier: GPL-2.0-only > /* > - * ppc64 code to implement the kexec_file_load syscall > + * powerpc code to implement the kexec_file_load syscall > * > * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) > * Copyright (C) 2004 IBM Corp. > @@ -16,26 +16,10 @@ > > #include <linux/slab.h> > #include <linux/kexec.h> > -#include <linux/of_fdt.h> > #include <linux/libfdt.h> > #include <asm/ima.h> > > -#define SLAVE_CODE_SIZE 256 > - > -const struct kexec_file_ops * const kexec_file_loaders[] = { > - &kexec_elf64_ops, > - NULL > -}; > - > -int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, > - unsigned long buf_len) > -{ > - /* We don't support crash kernels yet. */ > - if (image->type == KEXEC_TYPE_CRASH) > - return -EOPNOTSUPP; > - > - return kexec_image_probe_default(image, buf, buf_len); > -} > +#define SLAVE_CODE_SIZE 256 /* First 0x100 bytes */ > > /** > * setup_purgatory - initialize the purgatory's global variables > @@ -127,24 +111,17 @@ int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size) > * @initrd_len: Size of the next initrd, or 0 if there will be none. > * @cmdline: Command line for the next kernel, or NULL if there will > * be none. > + * @chosen_node: Set this output parameter to chosen_node. minor: ^ seems to be "node" > * > * Return: 0 on success, or negative errno on error. > */ > int setup_new_fdt(const struct kimage *image, void *fdt, > unsigned long initrd_load_addr, unsigned long initrd_len, > - const char *cmdline) > + const char *cmdline, int *node) > { > int ret, chosen_node; > const void *prop; > > - /* Remove memory reservation for the current device tree. */ > - ret = delete_fdt_mem_rsv(fdt, __pa(initial_boot_params), > - fdt_totalsize(initial_boot_params)); > - if (ret == 0) > - pr_debug("Removed old device tree reservation.\n"); > - else if (ret != -ENOENT) > - return ret; > - > chosen_node = fdt_path_offset(fdt, "/chosen"); > if (chosen_node == -FDT_ERR_NOTFOUND) { > chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), > @@ -157,6 +134,8 @@ int setup_new_fdt(const struct kimage *image, void *fdt, > pr_err("Malformed device tree: error reading /chosen.\n"); > return -EINVAL; > } > + if (node) > + *node = chosen_node; > > /* Did we boot using an initrd? */ > prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL); > @@ -242,10 +221,6 @@ int setup_new_fdt(const struct kimage *image, void *fdt, > return ret; > } > > - ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); > - if (ret) > - goto err; > - > return 0; > > err: > diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c > new file mode 100644 > index 0000000..e6bff960 > --- /dev/null > +++ b/arch/powerpc/kexec/file_load_64.c > @@ -0,0 +1,108 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * ppc64 code to implement the kexec_file_load syscall > + * > + * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) > + * Copyright (C) 2004 IBM Corp. > + * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation > + * Copyright (C) 2005 R Sharada (sharada@in.ibm.com) > + * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com) > + * Copyright (C) 2020 IBM Corporation > + * > + * Based on kexec-tools' kexec-ppc64.c, kexec-elf-rel-ppc64.c, fs2dt.c. > + * Heavily modified for the kernel by > + * Hari Bathini <hbathini@linux.ibm.com>. > + */ > + > +#include <linux/kexec.h> > +#include <linux/of_fdt.h> > +#include <linux/libfdt.h> > + > +const struct kexec_file_ops * const kexec_file_loaders[] = { > + &kexec_elf64_ops, > + NULL > +}; > + > +/** > + * setup_purgatory_ppc64 - initialize PPC64 specific purgatory's global > + * variables and call setup_purgatory() to initialize > + * common global variable. > + * @image: kexec image. > + * @slave_code: Slave code for the purgatory. > + * @fdt: Flattened device tree for the next kernel. > + * @kernel_load_addr: Address where the kernel is loaded. > + * @fdt_load_addr: Address where the flattened device tree is loaded. > + * > + * Returns 0 on success, negative errno on error. > + */ > +int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, > + const void *fdt, unsigned long kernel_load_addr, > + unsigned long fdt_load_addr) > +{ > + int ret; > + > + ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, > + fdt_load_addr); > + if (ret) > + pr_err("Failed to setup purgatory symbols"); > + return ret; > +} > + > +/** > + * setup_new_fdt_ppc64 - Update the flattend device-tree of the kernel > + * being loaded. > + * @image: kexec image being loaded. > + * @fdt: Flattened device tree for the next kernel. > + * @initrd_load_addr: Address where the next initrd will be loaded. > + * @initrd_len: Size of the next initrd, or 0 if there will be none. > + * @cmdline: Command line for the next kernel, or NULL if there will > + * be none. > + * > + * Returns 0 on success, negative errno on error. > + */ > +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, > + unsigned long initrd_load_addr, > + unsigned long initrd_len, const char *cmdline) > +{ > + int chosen_node, ret; > + > + /* Remove memory reservation for the current device tree. */ > + ret = delete_fdt_mem_rsv(fdt, __pa(initial_boot_params), > + fdt_totalsize(initial_boot_params)); > + if (ret == 0) > + pr_debug("Removed old device tree reservation.\n"); > + else if (ret != -ENOENT) { > + pr_err("Failed to remove old device-tree reservation.\n"); > + return ret; > + } > + > + ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, > + cmdline, &chosen_node); > + if (ret) > + return ret; > + > + ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); > + if (ret) > + pr_err("Failed to update device-tree with linux,booted-from-kexec\n"); > + > + return ret; > +} > + > +/** > + * arch_kexec_kernel_image_probe - Does additional handling needed to setup > + * kexec segments. > + * @image: kexec image being loaded. > + * @buf: Buffer pointing to elf data. > + * @buf_len: Length of the buffer. > + * > + * Returns 0 on success, negative errno on error. > + */ > +int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, > + unsigned long buf_len) > +{ > + /* We don't support crash kernels yet. */ > + if (image->type == KEXEC_TYPE_CRASH) > + return -EOPNOTSUPP; > + > + return kexec_image_probe_default(image, buf, buf_len); > +} > diff --git a/arch/powerpc/purgatory/Makefile b/arch/powerpc/purgatory/Makefile > index 7c6d8b1..348f5958 100644 > --- a/arch/powerpc/purgatory/Makefile > +++ b/arch/powerpc/purgatory/Makefile > @@ -2,11 +2,11 @@ > > KASAN_SANITIZE := n > > -targets += trampoline.o purgatory.ro kexec-purgatory.c > +targets += trampoline_$(BITS).o purgatory.ro kexec-purgatory.c > > LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined > > -$(obj)/purgatory.ro: $(obj)/trampoline.o FORCE > +$(obj)/purgatory.ro: $(obj)/trampoline_$(BITS).o FORCE > $(call if_changed,ld) > > quiet_cmd_bin2c = BIN2C $@ > diff --git a/arch/powerpc/purgatory/trampoline.S b/arch/powerpc/purgatory/trampoline.S > deleted file mode 100644 > index a5a83c3..0000000 > --- a/arch/powerpc/purgatory/trampoline.S > +++ /dev/null > @@ -1,117 +0,0 @@ > -/* SPDX-License-Identifier: GPL-2.0-only */ > -/* > - * kexec trampoline > - * > - * Based on code taken from kexec-tools and kexec-lite. > - * > - * Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation > - * Copyright (C) 2006, Mohan Kumar M, IBM Corporation > - * Copyright (C) 2013, Anton Blanchard, IBM Corporation > - */ > - > -#include <asm/asm-compat.h> > - > - .machine ppc64 > - .balign 256 > - .globl purgatory_start > -purgatory_start: > - b master > - > - /* ABI: possible run_at_load flag at 0x5c */ > - .org purgatory_start + 0x5c > - .globl run_at_load > -run_at_load: > - .long 0 > - .size run_at_load, . - run_at_load > - > - /* ABI: slaves start at 60 with r3=phys */ > - .org purgatory_start + 0x60 > -slave: > - b . > - /* ABI: end of copied region */ > - .org purgatory_start + 0x100 > - .size purgatory_start, . - purgatory_start > - > -/* > - * The above 0x100 bytes at purgatory_start are replaced with the > - * code from the kernel (or next stage) by setup_purgatory(). > - */ > - > -master: > - or %r1,%r1,%r1 /* low priority to let other threads catchup */ > - isync > - mr %r17,%r3 /* save cpu id to r17 */ > - mr %r15,%r4 /* save physical address in reg15 */ > - > - or %r3,%r3,%r3 /* ok now to high priority, lets boot */ > - lis %r6,0x1 > - mtctr %r6 /* delay a bit for slaves to catch up */ > - bdnz . /* before we overwrite 0-100 again */ > - > - bl 0f /* Work out where we're running */ > -0: mflr %r18 > - > - /* load device-tree address */ > - ld %r3, (dt_offset - 0b)(%r18) > - mr %r16,%r3 /* save dt address in reg16 */ > - li %r4,20 > - LWZX_BE %r6,%r3,%r4 /* fetch __be32 version number at byte 20 */ > - cmpwi %cr0,%r6,2 /* v2 or later? */ > - blt 1f > - li %r4,28 > - STWX_BE %r17,%r3,%r4 /* Store my cpu as __be32 at byte 28 */ > -1: > - /* load the kernel address */ > - ld %r4,(kernel - 0b)(%r18) > - > - /* load the run_at_load flag */ > - /* possibly patched by kexec */ > - ld %r6,(run_at_load - 0b)(%r18) > - /* and patch it into the kernel */ > - stw %r6,(0x5c)(%r4) > - > - mr %r3,%r16 /* restore dt address */ > - > - li %r5,0 /* r5 will be 0 for kernel */ > - > - mfmsr %r11 > - andi. %r10,%r11,1 /* test MSR_LE */ > - bne .Little_endian > - > - mtctr %r4 /* prepare branch to */ > - bctr /* start kernel */ > - > -.Little_endian: > - mtsrr0 %r4 /* prepare branch to */ > - > - clrrdi %r11,%r11,1 /* clear MSR_LE */ > - mtsrr1 %r11 > - > - rfid /* update MSR and start kernel */ > - > - > - .balign 8 > - .globl kernel > -kernel: > - .8byte 0x0 > - .size kernel, . - kernel > - > - .balign 8 > - .globl dt_offset > -dt_offset: > - .8byte 0x0 > - .size dt_offset, . - dt_offset > - > - > - .data > - .balign 8 > -.globl purgatory_sha256_digest > -purgatory_sha256_digest: > - .skip 32 > - .size purgatory_sha256_digest, . - purgatory_sha256_digest > - > - .balign 8 > -.globl purgatory_sha_regions > -purgatory_sha_regions: > - .skip 8 * 2 * 16 > - .size purgatory_sha_regions, . - purgatory_sha_regions > diff --git a/arch/powerpc/purgatory/trampoline_64.S b/arch/powerpc/purgatory/trampoline_64.S > new file mode 100644 > index 0000000..a5a83c3 > --- /dev/null > +++ b/arch/powerpc/purgatory/trampoline_64.S > @@ -0,0 +1,117 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * kexec trampoline > + * > + * Based on code taken from kexec-tools and kexec-lite. > + * > + * Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation > + * Copyright (C) 2006, Mohan Kumar M, IBM Corporation > + * Copyright (C) 2013, Anton Blanchard, IBM Corporation > + */ > + > +#include <asm/asm-compat.h> > + > + .machine ppc64 > + .balign 256 > + .globl purgatory_start > +purgatory_start: > + b master > + > + /* ABI: possible run_at_load flag at 0x5c */ > + .org purgatory_start + 0x5c > + .globl run_at_load > +run_at_load: > + .long 0 > + .size run_at_load, . - run_at_load > + > + /* ABI: slaves start at 60 with r3=phys */ > + .org purgatory_start + 0x60 > +slave: > + b . > + /* ABI: end of copied region */ > + .org purgatory_start + 0x100 > + .size purgatory_start, . - purgatory_start > + > +/* > + * The above 0x100 bytes at purgatory_start are replaced with the > + * code from the kernel (or next stage) by setup_purgatory(). > + */ > + > +master: > + or %r1,%r1,%r1 /* low priority to let other threads catchup */ > + isync > + mr %r17,%r3 /* save cpu id to r17 */ > + mr %r15,%r4 /* save physical address in reg15 */ > + > + or %r3,%r3,%r3 /* ok now to high priority, lets boot */ > + lis %r6,0x1 > + mtctr %r6 /* delay a bit for slaves to catch up */ > + bdnz . /* before we overwrite 0-100 again */ > + > + bl 0f /* Work out where we're running */ > +0: mflr %r18 > + > + /* load device-tree address */ > + ld %r3, (dt_offset - 0b)(%r18) > + mr %r16,%r3 /* save dt address in reg16 */ > + li %r4,20 > + LWZX_BE %r6,%r3,%r4 /* fetch __be32 version number at byte 20 */ > + cmpwi %cr0,%r6,2 /* v2 or later? */ > + blt 1f > + li %r4,28 > + STWX_BE %r17,%r3,%r4 /* Store my cpu as __be32 at byte 28 */ > +1: > + /* load the kernel address */ > + ld %r4,(kernel - 0b)(%r18) > + > + /* load the run_at_load flag */ > + /* possibly patched by kexec */ > + ld %r6,(run_at_load - 0b)(%r18) > + /* and patch it into the kernel */ > + stw %r6,(0x5c)(%r4) > + > + mr %r3,%r16 /* restore dt address */ > + > + li %r5,0 /* r5 will be 0 for kernel */ > + > + mfmsr %r11 > + andi. %r10,%r11,1 /* test MSR_LE */ > + bne .Little_endian > + > + mtctr %r4 /* prepare branch to */ > + bctr /* start kernel */ > + > +.Little_endian: > + mtsrr0 %r4 /* prepare branch to */ > + > + clrrdi %r11,%r11,1 /* clear MSR_LE */ > + mtsrr1 %r11 > + > + rfid /* update MSR and start kernel */ > + > + > + .balign 8 > + .globl kernel > +kernel: > + .8byte 0x0 > + .size kernel, . - kernel > + > + .balign 8 > + .globl dt_offset > +dt_offset: > + .8byte 0x0 > + .size dt_offset, . - dt_offset > + > + > + .data > + .balign 8 > +.globl purgatory_sha256_digest > +purgatory_sha256_digest: > + .skip 32 > + .size purgatory_sha256_digest, . - purgatory_sha256_digest > + > + .balign 8 > +.globl purgatory_sha_regions > +purgatory_sha_regions: > + .skip 8 * 2 * 16 > + .size purgatory_sha_regions, . - purgatory_sha_regions >
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index c684768..7008ea1 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -114,8 +114,17 @@ int setup_purgatory(struct kimage *image, const void *slave_code, unsigned long fdt_load_addr); int setup_new_fdt(const struct kimage *image, void *fdt, unsigned long initrd_load_addr, unsigned long initrd_len, - const char *cmdline); + const char *cmdline, int *node); int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size); + +#ifdef CONFIG_PPC64 +int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, + const void *fdt, unsigned long kernel_load_addr, + unsigned long fdt_load_addr); +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, + unsigned long initrd_load_addr, + unsigned long initrd_len, const char *cmdline); +#endif /* CONFIG_PPC64 */ #endif /* CONFIG_KEXEC_FILE */ #else /* !CONFIG_KEXEC_CORE */ diff --git a/arch/powerpc/kexec/Makefile b/arch/powerpc/kexec/Makefile index 86380c6..67c3553 100644 --- a/arch/powerpc/kexec/Makefile +++ b/arch/powerpc/kexec/Makefile @@ -7,7 +7,7 @@ obj-y += core.o crash.o core_$(BITS).o obj-$(CONFIG_PPC32) += relocate_32.o -obj-$(CONFIG_KEXEC_FILE) += file_load.o elf_$(BITS).o +obj-$(CONFIG_KEXEC_FILE) += file_load.o file_load_$(BITS).o elf_$(BITS).o ifdef CONFIG_HAVE_IMA_KEXEC ifdef CONFIG_IMA diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c index 3072fd6..23ad04c 100644 --- a/arch/powerpc/kexec/elf_64.c +++ b/arch/powerpc/kexec/elf_64.c @@ -88,7 +88,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, goto out; } - ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline); + ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, + initrd_len, cmdline); if (ret) goto out; @@ -107,8 +108,8 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; - ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, - fdt_load_addr); + ret = setup_purgatory_ppc64(image, slave_code, fdt, kernel_load_addr, + fdt_load_addr); if (ret) pr_err("Error setting up the purgatory.\n"); diff --git a/arch/powerpc/kexec/file_load.c b/arch/powerpc/kexec/file_load.c index 143c917..99a2c4d 100644 --- a/arch/powerpc/kexec/file_load.c +++ b/arch/powerpc/kexec/file_load.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * ppc64 code to implement the kexec_file_load syscall + * powerpc code to implement the kexec_file_load syscall * * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) * Copyright (C) 2004 IBM Corp. @@ -16,26 +16,10 @@ #include <linux/slab.h> #include <linux/kexec.h> -#include <linux/of_fdt.h> #include <linux/libfdt.h> #include <asm/ima.h> -#define SLAVE_CODE_SIZE 256 - -const struct kexec_file_ops * const kexec_file_loaders[] = { - &kexec_elf64_ops, - NULL -}; - -int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, - unsigned long buf_len) -{ - /* We don't support crash kernels yet. */ - if (image->type == KEXEC_TYPE_CRASH) - return -EOPNOTSUPP; - - return kexec_image_probe_default(image, buf, buf_len); -} +#define SLAVE_CODE_SIZE 256 /* First 0x100 bytes */ /** * setup_purgatory - initialize the purgatory's global variables @@ -127,24 +111,17 @@ int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size) * @initrd_len: Size of the next initrd, or 0 if there will be none. * @cmdline: Command line for the next kernel, or NULL if there will * be none. + * @chosen_node: Set this output parameter to chosen_node. * * Return: 0 on success, or negative errno on error. */ int setup_new_fdt(const struct kimage *image, void *fdt, unsigned long initrd_load_addr, unsigned long initrd_len, - const char *cmdline) + const char *cmdline, int *node) { int ret, chosen_node; const void *prop; - /* Remove memory reservation for the current device tree. */ - ret = delete_fdt_mem_rsv(fdt, __pa(initial_boot_params), - fdt_totalsize(initial_boot_params)); - if (ret == 0) - pr_debug("Removed old device tree reservation.\n"); - else if (ret != -ENOENT) - return ret; - chosen_node = fdt_path_offset(fdt, "/chosen"); if (chosen_node == -FDT_ERR_NOTFOUND) { chosen_node = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), @@ -157,6 +134,8 @@ int setup_new_fdt(const struct kimage *image, void *fdt, pr_err("Malformed device tree: error reading /chosen.\n"); return -EINVAL; } + if (node) + *node = chosen_node; /* Did we boot using an initrd? */ prop = fdt_getprop(fdt, chosen_node, "linux,initrd-start", NULL); @@ -242,10 +221,6 @@ int setup_new_fdt(const struct kimage *image, void *fdt, return ret; } - ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); - if (ret) - goto err; - return 0; err: diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c new file mode 100644 index 0000000..e6bff960 --- /dev/null +++ b/arch/powerpc/kexec/file_load_64.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ppc64 code to implement the kexec_file_load syscall + * + * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) + * Copyright (C) 2004 IBM Corp. + * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation + * Copyright (C) 2005 R Sharada (sharada@in.ibm.com) + * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com) + * Copyright (C) 2020 IBM Corporation + * + * Based on kexec-tools' kexec-ppc64.c, kexec-elf-rel-ppc64.c, fs2dt.c. + * Heavily modified for the kernel by + * Hari Bathini <hbathini@linux.ibm.com>. + */ + +#include <linux/kexec.h> +#include <linux/of_fdt.h> +#include <linux/libfdt.h> + +const struct kexec_file_ops * const kexec_file_loaders[] = { + &kexec_elf64_ops, + NULL +}; + +/** + * setup_purgatory_ppc64 - initialize PPC64 specific purgatory's global + * variables and call setup_purgatory() to initialize + * common global variable. + * @image: kexec image. + * @slave_code: Slave code for the purgatory. + * @fdt: Flattened device tree for the next kernel. + * @kernel_load_addr: Address where the kernel is loaded. + * @fdt_load_addr: Address where the flattened device tree is loaded. + * + * Returns 0 on success, negative errno on error. + */ +int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, + const void *fdt, unsigned long kernel_load_addr, + unsigned long fdt_load_addr) +{ + int ret; + + ret = setup_purgatory(image, slave_code, fdt, kernel_load_addr, + fdt_load_addr); + if (ret) + pr_err("Failed to setup purgatory symbols"); + return ret; +} + +/** + * setup_new_fdt_ppc64 - Update the flattend device-tree of the kernel + * being loaded. + * @image: kexec image being loaded. + * @fdt: Flattened device tree for the next kernel. + * @initrd_load_addr: Address where the next initrd will be loaded. + * @initrd_len: Size of the next initrd, or 0 if there will be none. + * @cmdline: Command line for the next kernel, or NULL if there will + * be none. + * + * Returns 0 on success, negative errno on error. + */ +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, + unsigned long initrd_load_addr, + unsigned long initrd_len, const char *cmdline) +{ + int chosen_node, ret; + + /* Remove memory reservation for the current device tree. */ + ret = delete_fdt_mem_rsv(fdt, __pa(initial_boot_params), + fdt_totalsize(initial_boot_params)); + if (ret == 0) + pr_debug("Removed old device tree reservation.\n"); + else if (ret != -ENOENT) { + pr_err("Failed to remove old device-tree reservation.\n"); + return ret; + } + + ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, + cmdline, &chosen_node); + if (ret) + return ret; + + ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0); + if (ret) + pr_err("Failed to update device-tree with linux,booted-from-kexec\n"); + + return ret; +} + +/** + * arch_kexec_kernel_image_probe - Does additional handling needed to setup + * kexec segments. + * @image: kexec image being loaded. + * @buf: Buffer pointing to elf data. + * @buf_len: Length of the buffer. + * + * Returns 0 on success, negative errno on error. + */ +int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, + unsigned long buf_len) +{ + /* We don't support crash kernels yet. */ + if (image->type == KEXEC_TYPE_CRASH) + return -EOPNOTSUPP; + + return kexec_image_probe_default(image, buf, buf_len); +} diff --git a/arch/powerpc/purgatory/Makefile b/arch/powerpc/purgatory/Makefile index 7c6d8b1..348f5958 100644 --- a/arch/powerpc/purgatory/Makefile +++ b/arch/powerpc/purgatory/Makefile @@ -2,11 +2,11 @@ KASAN_SANITIZE := n -targets += trampoline.o purgatory.ro kexec-purgatory.c +targets += trampoline_$(BITS).o purgatory.ro kexec-purgatory.c LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -$(obj)/purgatory.ro: $(obj)/trampoline.o FORCE +$(obj)/purgatory.ro: $(obj)/trampoline_$(BITS).o FORCE $(call if_changed,ld) quiet_cmd_bin2c = BIN2C $@ diff --git a/arch/powerpc/purgatory/trampoline.S b/arch/powerpc/purgatory/trampoline.S deleted file mode 100644 index a5a83c3..0000000 --- a/arch/powerpc/purgatory/trampoline.S +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * kexec trampoline - * - * Based on code taken from kexec-tools and kexec-lite. - * - * Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation - * Copyright (C) 2006, Mohan Kumar M, IBM Corporation - * Copyright (C) 2013, Anton Blanchard, IBM Corporation - */ - -#include <asm/asm-compat.h> - - .machine ppc64 - .balign 256 - .globl purgatory_start -purgatory_start: - b master - - /* ABI: possible run_at_load flag at 0x5c */ - .org purgatory_start + 0x5c - .globl run_at_load -run_at_load: - .long 0 - .size run_at_load, . - run_at_load - - /* ABI: slaves start at 60 with r3=phys */ - .org purgatory_start + 0x60 -slave: - b . - /* ABI: end of copied region */ - .org purgatory_start + 0x100 - .size purgatory_start, . - purgatory_start - -/* - * The above 0x100 bytes at purgatory_start are replaced with the - * code from the kernel (or next stage) by setup_purgatory(). - */ - -master: - or %r1,%r1,%r1 /* low priority to let other threads catchup */ - isync - mr %r17,%r3 /* save cpu id to r17 */ - mr %r15,%r4 /* save physical address in reg15 */ - - or %r3,%r3,%r3 /* ok now to high priority, lets boot */ - lis %r6,0x1 - mtctr %r6 /* delay a bit for slaves to catch up */ - bdnz . /* before we overwrite 0-100 again */ - - bl 0f /* Work out where we're running */ -0: mflr %r18 - - /* load device-tree address */ - ld %r3, (dt_offset - 0b)(%r18) - mr %r16,%r3 /* save dt address in reg16 */ - li %r4,20 - LWZX_BE %r6,%r3,%r4 /* fetch __be32 version number at byte 20 */ - cmpwi %cr0,%r6,2 /* v2 or later? */ - blt 1f - li %r4,28 - STWX_BE %r17,%r3,%r4 /* Store my cpu as __be32 at byte 28 */ -1: - /* load the kernel address */ - ld %r4,(kernel - 0b)(%r18) - - /* load the run_at_load flag */ - /* possibly patched by kexec */ - ld %r6,(run_at_load - 0b)(%r18) - /* and patch it into the kernel */ - stw %r6,(0x5c)(%r4) - - mr %r3,%r16 /* restore dt address */ - - li %r5,0 /* r5 will be 0 for kernel */ - - mfmsr %r11 - andi. %r10,%r11,1 /* test MSR_LE */ - bne .Little_endian - - mtctr %r4 /* prepare branch to */ - bctr /* start kernel */ - -.Little_endian: - mtsrr0 %r4 /* prepare branch to */ - - clrrdi %r11,%r11,1 /* clear MSR_LE */ - mtsrr1 %r11 - - rfid /* update MSR and start kernel */ - - - .balign 8 - .globl kernel -kernel: - .8byte 0x0 - .size kernel, . - kernel - - .balign 8 - .globl dt_offset -dt_offset: - .8byte 0x0 - .size dt_offset, . - dt_offset - - - .data - .balign 8 -.globl purgatory_sha256_digest -purgatory_sha256_digest: - .skip 32 - .size purgatory_sha256_digest, . - purgatory_sha256_digest - - .balign 8 -.globl purgatory_sha_regions -purgatory_sha_regions: - .skip 8 * 2 * 16 - .size purgatory_sha_regions, . - purgatory_sha_regions diff --git a/arch/powerpc/purgatory/trampoline_64.S b/arch/powerpc/purgatory/trampoline_64.S new file mode 100644 index 0000000..a5a83c3 --- /dev/null +++ b/arch/powerpc/purgatory/trampoline_64.S @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * kexec trampoline + * + * Based on code taken from kexec-tools and kexec-lite. + * + * Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation + * Copyright (C) 2006, Mohan Kumar M, IBM Corporation + * Copyright (C) 2013, Anton Blanchard, IBM Corporation + */ + +#include <asm/asm-compat.h> + + .machine ppc64 + .balign 256 + .globl purgatory_start +purgatory_start: + b master + + /* ABI: possible run_at_load flag at 0x5c */ + .org purgatory_start + 0x5c + .globl run_at_load +run_at_load: + .long 0 + .size run_at_load, . - run_at_load + + /* ABI: slaves start at 60 with r3=phys */ + .org purgatory_start + 0x60 +slave: + b . + /* ABI: end of copied region */ + .org purgatory_start + 0x100 + .size purgatory_start, . - purgatory_start + +/* + * The above 0x100 bytes at purgatory_start are replaced with the + * code from the kernel (or next stage) by setup_purgatory(). + */ + +master: + or %r1,%r1,%r1 /* low priority to let other threads catchup */ + isync + mr %r17,%r3 /* save cpu id to r17 */ + mr %r15,%r4 /* save physical address in reg15 */ + + or %r3,%r3,%r3 /* ok now to high priority, lets boot */ + lis %r6,0x1 + mtctr %r6 /* delay a bit for slaves to catch up */ + bdnz . /* before we overwrite 0-100 again */ + + bl 0f /* Work out where we're running */ +0: mflr %r18 + + /* load device-tree address */ + ld %r3, (dt_offset - 0b)(%r18) + mr %r16,%r3 /* save dt address in reg16 */ + li %r4,20 + LWZX_BE %r6,%r3,%r4 /* fetch __be32 version number at byte 20 */ + cmpwi %cr0,%r6,2 /* v2 or later? */ + blt 1f + li %r4,28 + STWX_BE %r17,%r3,%r4 /* Store my cpu as __be32 at byte 28 */ +1: + /* load the kernel address */ + ld %r4,(kernel - 0b)(%r18) + + /* load the run_at_load flag */ + /* possibly patched by kexec */ + ld %r6,(run_at_load - 0b)(%r18) + /* and patch it into the kernel */ + stw %r6,(0x5c)(%r4) + + mr %r3,%r16 /* restore dt address */ + + li %r5,0 /* r5 will be 0 for kernel */ + + mfmsr %r11 + andi. %r10,%r11,1 /* test MSR_LE */ + bne .Little_endian + + mtctr %r4 /* prepare branch to */ + bctr /* start kernel */ + +.Little_endian: + mtsrr0 %r4 /* prepare branch to */ + + clrrdi %r11,%r11,1 /* clear MSR_LE */ + mtsrr1 %r11 + + rfid /* update MSR and start kernel */ + + + .balign 8 + .globl kernel +kernel: + .8byte 0x0 + .size kernel, . - kernel + + .balign 8 + .globl dt_offset +dt_offset: + .8byte 0x0 + .size dt_offset, . - dt_offset + + + .data + .balign 8 +.globl purgatory_sha256_digest +purgatory_sha256_digest: + .skip 32 + .size purgatory_sha256_digest, . - purgatory_sha256_digest + + .balign 8 +.globl purgatory_sha_regions +purgatory_sha_regions: + .skip 8 * 2 * 16 + .size purgatory_sha_regions, . - purgatory_sha_regions
Some of the kexec_file_load code isn't PPC64 specific. Move PPC64 specific code from kexec/file_load.c to kexec/file_load_64.c. Also, rename purgatory/trampoline.S to purgatory/trampoline_64.S in the same spirit. Signed-off-by: Hari Bathini <hbathini@linux.ibm.com> --- Changes in v2: * No changes. arch/powerpc/include/asm/kexec.h | 11 +++ arch/powerpc/kexec/Makefile | 2 - arch/powerpc/kexec/elf_64.c | 7 +- arch/powerpc/kexec/file_load.c | 37 ++-------- arch/powerpc/kexec/file_load_64.c | 108 ++++++++++++++++++++++++++++++ arch/powerpc/purgatory/Makefile | 4 + arch/powerpc/purgatory/trampoline.S | 117 -------------------------------- arch/powerpc/purgatory/trampoline_64.S | 117 ++++++++++++++++++++++++++++++++ 8 files changed, 248 insertions(+), 155 deletions(-) create mode 100644 arch/powerpc/kexec/file_load_64.c delete mode 100644 arch/powerpc/purgatory/trampoline.S create mode 100644 arch/powerpc/purgatory/trampoline_64.S