From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2646FC433FE for ; Fri, 8 Apr 2022 10:10:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234453AbiDHKMh (ORCPT ); Fri, 8 Apr 2022 06:12:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58006 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233738AbiDHKMM (ORCPT ); Fri, 8 Apr 2022 06:12:12 -0400 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D9C2A58E6D for ; Fri, 8 Apr 2022 03:10:08 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.53]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4KZYmK4QSrzBsCF; Fri, 8 Apr 2022 18:05:53 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:05 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 1/6] kexec_file: Fix kexec_file.c build error for riscv platform Date: Fri, 8 Apr 2022 18:09:09 +0800 Message-ID: <20220408100914.150110-2-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Liao Chang When CONFIG_KEXEC_FILE is set for riscv platform, the compilation of kernel/kexec_file.c generate build error: kernel/kexec_file.c: In function 'crash_prepare_elf64_headers': ./arch/riscv/include/asm/page.h:110:71: error: request for member 'virt_add= r' in something not a structure or union 110 | ((x) >=3D PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < kerne= l_map.virt_addr)) | = ^ ./arch/riscv/include/asm/page.h:131:2: note: in expansion of macro 'is_line= ar_mapping' 131 | is_linear_mapping(_x) ? \ | ^~~~~~~~~~~~~~~~~ ./arch/riscv/include/asm/page.h:140:31: note: in expansion of macro '__va_t= o_pa_nodebug' 140 | #define __phys_addr_symbol(x) __va_to_pa_nodebug(x) | ^~~~~~~~~~~~~~~~~~ ./arch/riscv/include/asm/page.h:143:24: note: in expansion of macro '__phys= _addr_symbol' 143 | #define __pa_symbol(x) __phys_addr_symbol(RELOC_HIDE((unsigned long= )(x), 0)) | ^~~~~~~~~~~~~~~~~~ kernel/kexec_file.c:1327:36: note: in expansion of macro '__pa_symbol' 1327 | phdr->p_offset =3D phdr->p_paddr =3D __pa_symbol(_text); This occurs is because the "kernel_map" referenced in macro is_linear_mapping() is suppose to be the one of struct kernel_mapping defined in arch/riscv/mm/init.c, but the 2nd argument of crash_prepare_elf64_header() has same symbol name, in expansion of macro is_linear_mapping in function crash_prepare_elf64_header(), "kernel_map" actually is the local variable. Signed-off-by: Liao Chang --- include/linux/kexec.h | 2 +- kernel/kexec_file.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 58d1b58a971e..ebb1bffbf068 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -227,7 +227,7 @@ struct crash_mem { extern int crash_exclude_mem_range(struct crash_mem *mem, unsigned long long mstart, unsigned long long mend); -extern int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_m= ap, +extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_ker= nel_map, void **addr, unsigned long *sz); #endif /* CONFIG_KEXEC_FILE */ =20 diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 8347fc158d2b..331a4f0f10f5 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -1260,7 +1260,7 @@ int crash_exclude_mem_range(struct crash_mem *mem, return 0; } =20 -int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map, +int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map, void **addr, unsigned long *sz) { Elf64_Ehdr *ehdr; @@ -1324,7 +1324,7 @@ int crash_prepare_elf64_headers(struct crash_mem *mem= , int kernel_map, phdr++; =20 /* Prepare PT_LOAD type program header for kernel text region */ - if (kernel_map) { + if (need_kernel_map) { phdr->p_type =3D PT_LOAD; phdr->p_flags =3D PF_R|PF_W|PF_X; phdr->p_vaddr =3D (unsigned long) _text; --=20 2.17.1 From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E12CC433EF for ; Fri, 8 Apr 2022 10:12:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234286AbiDHKMa (ORCPT ); Fri, 8 Apr 2022 06:12:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57976 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232467AbiDHKMM (ORCPT ); Fri, 8 Apr 2022 06:12:12 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD1D9A997B for ; Fri, 8 Apr 2022 03:10:08 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4KZYpV2GTBzFpXh; Fri, 8 Apr 2022 18:07:46 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:06 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 2/6] RISC-V: use memcpy for kexec_file mode Date: Fri, 8 Apr 2022 18:09:10 +0800 Message-ID: <20220408100914.150110-3-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Liao Chang The pointer to buffer loading kernel binaries is in kernel space for kexec_fil mode, When copy_from_user copies data from pointer to a block of memory, it checkes that the pointer is in the user space range, on RISCV-V that is: static inline bool __access_ok(unsigned long addr, unsigned long size) { return size <=3D TASK_SIZE && addr <=3D TASK_SIZE - size; } and TASK_SIZE is 0x4000000000 for 64-bits, which now causes copy_from_user to reject the access of the field 'buf' of struct kexec_segment that is in range [CONFIG_PAGE_OFFSET - VMALLOC_SIZE, CONFIG_PAGE_OFFSET), is invalid user space pointer. This patch fixes this issue by skipping access_ok(), use mempcy() instead. Signed-off-by: Liao Chang --- arch/riscv/kernel/machine_kexec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_= kexec.c index cbef0fc73afa..df8e24559035 100644 --- a/arch/riscv/kernel/machine_kexec.c +++ b/arch/riscv/kernel/machine_kexec.c @@ -65,7 +65,9 @@ machine_kexec_prepare(struct kimage *image) if (image->segment[i].memsz <=3D sizeof(fdt)) continue; =20 - if (copy_from_user(&fdt, image->segment[i].buf, sizeof(fdt))) + if (image->file_mode) + memcpy(&fdt, image->segment[i].buf, sizeof(fdt)); + else if (copy_from_user(&fdt, image->segment[i].buf, sizeof(fdt))) continue; =20 if (fdt_check_header(&fdt)) --=20 2.17.1 From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AE717C433F5 for ; Fri, 8 Apr 2022 10:10:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234384AbiDHKMd (ORCPT ); Fri, 8 Apr 2022 06:12:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58054 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233799AbiDHKMM (ORCPT ); Fri, 8 Apr 2022 06:12:12 -0400 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 69CA7AA023 for ; Fri, 8 Apr 2022 03:10:09 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.57]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4KZYqB0DzSzgYXn; Fri, 8 Apr 2022 18:08:22 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:06 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 3/6] RISC-V: Add kexec_file support Date: Fri, 8 Apr 2022 18:09:11 +0800 Message-ID: <20220408100914.150110-4-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Liao Chang This patch adds support for kexec_file on RISC-V. I tested it on riscv64 QEMU with busybear-linux and single core along with the OpenSBI firmware fw_jump.bin for generic platform. On SMP system, it depends on CONFIG_{HOTPLUG_CPU, RISCV_SBI} to resume/stop hart through OpenSBI firmware, it also needs a OpenSBI that support the HSM extension. Signed-off-by: Liao Chang Signed-off-by: Li Zhengyu --- arch/riscv/Kconfig | 11 ++ arch/riscv/include/asm/kexec.h | 4 + arch/riscv/kernel/Makefile | 1 + arch/riscv/kernel/elf_kexec.c | 180 +++++++++++++++++++++++++ arch/riscv/kernel/machine_kexec_file.c | 14 ++ 5 files changed, 210 insertions(+) create mode 100644 arch/riscv/kernel/elf_kexec.c create mode 100644 arch/riscv/kernel/machine_kexec_file.c diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 00fd9c548f26..e95e4c390514 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -383,6 +383,17 @@ config KEXEC =20 The name comes from the similarity to the exec system call. =20 +config KEXEC_FILE + bool "kexec file based systmem call" + select KEXEC_CORE + select KEXEC_ELF + select HAVE_IMA_KEXEC if IMA + help + This is new version of kexec system call. This system call is + file based and takes file descriptors as system call argument + for kernel and initramfs as opposed to list of segments as + accepted by previous system call. + config CRASH_DUMP bool "Build kdump crash kernel" help diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h index e4e291d40759..206217b23301 100644 --- a/arch/riscv/include/asm/kexec.h +++ b/arch/riscv/include/asm/kexec.h @@ -53,4 +53,8 @@ typedef void (*riscv_kexec_method)(unsigned long first_in= d_entry, =20 extern riscv_kexec_method riscv_kexec_norelocate; =20 +#ifdef CONFIG_KEXEC_FILE +extern const struct kexec_file_ops elf_kexec_ops; +#endif + #endif diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 87adbe47bc15..6673c50c58e2 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -64,6 +64,7 @@ endif obj-$(CONFIG_HOTPLUG_CPU) +=3D cpu-hotplug.o obj-$(CONFIG_KGDB) +=3D kgdb.o obj-$(CONFIG_KEXEC) +=3D kexec_relocate.o crash_save_regs.o machine_kexec= .o +obj-$(CONFIG_KEXEC_FILE) +=3D elf_kexec.o machine_kexec_file.o obj-$(CONFIG_CRASH_DUMP) +=3D crash_dump.o =20 obj-$(CONFIG_JUMP_LABEL) +=3D jump_label.o diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c new file mode 100644 index 000000000000..2d442a849871 --- /dev/null +++ b/arch/riscv/kernel/elf_kexec.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (C) 2021 Huawei Technologies Co, Ltd. + * + * Author: Liao Chang (liaochang1@huawei.com) + * + * Based on kexec-tools' kexec-elf-riscv.c, heavily modified + * for kernel. + */ + +#define pr_fmt(fmt) "kexec_image: " fmt + +#include +#include +#include +#include +#include +#include + +static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, + struct kexec_elf_info *elf_info, unsigned long old_pbase, + unsigned long new_pbase) +{ + int i; + int ret =3D 0; + size_t size; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + + kbuf.image =3D image; + + for (i =3D 0; i < ehdr->e_phnum; i++) { + phdr =3D &elf_info->proghdrs[i]; + if (phdr->p_type !=3D PT_LOAD) + continue; + + size =3D phdr->p_filesz; + if (size > phdr->p_memsz) + size =3D phdr->p_memsz; + + kbuf.buffer =3D (void *) elf_info->buffer + phdr->p_offset; + kbuf.bufsz =3D size; + kbuf.buf_align =3D phdr->p_align; + kbuf.mem =3D phdr->p_paddr - old_pbase + new_pbase; + kbuf.memsz =3D phdr->p_memsz; + kbuf.top_down =3D false; + ret =3D kexec_add_buffer(&kbuf); + if (ret) + break; + } + + return ret; +} + +/* + * Go through the available phsyical memory regions and find one that hold + * an image of the specified size. + */ +static int elf_find_pbase(struct kimage *image, unsigned long kernel_len, + struct elfhdr *ehdr, struct kexec_elf_info *elf_info, + unsigned long *old_pbase, unsigned long *new_pbase) +{ + int i; + int ret; + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + unsigned long lowest_paddr =3D ULONG_MAX; + unsigned long lowest_vaddr =3D ULONG_MAX; + + for (i =3D 0; i < ehdr->e_phnum; i++) { + phdr =3D &elf_info->proghdrs[i]; + if (phdr->p_type !=3D PT_LOAD) + continue; + + if (lowest_paddr > phdr->p_paddr) + lowest_paddr =3D phdr->p_paddr; + + if (lowest_vaddr > phdr->p_vaddr) + lowest_vaddr =3D phdr->p_vaddr; + } + + kbuf.image =3D image; + kbuf.buf_min =3D lowest_paddr; + kbuf.buf_max =3D ULONG_MAX; + kbuf.buf_align =3D PAGE_SIZE; + kbuf.mem =3D KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz =3D ALIGN(kernel_len, PAGE_SIZE); + kbuf.top_down =3D false; + ret =3D arch_kexec_locate_mem_hole(&kbuf); + if (!ret) { + *old_pbase =3D lowest_paddr; + *new_pbase =3D kbuf.mem; + image->start =3D ehdr->e_entry - lowest_vaddr + kbuf.mem; + } + return ret; +} + +static void *elf_kexec_load(struct kimage *image, char *kernel_buf, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + int ret; + unsigned long old_kernel_pbase =3D ULONG_MAX; + unsigned long new_kernel_pbase =3D 0UL; + unsigned long initrd_pbase =3D 0UL; + void *fdt; + struct elfhdr ehdr; + struct kexec_buf kbuf; + struct kexec_elf_info elf_info; + + ret =3D kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); + if (ret) + return ERR_PTR(ret); + + ret =3D elf_find_pbase(image, kernel_len, &ehdr, &elf_info, + &old_kernel_pbase, &new_kernel_pbase); + if (ret) + goto out; + pr_notice("The entry point of kernel at 0x%lx\n", image->start); + + /* Add the kernel binary to the image */ + ret =3D riscv_kexec_elf_load(image, &ehdr, &elf_info, + old_kernel_pbase, new_kernel_pbase); + if (ret) + goto out; + + kbuf.image =3D image; + kbuf.buf_min =3D new_kernel_pbase + kernel_len; + kbuf.buf_max =3D ULONG_MAX; + /* Add the initrd to the image */ + if (initrd !=3D NULL) { + kbuf.buffer =3D initrd; + kbuf.bufsz =3D kbuf.memsz =3D initrd_len; + kbuf.buf_align =3D PAGE_SIZE; + kbuf.top_down =3D false; + kbuf.mem =3D KEXEC_BUF_MEM_UNKNOWN; + ret =3D kexec_add_buffer(&kbuf); + if (ret) + goto out; + initrd_pbase =3D kbuf.mem; + pr_notice("Loaded initrd at 0x%lx\n", initrd_pbase); + } + + /* Add the DTB to the image */ + fdt =3D of_kexec_alloc_and_setup_fdt(image, initrd_pbase, + initrd_len, cmdline, 0); + if (!fdt) { + pr_err("Error setting up the new device tree.\n"); + ret =3D -EINVAL; + goto out; + } + + fdt_pack(fdt); + kbuf.buffer =3D fdt; + kbuf.bufsz =3D kbuf.memsz =3D fdt_totalsize(fdt); + kbuf.buf_align =3D PAGE_SIZE; + kbuf.mem =3D KEXEC_BUF_MEM_UNKNOWN; + kbuf.top_down =3D true; + ret =3D kexec_add_buffer(&kbuf); + if (ret) { + pr_err("Error add DTB kbuf ret=3D%d\n", ret); + goto out_free_fdt; + } + pr_notice("Loaded device tree at 0x%lx\n", kbuf.mem); + goto out; + +out_free_fdt: + kvfree(fdt); +out: + kexec_free_elf_info(&elf_info); + return ret ? ERR_PTR(ret) : NULL; +} + +const struct kexec_file_ops elf_kexec_ops =3D { + .probe =3D kexec_elf_probe, + .load =3D elf_kexec_load, +}; diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/mac= hine_kexec_file.c new file mode 100644 index 000000000000..b0bf8c1722c0 --- /dev/null +++ b/arch/riscv/kernel/machine_kexec_file.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * kexec_file for riscv, use vmlinux as the dump-capture kernel image. + * + * Copyright (C) 2021 Huawei Technologies Co, Ltd. + * + * Author: Liao Chang (liaochang1@huawei.com) + */ +#include + +const struct kexec_file_ops * const kexec_file_loaders[] =3D { + &elf_kexec_ops, + NULL +}; --=20 2.17.1 From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B824C433EF for ; Fri, 8 Apr 2022 10:10:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233799AbiDHKMp (ORCPT ); Fri, 8 Apr 2022 06:12:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58008 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232944AbiDHKMN (ORCPT ); Fri, 8 Apr 2022 06:12:13 -0400 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 50DB4AAB49 for ; Fri, 8 Apr 2022 03:10:10 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.57]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4KZYrf4MJYzdZnh; Fri, 8 Apr 2022 18:09:38 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:07 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 4/6] RISC-V: Support for kexec_file on panic Date: Fri, 8 Apr 2022 18:09:12 +0800 Message-ID: <20220408100914.150110-5-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch adds support for loading a kexec on panic (kdump) kernel. It has been tested with vmcore-dmesg on riscv64 QEMU on both an smp and a non-smp system. Signed-off-by: Li Zhengyu --- arch/riscv/kernel/elf_kexec.c | 119 +++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 1 deletion(-) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index 2d442a849871..911d65d5a123 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include =20 static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr, struct kexec_elf_info *elf_info, unsigned long old_pbase, @@ -97,6 +99,79 @@ static int elf_find_pbase(struct kimage *image, unsigned= long kernel_len, return ret; } =20 +static int get_nr_ram_ranges_callback(struct resource *res, void *arg) +{ + unsigned int *nr_ranges =3D arg; + + (*nr_ranges)++; + return 0; +} + +static int prepare_elf64_ram_headers_callback(struct resource *res, void *= arg) +{ + struct crash_mem *cmem =3D arg; + + cmem->ranges[cmem->nr_ranges].start =3D res->start; + cmem->ranges[cmem->nr_ranges].end =3D res->end; + cmem->nr_ranges++; + + return 0; +} + +static int prepare_elf_headers(void **addr, unsigned long *sz) +{ + struct crash_mem *cmem; + unsigned int nr_ranges; + int ret; + + nr_ranges =3D 1; /* For exclusion of crashkernel region */ + walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); + + cmem =3D kmalloc(struct_size(cmem, ranges, nr_ranges), GFP_KERNEL); + if (!cmem) + return -ENOMEM; + + cmem->max_nr_ranges =3D nr_ranges; + cmem->nr_ranges =3D 0; + ret =3D walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callba= ck); + if (ret) + goto out; + + /* Exclude crashkernel region */ + ret =3D crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); + if (!ret) + ret =3D crash_prepare_elf64_headers(cmem, true, addr, sz); + +out: + kfree(cmem); + return ret; +} + +static char *setup_kdump_cmdline(struct kimage *image, char *cmdline, + unsigned long cmdline_len) +{ + int elfcorehdr_strlen; + char *cmdline_ptr; + + cmdline_ptr =3D kzalloc(COMMAND_LINE_SIZE, GFP_KERNEL); + if (!cmdline_ptr) + return NULL; + + elfcorehdr_strlen =3D sprintf(cmdline_ptr, "elfcorehdr=3D0x%lx ", + image->elf_load_addr); + + if (elfcorehdr_strlen + cmdline_len > COMMAND_LINE_SIZE) { + pr_err("Appending elfcorehdr=3D exceeds cmdline size\n"); + kfree(cmdline_ptr); + return NULL; + } + + memcpy(cmdline_ptr + elfcorehdr_strlen, cmdline, cmdline_len); + /* Ensure it's nul terminated */ + cmdline_ptr[COMMAND_LINE_SIZE - 1] =3D '\0'; + return cmdline_ptr; +} + static void *elf_kexec_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, unsigned long initrd_len, char *cmdline, @@ -106,10 +181,12 @@ static void *elf_kexec_load(struct kimage *image, cha= r *kernel_buf, unsigned long old_kernel_pbase =3D ULONG_MAX; unsigned long new_kernel_pbase =3D 0UL; unsigned long initrd_pbase =3D 0UL; - void *fdt; + unsigned long headers_sz; + void *fdt, *headers; struct elfhdr ehdr; struct kexec_buf kbuf; struct kexec_elf_info elf_info; + char *modified_cmdline =3D NULL; =20 ret =3D kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info); if (ret) @@ -130,6 +207,45 @@ static void *elf_kexec_load(struct kimage *image, char= *kernel_buf, kbuf.image =3D image; kbuf.buf_min =3D new_kernel_pbase + kernel_len; kbuf.buf_max =3D ULONG_MAX; + + /* Add elfcorehdr */ + if (image->type =3D=3D KEXEC_TYPE_CRASH) { + ret =3D prepare_elf_headers(&headers, &headers_sz); + if (ret) { + pr_err("Preparing elf core header failed\n"); + goto out; + } + + kbuf.buffer =3D headers; + kbuf.bufsz =3D headers_sz; + kbuf.mem =3D KEXEC_BUF_MEM_UNKNOWN; + kbuf.memsz =3D headers_sz; + kbuf.buf_align =3D ELF_CORE_HEADER_ALIGN; + kbuf.top_down =3D true; + + ret =3D kexec_add_buffer(&kbuf); + if (ret) { + vfree(headers); + goto out; + } + image->elf_headers =3D headers; + image->elf_load_addr =3D kbuf.mem; + image->elf_headers_sz =3D headers_sz; + + pr_debug("Loaded elf core header at 0x%lx bufsz=3D0x%lx memsz=3D0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + + /* Setup cmdline for kdump kernel case */ + modified_cmdline =3D setup_kdump_cmdline(image, cmdline, + cmdline_len); + if (!modified_cmdline) { + pr_err("Setting up cmdline for kdump kernel failed\n"); + ret =3D -EINVAL; + goto out; + } + cmdline =3D modified_cmdline; + } + /* Add the initrd to the image */ if (initrd !=3D NULL) { kbuf.buffer =3D initrd; @@ -170,6 +286,7 @@ static void *elf_kexec_load(struct kimage *image, char = *kernel_buf, out_free_fdt: kvfree(fdt); out: + kfree(modified_cmdline); kexec_free_elf_info(&elf_info); return ret ? ERR_PTR(ret) : NULL; } --=20 2.17.1 From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DC2C3C433EF for ; Fri, 8 Apr 2022 10:10:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233085AbiDHKMu (ORCPT ); Fri, 8 Apr 2022 06:12:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58040 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233212AbiDHKMO (ORCPT ); Fri, 8 Apr 2022 06:12:14 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AFFF1AAB55 for ; Fri, 8 Apr 2022 03:10:10 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4KZYqB5gRvzgYc1; Fri, 8 Apr 2022 18:08:22 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:08 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 5/6] RISC-V: Add purgatory Date: Fri, 8 Apr 2022 18:09:13 +0800 Message-ID: <20220408100914.150110-6-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch adds purgatory, the name and concept have been taken from kexec-tools. Purgatory runs between two kernels, and do verify sha256 hash to ensure the kernel to jump to is fine and has not been corrupted after loading. Makefile is modified based on x86 platform. Signed-off-by: Li Zhengyu --- arch/riscv/Kbuild | 2 + arch/riscv/Kconfig | 6 ++ arch/riscv/purgatory/.gitignore | 4 ++ arch/riscv/purgatory/Makefile | 95 ++++++++++++++++++++++++++++++++ arch/riscv/purgatory/entry.S | 47 ++++++++++++++++ arch/riscv/purgatory/purgatory.c | 45 +++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 arch/riscv/purgatory/.gitignore create mode 100644 arch/riscv/purgatory/Makefile create mode 100644 arch/riscv/purgatory/entry.S create mode 100644 arch/riscv/purgatory/purgatory.c diff --git a/arch/riscv/Kbuild b/arch/riscv/Kbuild index fb3397223d52..f562c7343fda 100644 --- a/arch/riscv/Kbuild +++ b/arch/riscv/Kbuild @@ -3,5 +3,7 @@ obj-y +=3D kernel/ mm/ net/ obj-$(CONFIG_BUILTIN_DTB) +=3D boot/dts/ =20 +obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) +=3D purgatory/ + # for cleaning subdir- +=3D boot diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index e95e4c390514..68733c2b6fcc 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -394,6 +394,12 @@ config KEXEC_FILE for kernel and initramfs as opposed to list of segments as accepted by previous system call. =20 +config ARCH_HAS_KEXEC_PURGATORY + def_bool KEXEC_FILE + select BUILD_BIN2C + depends on CRYPTO=3Dy + depends on CRYPTO_SHA256=3Dy + config CRASH_DUMP bool "Build kdump crash kernel" help diff --git a/arch/riscv/purgatory/.gitignore b/arch/riscv/purgatory/.gitign= ore new file mode 100644 index 000000000000..38d7d1bda4d7 --- /dev/null +++ b/arch/riscv/purgatory/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +purgatory.chk +purgatory.ro +kexec-purgatory.c diff --git a/arch/riscv/purgatory/Makefile b/arch/riscv/purgatory/Makefile new file mode 100644 index 000000000000..d4df200f7edf --- /dev/null +++ b/arch/riscv/purgatory/Makefile @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0 +OBJECT_FILES_NON_STANDARD :=3D y + +purgatory-y :=3D purgatory.o sha256.o entry.o string.o ctype.o memcpy.o me= mset.o + +targets +=3D $(purgatory-y) +PURGATORY_OBJS =3D $(addprefix $(obj)/,$(purgatory-y)) + +$(obj)/string.o: $(srctree)/lib/string.c FORCE + $(call if_changed_rule,cc_o_c) + +$(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE + $(call if_changed_rule,cc_o_c) + +$(obj)/memcpy.o: $(srctree)/arch/riscv/lib/memcpy.S FORCE + $(call if_changed_rule,as_o_S) + +$(obj)/memset.o: $(srctree)/arch/riscv/lib/memset.S FORCE + $(call if_changed_rule,as_o_S) + +$(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE + $(call if_changed_rule,cc_o_c) + +CFLAGS_sha256.o :=3D -D__DISABLE_EXPORTS +CFLAGS_string.o :=3D -D__DISABLE_EXPORTS +CFLAGS_ctype.o :=3D -D__DISABLE_EXPORTS + +# When linking purgatory.ro with -r unresolved symbols are not checked, +# also link a purgatory.chk binary without -r to check for unresolved symb= ols. +PURGATORY_LDFLAGS :=3D -e purgatory_start -z nodefaultlib +LDFLAGS_purgatory.ro :=3D -r $(PURGATORY_LDFLAGS) +LDFLAGS_purgatory.chk :=3D $(PURGATORY_LDFLAGS) +targets +=3D purgatory.ro purgatory.chk + +# Sanitizer, etc. runtimes are unavailable and cannot be linked here. +GCOV_PROFILE :=3D n +KASAN_SANITIZE :=3D n +UBSAN_SANITIZE :=3D n +KCSAN_SANITIZE :=3D n +KCOV_INSTRUMENT :=3D n + +# These are adjustments to the compiler flags used for objects that +# make up the standalone purgatory.ro + +PURGATORY_CFLAGS_REMOVE :=3D -mcmodel=3Dkernel +PURGATORY_CFLAGS :=3D -mcmodel=3Dmedany -ffreestanding -fno-zero-initializ= ed-in-bss +PURGATORY_CFLAGS +=3D $(DISABLE_STACKLEAK_PLUGIN) -DDISABLE_BRANCH_PROFILI= NG +PURGATORY_CFLAGS +=3D -fno-stack-protector -g0 + +# Default KBUILD_CFLAGS can have -pg option set when FTRACE is enabled. Th= at +# in turn leaves some undefined symbols like __fentry__ in purgatory and n= ot +# sure how to relocate those. +ifdef CONFIG_FUNCTION_TRACER +PURGATORY_CFLAGS_REMOVE +=3D $(CC_FLAGS_FTRACE) +endif + +ifdef CONFIG_STACKPROTECTOR +PURGATORY_CFLAGS_REMOVE +=3D -fstack-protector +endif + +ifdef CONFIG_STACKPROTECTOR_STRONG +PURGATORY_CFLAGS_REMOVE +=3D -fstack-protector-strong +endif + +CFLAGS_REMOVE_purgatory.o +=3D $(PURGATORY_CFLAGS_REMOVE) +CFLAGS_purgatory.o +=3D $(PURGATORY_CFLAGS) + +CFLAGS_REMOVE_sha256.o +=3D $(PURGATORY_CFLAGS_REMOVE) +CFLAGS_sha256.o +=3D $(PURGATORY_CFLAGS) + +CFLAGS_REMOVE_string.o +=3D $(PURGATORY_CFLAGS_REMOVE) +CFLAGS_string.o +=3D $(PURGATORY_CFLAGS) + +CFLAGS_REMOVE_ctype.o +=3D $(PURGATORY_CFLAGS_REMOVE) +CFLAGS_ctype.o +=3D $(PURGATORY_CFLAGS) + +AFLAGS_REMOVE_entry.o +=3D -Wa,-gdwarf-2 +AFLAGS_REMOVE_memcpy.o +=3D -Wa,-gdwarf-2 +AFLAGS_REMOVE_memset.o +=3D -Wa,-gdwarf-2 + +$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE + $(call if_changed,ld) + +$(obj)/purgatory.chk: $(obj)/purgatory.ro FORCE + $(call if_changed,ld) + +targets +=3D kexec-purgatory.c + +quiet_cmd_bin2c =3D BIN2C $@ + cmd_bin2c =3D $(objtree)/scripts/bin2c kexec_purgatory < $< > $@ + +$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro $(obj)/purgatory.chk FORCE + $(call if_changed,bin2c) + +obj-$(CONFIG_ARCH_HAS_KEXEC_PURGATORY) +=3D kexec-purgatory.o diff --git a/arch/riscv/purgatory/entry.S b/arch/riscv/purgatory/entry.S new file mode 100644 index 000000000000..0194f4554130 --- /dev/null +++ b/arch/riscv/purgatory/entry.S @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * purgatory: Runs between two kernels + * + * Copyright (C) 2022 Huawei Technologies Co, Ltd. + * + * Author: Li Zhengyu (lizhengyu3@huawei.com) + * + */ + +.macro size, sym:req + .size \sym, . - \sym +.endm + +.text + +.globl purgatory_start +purgatory_start: + + lla sp, .Lstack + mv s0, a0 /* The hartid of the current hart */ + mv s1, a1 /* Phys address of the FDT image */ + + jal purgatory + + /* Start new image. */ + mv a0, s0 + mv a1, s1 + ld a2, riscv_kernel_entry + jr a2 + +size purgatory_start + +.align 4 + .rept 256 + .quad 0 + .endr +.Lstack: + +.data + +.globl riscv_kernel_entry +riscv_kernel_entry: + .quad 0 +size riscv_kernel_entry + +.end diff --git a/arch/riscv/purgatory/purgatory.c b/arch/riscv/purgatory/purgat= ory.c new file mode 100644 index 000000000000..80596ab5fb62 --- /dev/null +++ b/arch/riscv/purgatory/purgatory.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * purgatory: Runs between two kernels + * + * Copyright (C) 2022 Huawei Technologies Co, Ltd. + * + * Author: Li Zhengyu (lizhengyu3@huawei.com) + * + */ + +#include +#include +#include +#include + +u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(".kexec-purgatory= "); + +struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] __section= (".kexec-purgatory"); + +static int verify_sha256_digest(void) +{ + struct kexec_sha_region *ptr, *end; + struct sha256_state ss; + u8 digest[SHA256_DIGEST_SIZE]; + + sha256_init(&ss); + end =3D purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions); + for (ptr =3D purgatory_sha_regions; ptr < end; ptr++) + sha256_update(&ss, (uint8_t *)(ptr->start), ptr->len); + sha256_final(&ss, digest); + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)) !=3D 0) + return 1; + return 0; +} + +/* workaround for a warning with -Wmissing-prototypes */ +void purgatory(void); + +void purgatory(void) +{ + if (verify_sha256_digest()) + for (;;) + /* loop forever */ + ; +} --=20 2.17.1 From nobody Mon May 11 11:30:55 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8AD23C433F5 for ; Fri, 8 Apr 2022 10:11:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234263AbiDHKNA (ORCPT ); Fri, 8 Apr 2022 06:13:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58302 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233823AbiDHKMP (ORCPT ); Fri, 8 Apr 2022 06:12:15 -0400 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 66BC3A997B for ; Fri, 8 Apr 2022 03:10:11 -0700 (PDT) Received: from kwepemi500014.china.huawei.com (unknown [172.30.72.55]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4KZYqC59v2zgYXp; Fri, 8 Apr 2022 18:08:23 +0800 (CST) Received: from huawei.com (10.67.174.157) by kwepemi500014.china.huawei.com (7.221.188.232) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Fri, 8 Apr 2022 18:10:08 +0800 From: Li Zhengyu To: , CC: , , , , , , , , , , , , , Subject: [PATCH v3 -next 6/6] RISC-V: Load purgatory in kexec_file Date: Fri, 8 Apr 2022 18:09:14 +0800 Message-ID: <20220408100914.150110-7-lizhengyu3@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220408100914.150110-1-lizhengyu3@huawei.com> References: <20220408100914.150110-1-lizhengyu3@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.157] X-ClientProxiedBy: dggems703-chm.china.huawei.com (10.3.19.180) To kwepemi500014.china.huawei.com (7.221.188.232) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch supports kexec_file to load and relocate purgatory. It works well on riscv64 QEMU, being tested with devmem. Signed-off-by: Li Zhengyu --- arch/riscv/kernel/elf_kexec.c | 151 ++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index 911d65d5a123..9cb85095fd45 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -182,6 +182,7 @@ static void *elf_kexec_load(struct kimage *image, char = *kernel_buf, unsigned long new_kernel_pbase =3D 0UL; unsigned long initrd_pbase =3D 0UL; unsigned long headers_sz; + unsigned long kernel_start; void *fdt, *headers; struct elfhdr ehdr; struct kexec_buf kbuf; @@ -196,6 +197,7 @@ static void *elf_kexec_load(struct kimage *image, char = *kernel_buf, &old_kernel_pbase, &new_kernel_pbase); if (ret) goto out; + kernel_start =3D image->start; pr_notice("The entry point of kernel at 0x%lx\n", image->start); =20 /* Add the kernel binary to the image */ @@ -246,6 +248,22 @@ static void *elf_kexec_load(struct kimage *image, char= *kernel_buf, cmdline =3D modified_cmdline; } =20 +#ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY + /* Add purgatory to the image */ + kbuf.top_down =3D true; + kbuf.mem =3D KEXEC_BUF_MEM_UNKNOWN; + ret =3D kexec_load_purgatory(image, &kbuf); + if (ret) { + pr_err("Error loading purgatory ret=3D%d\n", ret); + goto out; + } + ret =3D kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", + &kernel_start, + sizeof(kernel_start), 0); + if (ret) + pr_err("Error update purgatory ret=3D%d\n", ret); +#endif /* CONFIG_ARCH_HAS_KEXEC_PURGATORY */ + /* Add the initrd to the image */ if (initrd !=3D NULL) { kbuf.buffer =3D initrd; @@ -291,6 +309,139 @@ static void *elf_kexec_load(struct kimage *image, cha= r *kernel_buf, return ret ? ERR_PTR(ret) : NULL; } =20 +#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL << RISCV_IMM_BITS) +#define RISCV_CONST_HIGH_PART(x) \ + (((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1)) +#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x)) + +#define ENCODE_ITYPE_IMM(x) \ + (RV_X(x, 0, 12) << 20) +#define ENCODE_BTYPE_IMM(x) \ + ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \ + (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31)) +#define ENCODE_UTYPE_IMM(x) \ + (RV_X(x, 12, 20) << 12) +#define ENCODE_JTYPE_IMM(x) \ + ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \ + (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) +#define ENCODE_CBTYPE_IMM(x) \ + ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12)) +#define ENCODE_CJTYPE_IMM(x) \ + ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \ + (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \ + (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12)) +#define ENCODE_UJTYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \ + (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32)) +#define ENCODE_UITYPE_IMM(x) \ + (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32)) + +#define CLEAN_IMM(type, x) \ + ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x)) + +int arch_kexec_apply_relocations_add(struct purgatory_info *pi, + Elf_Shdr *section, + const Elf_Shdr *relsec, + const Elf_Shdr *symtab) +{ + const char *strtab, *name, *shstrtab; + const Elf_Shdr *sechdrs; + Elf_Rela *relas; + int i, r_type; + + /* String & section header string table */ + sechdrs =3D (void *)pi->ehdr + pi->ehdr->e_shoff; + strtab =3D (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset; + shstrtab =3D (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; + + relas =3D (void *)pi->ehdr + relsec->sh_offset; + + for (i =3D 0; i < relsec->sh_size / sizeof(*relas); i++) { + const Elf_Sym *sym; /* symbol to relocate */ + unsigned long addr; /* final location after relocation */ + unsigned long val; /* relocated symbol value */ + unsigned long sec_base; /* relocated symbol value */ + void *loc; /* tmp location to modify */ + + sym =3D (void *)pi->ehdr + symtab->sh_offset; + sym +=3D ELF64_R_SYM(relas[i].r_info); + + if (sym->st_name) + name =3D strtab + sym->st_name; + else + name =3D shstrtab + sechdrs[sym->st_shndx].sh_name; + + loc =3D pi->purgatory_buf; + loc +=3D section->sh_offset; + loc +=3D relas[i].r_offset; + + if (sym->st_shndx =3D=3D SHN_ABS) + sec_base =3D 0; + else if (sym->st_shndx >=3D pi->ehdr->e_shnum) { + pr_err("Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } else + sec_base =3D pi->sechdrs[sym->st_shndx].sh_addr; + + val =3D sym->st_value; + val +=3D sec_base; + val +=3D relas[i].r_addend; + + addr =3D section->sh_addr + relas[i].r_offset; + + r_type =3D ELF64_R_TYPE(relas[i].r_info); + + switch (r_type) { + case R_RISCV_BRANCH: + *(u32 *)loc =3D CLEAN_IMM(BTYPE, *(u32 *)loc) | + ENCODE_BTYPE_IMM(val - addr); + break; + case R_RISCV_JAL: + *(u32 *)loc =3D CLEAN_IMM(JTYPE, *(u32 *)loc) | + ENCODE_JTYPE_IMM(val - addr); + break; + /* + * With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I + * sym is expected to be next to R_RISCV_PCREL_HI20 + * in purgatory relsec. Handle it like R_RISCV_CALL + * sym, instead of searching the whole relsec. + */ + case R_RISCV_PCREL_HI20: + case R_RISCV_CALL: + *(u64 *)loc =3D CLEAN_IMM(UITYPE, *(u64 *)loc) | + ENCODE_UJTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_BRANCH: + *(u32 *)loc =3D CLEAN_IMM(CBTYPE, *(u32 *)loc) | + ENCODE_CBTYPE_IMM(val - addr); + break; + case R_RISCV_RVC_JUMP: + *(u32 *)loc =3D CLEAN_IMM(CJTYPE, *(u32 *)loc) | + ENCODE_CJTYPE_IMM(val - addr); + break; + case R_RISCV_ADD32: + *(u32 *)loc +=3D val; + break; + case R_RISCV_SUB32: + *(u32 *)loc -=3D val; + break; + /* It has been applied by R_RISCV_PCREL_HI20 sym */ + case R_RISCV_PCREL_LO12_I: + case R_RISCV_ALIGN: + case R_RISCV_RELAX: + break; + default: + pr_err("Unknown rela relocation: %d\n", r_type); + return -ENOEXEC; + } + } + return 0; +} + const struct kexec_file_ops elf_kexec_ops =3D { .probe =3D kexec_elf_probe, .load =3D elf_kexec_load, --=20 2.17.1