Received: by 2002:a25:6193:0:0:0:0:0 with SMTP id v141csp4469005ybb; Tue, 14 Apr 2020 07:56:14 -0700 (PDT) X-Google-Smtp-Source: APiQypIxnqYhTlvDh2p5V+GOWLkzIS1PR1sXYDTDVEx1RM0OgNBw5hxvkZoq0FHUj0+UpKvH5kzH X-Received: by 2002:a50:cf8e:: with SMTP id h14mr21309871edk.369.1586876174409; Tue, 14 Apr 2020 07:56:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1586876174; cv=none; d=google.com; s=arc-20160816; b=u+vpNvJsM7SnlDV472diXzD5H9DlzDcAm40goVXw9aR+wZ9/nluRGYNwUvmeZQWItY O0vhTS2wddkIuDapyCaP+BRpe6SySg2GDHs7TTYgd/RwyEgGu1PaLTHJhGx3hwYR+do0 Hhilc6LK562L93Zl6D5PWFGKySbffugc7TltHe/TyGzIpJ6z4igAFiwoR4VeIH4H/gsQ Xi2joGYIm2fsDzvgR3IFrOprT8d0nKeHJl1BDKpW3HC3kCCsFRUEc71icf7DXk0FAQUW VFCTSZZJyYQWeVkzn7kA/lbrh+4oV4n6Uzr866AqqBEvBkeg6+3juq7DZQ0+2rZcntSv OMkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=3yW7h8nffs2Ugfl/+9tsCXAOp2f+diWOQyV3xf4TpjQ=; b=yR/Iwqm4WaIP3W4lPIJeOtT7ddnlSNbJXdsDRJ1POeMkG81lYGbdiZGUN/t+LmYw4K rVNfgv9Ne0o9qWQt2Yu0XBA4FSF12+yHS9eh6Y5AaaAMalGQ0uRz7oisBWNodwwBC7mt kOvlJ1V/Xvm7yCSUTVh++GbUQHeE9SUYEwyZLn/gxyHNIsORltCqgUk8pCwkR4hrZBBr kjnN6m5sApuRr7dD7gKquGxkDMi2y056rgsS+b7i2IIiSwpXU1RATHmnfsRX33aCubyU tawtlO47JoT/9DtfvIEJBHxfNNcIMFezL1ixcAJleDH19m1v7Zn3ruOjp9rxDAPn0+Nc Nspg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=kkhRNFE9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id g22si8420641ejr.228.2020.04.14.07.55.51; Tue, 14 Apr 2020 07:56:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=kkhRNFE9; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2406790AbgDNHmT (ORCPT + 99 others); Tue, 14 Apr 2020 03:42:19 -0400 Received: from mail.kernel.org ([198.145.29.99]:51374 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729368AbgDNHmJ (ORCPT ); Tue, 14 Apr 2020 03:42:09 -0400 Received: from mail-il1-f175.google.com (mail-il1-f175.google.com [209.85.166.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id DE6452078A; Tue, 14 Apr 2020 07:42:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1586850128; bh=6uhrz44i5eT5f7oLOC1OL5FsVtDT/iQzuTX/CEU8+zg=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=kkhRNFE9I2rpe6sQkWBvxuZaLVbg2k7qQG00iGfMn+/lB/f4EpTtiIstquxxZzcHx Boy3N8hW0XUYjpMpVWWDMxuiLsBLOIqw/GFFqVBO2tV9JEdob4OvPkRBe2168zb3DO KJ+dXf05/GRM9IhKGc/hQuPjx581hpLtIlKD/WKM= Received: by mail-il1-f175.google.com with SMTP id t8so6385276ilj.3; Tue, 14 Apr 2020 00:42:07 -0700 (PDT) X-Gm-Message-State: AGi0Pubfk2YiXe6/uZL+Y1OCSxUhUwjzKkzeKj68YFESJqRCz1yp7FMx EEtL4BHXUtktgvKRjDLyeVHjEFMyEWQOfUP2yYQ= X-Received: by 2002:a92:c788:: with SMTP id c8mr20566174ilk.279.1586850127067; Tue, 14 Apr 2020 00:42:07 -0700 (PDT) MIME-Version: 1.0 References: <20200413212907.29244-1-atish.patra@wdc.com> <20200413212907.29244-6-atish.patra@wdc.com> In-Reply-To: <20200413212907.29244-6-atish.patra@wdc.com> From: Ard Biesheuvel Date: Tue, 14 Apr 2020 09:41:56 +0200 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [v2 PATCH 5/5] RISC-V: Add EFI stub support. To: Atish Patra Cc: Linux Kernel Mailing List , Arnd Bergmann , Catalin Marinas , Greg Kroah-Hartman , Ingo Molnar , linux-efi , linux-riscv@lists.infradead.org, Linux ARM , Masahiro Yamada , Palmer Dabbelt , Russell King , Will Deacon Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Mon, 13 Apr 2020 at 23:29, Atish Patra wrote: > > Add a RISC-V architecture specific stub code that actually copies the > actual kernel image to a valid address and jump to it after boot services > are terminated. Enable UEFI related kernel configs as well for RISC-V. > > Signed-off-by: Atish Patra > --- > arch/riscv/Kconfig | 20 ++++ > arch/riscv/Makefile | 1 + > arch/riscv/configs/defconfig | 1 + > arch/riscv/include/asm/efi.h | 45 ++++++++ > drivers/firmware/efi/Kconfig | 2 +- > drivers/firmware/efi/libstub/Makefile | 8 ++ > drivers/firmware/efi/libstub/riscv-stub.c | 131 ++++++++++++++++++++++ > 7 files changed, 207 insertions(+), 1 deletion(-) > create mode 100644 arch/riscv/include/asm/efi.h > create mode 100644 drivers/firmware/efi/libstub/riscv-stub.c > > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig > index f39e326a7a42..eb4f41c8f3ce 100644 > --- a/arch/riscv/Kconfig > +++ b/arch/riscv/Kconfig > @@ -379,10 +379,30 @@ config CMDLINE_FORCE > > endchoice > > +config EFI_STUB > + bool > + > +config EFI > + bool "UEFI runtime support" > + depends on OF > + select LIBFDT > + select UCS2_STRING > + select EFI_PARAMS_FROM_FDT > + select EFI_STUB > + select EFI_GENERIC_STUB > + default y > + help > + This option provides support for runtime services provided > + by UEFI firmware (such as non-volatile variables, realtime > + clock, and platform reset). A UEFI stub is also provided to > + allow the kernel to be booted as an EFI application. This > + is only useful on systems that have UEFI firmware. > + > endmenu > > menu "Power management options" > > source "kernel/power/Kconfig" > +source "drivers/firmware/Kconfig" > > endmenu > diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile > index fb6e37db836d..079435804d6d 100644 > --- a/arch/riscv/Makefile > +++ b/arch/riscv/Makefile > @@ -80,6 +80,7 @@ head-y := arch/riscv/kernel/head.o > core-y += arch/riscv/ > > libs-y += arch/riscv/lib/ > +core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a > > PHONY += vdso_install > vdso_install: > diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig > index 4da4886246a4..ae69e12d306a 100644 > --- a/arch/riscv/configs/defconfig > +++ b/arch/riscv/configs/defconfig > @@ -129,3 +129,4 @@ CONFIG_DEBUG_BLOCK_EXT_DEVT=y > # CONFIG_RUNTIME_TESTING_MENU is not set > CONFIG_MEMTEST=y > # CONFIG_SYSFS_SYSCALL is not set > +CONFIG_EFI=y > diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h > new file mode 100644 > index 000000000000..ba0a6d35cc15 > --- /dev/null > +++ b/arch/riscv/include/asm/efi.h > @@ -0,0 +1,45 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + * Based on arch/arm64/include/asm/efi.h > + */ > +#ifndef _ASM_EFI_H > +#define _ASM_EFI_H > + > +#include > +#include > +#include > +#include > + > +#define VA_BITS_MIN 39 > + > +/* on RISC-V, the FDT may be located anywhere in system RAM */ > +static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base) > +{ > + return ULONG_MAX; > +} > + > +/* Load initrd at enough distance from DRAM start */ > +static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, > + unsigned long image_addr) > +{ > + return dram_base + SZ_256M; > +} > + > +#define efi_bs_call(func, ...) efi_system_table()->boottime->func(__VA_ARGS__) > +#define efi_rt_call(func, ...) efi_system_table()->runtime->func(__VA_ARGS__) > +#define efi_is_native() (true) > + > +#define efi_table_attr(inst, attr) (inst->attr) > + > +#define efi_call_proto(inst, func, ...) inst->func(inst, ##__VA_ARGS__) > + > +#define alloc_screen_info(x...) (&screen_info) > +extern char stext_offset[]; > + > +static inline void free_screen_info(struct screen_info *si) > +{ > +} > +#define EFI_ALLOC_ALIGN SZ_64K > + > +#endif /* _ASM_EFI_H */ > diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig > index 2a2b2b96a1dc..fcdc789d3f87 100644 > --- a/drivers/firmware/efi/Kconfig > +++ b/drivers/firmware/efi/Kconfig > @@ -111,7 +111,7 @@ config EFI_GENERIC_STUB > > config EFI_ARMSTUB_DTB_LOADER > bool "Enable the DTB loader" > - depends on EFI_GENERIC_STUB > + depends on EFI_GENERIC_STUB && !RISCV > default y > help > Select this config option to add support for the dtb= command > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile > index d590504541f6..b1db3a793c43 100644 > --- a/drivers/firmware/efi/libstub/Makefile > +++ b/drivers/firmware/efi/libstub/Makefile > @@ -22,6 +22,8 @@ cflags-$(CONFIG_ARM64) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ > cflags-$(CONFIG_ARM) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ > -fno-builtin -fpic \ > $(call cc-option,-mno-single-pic-base) > +cflags-$(CONFIG_RISCV) := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \ > + -fpic > > cflags-$(CONFIG_EFI_GENERIC_STUB) += -I$(srctree)/scripts/dtc/libfdt > > @@ -56,6 +58,7 @@ lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o string.o \ > lib-$(CONFIG_ARM) += arm32-stub.o > lib-$(CONFIG_ARM64) += arm64-stub.o > lib-$(CONFIG_X86) += x86-stub.o > +lib-$(CONFIG_RISCV) += riscv-stub.o > CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) > CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) > > @@ -80,6 +83,11 @@ STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \ > --prefix-symbols=__efistub_ > STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS > > +STUBCOPY_FLAGS-$(CONFIG_RISCV) += --prefix-alloc-sections=.init \ > + --prefix-symbols=__efistub_ > +STUBCOPY_RELOC-$(CONFIG_RISCV) := R_RISCV_HI20 > + > + > $(obj)/%.stub.o: $(obj)/%.o FORCE > $(call if_changed,stubcopy) > > diff --git a/drivers/firmware/efi/libstub/riscv-stub.c b/drivers/firmware/efi/libstub/riscv-stub.c > new file mode 100644 > index 000000000000..acb69eae187a > --- /dev/null > +++ b/drivers/firmware/efi/libstub/riscv-stub.c > @@ -0,0 +1,131 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2013, 2014 Linaro Ltd; > + * Copyright (C) 2020 Western Digital Corporation or its affiliates. > + * > + * This file implements the EFI boot stub for the RISC-V kernel. > + * Adapted from ARM64 version at drivers/firmware/efi/libstub/arm64-stub.c. > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +#include "efistub.h" > +/* > + * RISCV requires the kernel image to placed TEXT_OFFSET bytes beyond a 2 MB > + * aligned base for 64 bit and 4MB for 32 bit. > + */ > +#ifdef CONFIG_64BIT > +#define MIN_KIMG_ALIGN SZ_2M > +#else > +#define MIN_KIMG_ALIGN SZ_4M > +#endif > +/* > + * TEXT_OFFSET ensures that we don't overwrite the firmware that probably sits > + * at the beginning of the DRAM. > + */ > +#define TEXT_OFFSET MIN_KIMG_ALIGN > + Again, this is not the right approach. If there are any allocations in memory that EFI cannot touch, you have to mark them as reserved in the EFI memory map. Otherwise, anything running in the EFI context (GRUB, systemd-boot, shim, etc) could step on it, not just the kernel. > +typedef __attribute__((noreturn)) void (*jump_kernel_func)(unsigned int, > + unsigned long); > +efi_status_t check_platform_features(void) > +{ > + return EFI_SUCCESS; > +} > + > +static u32 get_boot_hartid_from_fdt(unsigned long fdt) > +{ > + int chosen_node, len; > + const fdt32_t *prop; > + > + chosen_node = fdt_path_offset((void *)fdt, "/chosen"); > + if (chosen_node < 0) > + return U32_MAX; > + prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len); > + if (!prop || len != sizeof(u32)) > + return U32_MAX; > + > + return fdt32_to_cpu(*prop); > +} > + > +/* > + * Jump to real kernel here with following constraints. > + * 1. MMU should be disabled. > + * 2. a0 should contain hartid > + * 3. a1 should DT address > + */ > +void __noreturn efi_enter_kernel(unsigned long entrypoint, unsigned long fdt, > + unsigned long fdt_size) > +{ > + unsigned long kernel_entry = entrypoint + (unsigned long)stext_offset; > + jump_kernel_func jump_kernel = (void (*)(unsigned int, unsigned long))kernel_entry; > + u32 hartid = get_boot_hartid_from_fdt(fdt); > + > + if (hartid == U32_MAX) > + /* We can not use panic or BUG at this point */ > + __asm__ __volatile__ ("ebreak"); > + /* Disable MMU */ > + csr_write(CSR_SATP, 0); > + jump_kernel(hartid, fdt); > +} > + > +efi_status_t handle_kernel_image(unsigned long *image_addr, > + unsigned long *image_size, > + unsigned long *reserve_addr, > + unsigned long *reserve_size, > + unsigned long dram_base, > + efi_loaded_image_t *image) > +{ > + efi_status_t status; > + unsigned long kernel_size, kernel_memsize = 0; > + unsigned long preferred_offset; > + > + /* > + * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond > + * a KIMG_ALIGN aligned base. MIN_KIMG_ALIGN > + */ > + preferred_offset = round_up(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET; > + > + kernel_size = _edata - _start; > + kernel_memsize = kernel_size + (_end - _edata); > + > + /* > + * Try a straight allocation at the preferred offset. It will also > + * ensure that, on platforms where the [dram_base, dram_base + TEXT_OFFSET) > + * interval is partially occupied by the firmware we can still place > + * the kernel at the address 'dram_base + TEXT_OFFSET'. If the straight > + * allocation fails, efi_low_alloc tries allocate memory from the lowest > + * available LOADER_DATA mapped memory as long as address and size meet > + * the alignment constraints. > + */ > + if (*image_addr == preferred_offset) > + return EFI_SUCCESS; > + > + *image_addr = *reserve_addr = preferred_offset; > + *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN); > + > + status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, > + EFI_LOADER_DATA, > + *reserve_size / EFI_PAGE_SIZE, > + (efi_physical_addr_t *)reserve_addr); > + > + if (status != EFI_SUCCESS) { > + pr_efi("straight allocation failed do a low alloc\n"); > + *reserve_size = kernel_memsize + TEXT_OFFSET; > + status = efi_low_alloc(*reserve_size, MIN_KIMG_ALIGN, > + reserve_addr); > + So, instead of the above, could we simply allocate kernel_memsize bytes using efi_allocate_pages(), with the max address set to 'round_up(dram_base, MIN_KIMG_ALIGN) + kernel_memsize + TEXT_OFFSET - 1'? This should work in the majority of cases, and not trample on the TEXT_OFFSET bytes at the start, regardless of whether they are reserved or not. In the future, I imagine you may want to relax the requirements regarding the physical placement of the kernel, in which case you can start falling back to a suitably aligned allocation anywhere in memory. > + if (status != EFI_SUCCESS) { > + pr_efi_err("Failed to relocate kernel\n"); > + *reserve_size = 0; > + return status; > + } > + *image_addr = *reserve_addr + TEXT_OFFSET; > + } > + memcpy((void *)*image_addr, image->image_base, kernel_size); > + > + return EFI_SUCCESS; > +} > -- > 2.24.0 >