2020-07-06 17:29:15

by Atish Patra

[permalink] [raw]
Subject: [RFC PATCH v2 00/11] Add UEFI support for RISC-V

This series adds UEFI support for RISC-V.

Linux kernel: 5.8-rc4
U-Boot: master
OpenSBI: master

Patch 1-6 are preparatory patches that fixes some of the geric efi and riscv issues.

Patch 7-9 adds the efi stub support for RISC-V which was reviewed few months back.
https://www.spinics.net/lists/linux-efi/msg19144.html

Patch 10 just renames arm-init code so that it can be used across different
architectures. Patch 11 adds the runtime services for RISC-V.

The patches can also be found in following git repo.
https://github.com/atishp04/linux/tree/uefi_riscv_5.9_v2

The patches have been verified on Qemu using bootefi command in U-Boot for both
RV32 and RV64.

For RV32, maximum allocated memory should be 1G as RISC-V kernel can not map
beyond 1G of physical memory for RV32.

EDK2 can boot quite far into Linux with current series. Currently, we are seeing
some traps from drivers (spi/network). At first glance, they don't seem to be
caused by efi. I thought it is better to get some early feedback on the series
while EDK2 issue is being debugged.

That's why uefi runtime services are not actually well tested in RISC-V.
Any suggestions to test the efi run time services are appreciated.

Changes from v1->v2:
1. Removed patch 1 as it is already taken into efi-tree.
2. Fixed compilation issues with patch 9.
3. Moved few function prototype declaration to header file to keep kbuild happy.

Changes from previous version:
1. Added full ioremap support.
2. Added efi runtime services support.
3. Fixes mm issues

Anup Patel (1):
RISC-V: Move DT mapping outof fixmap

Atish Patra (10):
efi/libstub: Move the function prototypes to header file
RISC-V: Setup exception vector early
RISC-V: Add early ioremap support
RISC-V: Set maximum number of mapped pages correctly
riscv: Parse all memory blocks to remove unusable memory
include: pe.h: Add RISC-V related PE definition
RISC-V: Add PE/COFF header for EFI stub
RISC-V: Add EFI stub support.
efi: Rename arm-init to efi-init common for all arch
RISC-V: Add EFI runtime services

arch/riscv/Kconfig | 25 ++++
arch/riscv/Makefile | 1 +
arch/riscv/configs/defconfig | 1 +
arch/riscv/include/asm/Kbuild | 1 +
arch/riscv/include/asm/efi.h | 56 +++++++
arch/riscv/include/asm/fixmap.h | 16 +-
arch/riscv/include/asm/io.h | 1 +
arch/riscv/include/asm/mmu.h | 2 +
arch/riscv/include/asm/pgalloc.h | 12 ++
arch/riscv/include/asm/pgtable.h | 4 +
arch/riscv/include/asm/sections.h | 13 ++
arch/riscv/kernel/Makefile | 5 +
arch/riscv/kernel/efi-header.S | 104 +++++++++++++
arch/riscv/kernel/efi.c | 106 +++++++++++++
arch/riscv/kernel/head.S | 27 +++-
arch/riscv/kernel/head.h | 2 -
arch/riscv/kernel/image-vars.h | 51 +++++++
arch/riscv/kernel/setup.c | 16 +-
arch/riscv/kernel/smpboot.c | 1 -
arch/riscv/kernel/traps.c | 8 +-
arch/riscv/kernel/vmlinux.lds.S | 22 ++-
arch/riscv/mm/init.c | 104 ++++++++-----
drivers/firmware/efi/Kconfig | 3 +-
drivers/firmware/efi/Makefile | 4 +-
.../firmware/efi/{arm-init.c => efi-init.c} | 0
drivers/firmware/efi/libstub/Makefile | 10 ++
drivers/firmware/efi/libstub/efi-stub.c | 28 ++--
drivers/firmware/efi/libstub/efistub.h | 16 ++
drivers/firmware/efi/libstub/riscv-stub.c | 110 ++++++++++++++
drivers/firmware/efi/riscv-runtime.c | 141 ++++++++++++++++++
include/linux/pe.h | 3 +
31 files changed, 811 insertions(+), 82 deletions(-)
create mode 100644 arch/riscv/include/asm/efi.h
create mode 100644 arch/riscv/include/asm/sections.h
create mode 100644 arch/riscv/kernel/efi-header.S
create mode 100644 arch/riscv/kernel/efi.c
create mode 100644 arch/riscv/kernel/image-vars.h
rename drivers/firmware/efi/{arm-init.c => efi-init.c} (100%)
create mode 100644 drivers/firmware/efi/libstub/riscv-stub.c
create mode 100644 drivers/firmware/efi/riscv-runtime.c

--
2.24.0


2020-07-06 17:29:30

by Atish Patra

[permalink] [raw]
Subject: [RFC PATCH v2 05/11] RISC-V: Set maximum number of mapped pages correctly

Currently, maximum number of mapper pages are set to the pfn calculated
from the memblock size of the memblock containing kernel. This will work
until that memblock spans the entire memory. However, it will be set to
a wrong value if there are multiple memblocks defined in kernel
(e.g. with efi runtime services).

Set the the maximum value to the pfn calculated from dram size.

Signed-off-by: Atish Patra <[email protected]>
---
arch/riscv/mm/init.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index bad60686d080..4021706aef81 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -147,9 +147,9 @@ void __init setup_bootmem(void)
/* Reserve from the start of the kernel to the end of the kernel */
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);

- set_max_mapnr(PFN_DOWN(mem_size));
max_pfn = PFN_DOWN(memblock_end_of_DRAM());
max_low_pfn = max_pfn;
+ set_max_mapnr(max_low_pfn);

#ifdef CONFIG_BLK_DEV_INITRD
setup_initrd();
--
2.24.0

2020-07-06 17:30:24

by Atish Patra

[permalink] [raw]
Subject: [RFC PATCH v2 11/11] RISC-V: Add EFI runtime services

This patch adds EFI runtime service support for RISC-V.

Signed-off-by: Atish Patra <[email protected]>
---
arch/riscv/Kconfig | 2 +
arch/riscv/include/asm/efi.h | 20 ++++
arch/riscv/include/asm/mmu.h | 2 +
arch/riscv/include/asm/pgalloc.h | 12 ++
arch/riscv/include/asm/pgtable.h | 4 +
arch/riscv/kernel/Makefile | 1 +
arch/riscv/kernel/efi.c | 106 ++++++++++++++++++
arch/riscv/kernel/setup.c | 7 +-
arch/riscv/mm/init.c | 2 +-
drivers/firmware/efi/Makefile | 2 +
drivers/firmware/efi/libstub/efi-stub.c | 11 +-
drivers/firmware/efi/riscv-runtime.c | 141 ++++++++++++++++++++++++
12 files changed, 306 insertions(+), 4 deletions(-)
create mode 100644 arch/riscv/kernel/efi.c
create mode 100644 drivers/firmware/efi/riscv-runtime.c

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index a902e98048a1..601e8b873628 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -399,7 +399,9 @@ config EFI
select EFI_PARAMS_FROM_FDT
select EFI_STUB
select EFI_GENERIC_STUB
+ select EFI_RUNTIME_WRAPPERS
select RISCV_ISA_C
+ depends on MMU
default y
help
This option provides support for runtime services provided
diff --git a/arch/riscv/include/asm/efi.h b/arch/riscv/include/asm/efi.h
index 86da231909bb..93c305a638f4 100644
--- a/arch/riscv/include/asm/efi.h
+++ b/arch/riscv/include/asm/efi.h
@@ -5,11 +5,28 @@
#ifndef _ASM_EFI_H
#define _ASM_EFI_H

+#include <asm/csr.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/ptrace.h>
#include <asm/tlbflush.h>

+#ifdef CONFIG_EFI
+extern void efi_init(void);
+#else
+#define efi_init()
+#endif
+
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
+
+#define arch_efi_call_virt_setup() efi_virtmap_load()
+#define arch_efi_call_virt_teardown() efi_virtmap_unload()
+
+#define arch_efi_call_virt(p, f, args...) p->f(args)
+
+#define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
+
/* 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)
{
@@ -33,4 +50,7 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}

+void efi_virtmap_load(void);
+void efi_virtmap_unload(void);
+
#endif /* _ASM_EFI_H */
diff --git a/arch/riscv/include/asm/mmu.h b/arch/riscv/include/asm/mmu.h
index 967eacb01ab5..dabcf2cfb3dc 100644
--- a/arch/riscv/include/asm/mmu.h
+++ b/arch/riscv/include/asm/mmu.h
@@ -20,6 +20,8 @@ typedef struct {
#endif
} mm_context_t;

+void __init create_pgd_mapping(pgd_t *pgdp, uintptr_t va, phys_addr_t pa,
+ phys_addr_t sz, pgprot_t prot);
#endif /* __ASSEMBLY__ */

#endif /* _ASM_RISCV_MMU_H */
diff --git a/arch/riscv/include/asm/pgalloc.h b/arch/riscv/include/asm/pgalloc.h
index 3f601ee8233f..ad567bf0fb84 100644
--- a/arch/riscv/include/asm/pgalloc.h
+++ b/arch/riscv/include/asm/pgalloc.h
@@ -40,6 +40,18 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)

#define pmd_pgtable(pmd) pmd_page(pmd)

+static inline pgd_t *pgd_alloc_nomap(struct mm_struct *mm)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
+ if (likely(pgd != NULL))
+ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
+
+ return pgd;
+}
+
+
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *pgd;
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index eaea1f717010..d53ef48768ae 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -100,6 +100,10 @@

#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
+#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
+#define PAGE_KERNEL_READ_EXEC __pgprot((_PAGE_KERNEL & ~_PAGE_WRITE) \
+ | _PAGE_EXEC)

#define PAGE_TABLE __pgprot(_PAGE_TABLE)

diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 6f7a3b3771fd..239c44c451b6 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -36,6 +36,7 @@ OBJCOPYFLAGS := --prefix-symbols=__efistub_
$(obj)/%.stub.o: $(obj)/%.o FORCE
$(call if_changed,objcopy)

+obj-$(CONFIG_EFI) += efi.o
obj-$(CONFIG_FPU) += fpu.o
obj-$(CONFIG_SMP) += smpboot.o
obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c
new file mode 100644
index 000000000000..d6c0b733f3d1
--- /dev/null
+++ b/arch/riscv/kernel/efi.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ * Adapted from arch/arm64/kernel/efi.c
+ */
+
+#include <linux/efi.h>
+#include <linux/init.h>
+
+#include <asm/efi.h>
+#include <asm/pgtable.h>
+#include <asm/pgtable-bits.h>
+
+/*
+ * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
+ * executable, everything else can be mapped with the XN bits
+ * set. Also take the new (optional) RO/XP bits into account.
+ */
+static __init pgprot_t efimem_to_pgprot_map(efi_memory_desc_t *md)
+{
+ u64 attr = md->attribute;
+ u32 type = md->type;
+
+ if (type == EFI_MEMORY_MAPPED_IO)
+ return PAGE_KERNEL;
+
+ if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr),
+ "UEFI Runtime regions are not aligned to page size -- buggy firmware?"))
+ /*
+ * If the region is not aligned to the page size of the OS, we
+ * can not use strict permissions, since that would also affect
+ * the mapping attributes of the adjacent regions.
+ */
+ return PAGE_EXEC;
+
+ /* R-- */
+ if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
+ (EFI_MEMORY_XP | EFI_MEMORY_RO))
+ return PAGE_KERNEL_READ;
+
+ /* R-X */
+ if (attr & EFI_MEMORY_RO)
+ return PAGE_KERNEL_READ_EXEC;
+
+ /* RW- */
+ if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) ==
+ EFI_MEMORY_XP) ||
+ type != EFI_RUNTIME_SERVICES_CODE)
+ return PAGE_KERNEL;
+
+ /* RWX */
+ return PAGE_KERNEL_EXEC;
+}
+
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
+{
+ pgprot_t prot = __pgprot(pgprot_val(efimem_to_pgprot_map(md)) &
+ ~(_PAGE_GLOBAL));
+ int i;
+
+ /* RISC-V maps one page at a time */
+ for (i = 0; i <= md->num_pages; i++)
+ create_pgd_mapping(mm->pgd, md->virt_addr + i * PAGE_SIZE,
+ md->phys_addr + i * PAGE_SIZE,
+ PAGE_SIZE, prot);
+ return 0;
+}
+
+static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
+{
+ efi_memory_desc_t *md = data;
+ pte_t pte = READ_ONCE(*ptep);
+ unsigned long val;
+
+ if (md->attribute & EFI_MEMORY_RO) {
+ val = pte_val(pte) & ~_PAGE_WRITE;
+ val = pte_val(pte) | _PAGE_READ;
+ pte = __pte(val);
+ }
+ if (md->attribute & EFI_MEMORY_XP) {
+ val = pte_val(pte) & ~_PAGE_EXEC;
+ pte = __pte(val);
+ }
+ set_pte(ptep, pte);
+
+ return 0;
+}
+
+int __init efi_set_mapping_permissions(struct mm_struct *mm,
+ efi_memory_desc_t *md)
+{
+ BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
+ md->type != EFI_RUNTIME_SERVICES_DATA);
+
+ /*
+ * Calling apply_to_page_range() is only safe on regions that are
+ * guaranteed to be mapped down to pages. Since we are only called
+ * for regions that have been mapped using efi_create_mapping() above
+ * (and this is checked by the generic Memory Attributes table parsing
+ * routines), there is no need to check that again here.
+ */
+ return apply_to_page_range(mm, md->virt_addr,
+ md->num_pages << EFI_PAGE_SHIFT,
+ set_permissions, md);
+}
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 1244b433fe7c..0a725bd8d73e 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -17,6 +17,7 @@
#include <linux/sched/task.h>
#include <linux/swiotlb.h>
#include <linux/smp.h>
+#include <linux/efi.h>

#include <asm/clint.h>
#include <asm/cpu_ops.h>
@@ -26,11 +27,12 @@
#include <asm/tlbflush.h>
#include <asm/thread_info.h>
#include <asm/kasan.h>
+#include <asm/efi.h>

#include "head.h"

-#ifdef CONFIG_DUMMY_CONSOLE
-struct screen_info screen_info = {
+#if defined(CONFIG_DUMMY_CONSOLE) || defined(CONFIG_EFI)
+struct screen_info screen_info __section(.data) = {
.orig_video_lines = 30,
.orig_video_cols = 80,
.orig_video_mode = 0,
@@ -75,6 +77,7 @@ void __init setup_arch(char **cmdline_p)
early_ioremap_setup();
parse_early_param();

+ efi_init();
setup_bootmem();
paging_init();
unflatten_and_copy_device_tree();
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index c5268fe6e6de..eab96ed24065 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -319,7 +319,7 @@ static void __init create_pmd_mapping(pmd_t *pmdp,
#define fixmap_pgd_next fixmap_pte
#endif

-static void __init create_pgd_mapping(pgd_t *pgdp,
+void __init create_pgd_mapping(pgd_t *pgdp,
uintptr_t va, phys_addr_t pa,
phys_addr_t sz, pgprot_t prot)
{
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index 61fd1e8b26fb..4d628081bb2f 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -35,6 +35,8 @@ fake_map-$(CONFIG_X86) += x86_fake_mem.o
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
obj-$(CONFIG_ARM) += $(arm-obj-y)
obj-$(CONFIG_ARM64) += $(arm-obj-y)
+riscv-obj-$(CONFIG_EFI) := efi-init.o riscv-runtime.o
+obj-$(CONFIG_RISCV) += $(riscv-obj-y)
obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o
obj-$(CONFIG_EFI_EARLYCON) += earlycon.o
obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index a5a405d8ab44..5c26725d8fd0 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -17,7 +17,10 @@

/*
* This is the base address at which to start allocating virtual memory ranges
- * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use
+ * for UEFI Runtime Services.
+ *
+ * For ARM/ARM64:
+ * This is in the low TTBR0 range so that we can use
* any allocation we choose, and eliminate the risk of a conflict after kexec.
* The value chosen is the largest non-zero power of 2 suitable for this purpose
* both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
@@ -25,6 +28,12 @@
* Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
* map everything below 1 GB. (512 MB is a reasonable upper bound for the
* entire footprint of the UEFI runtime services memory regions)
+ *
+ * For RISC-V:
+ * There is no specific reason for which, this address (512MB) can't be used
+ * EFI runtime virtual address for RISC-V. It also helps to use EFI runtime
+ * services on both RV32/RV64. Keep the same runtime virtual address for RISC-V
+ * as well to minimize the code churn.
*/
#define EFI_RT_VIRTUAL_BASE SZ_512M
#define EFI_RT_VIRTUAL_SIZE SZ_512M
diff --git a/drivers/firmware/efi/riscv-runtime.c b/drivers/firmware/efi/riscv-runtime.c
new file mode 100644
index 000000000000..3bc48a268f66
--- /dev/null
+++ b/drivers/firmware/efi/riscv-runtime.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013, 2014 Linaro Ltd.
+ */
+
+#include <linux/dmi.h>
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/preempt.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/pgtable.h>
+
+#include <asm/cacheflush.h>
+#include <asm/efi.h>
+#include <asm/mmu.h>
+#include <asm/pgalloc.h>
+
+static bool __init efi_virtmap_init(void)
+{
+ efi_memory_desc_t *md;
+
+ efi_mm.pgd = pgd_alloc_nomap(&efi_mm);
+ mm_init_cpumask(&efi_mm);
+ init_new_context(NULL, &efi_mm);
+
+ for_each_efi_memory_desc(md) {
+ phys_addr_t phys = md->phys_addr;
+ int ret;
+
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+ if (md->virt_addr == 0)
+ return false;
+
+ ret = efi_create_mapping(&efi_mm, md);
+ if (ret) {
+ pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
+ &phys, ret);
+ return false;
+ }
+ }
+
+ if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
+ return false;
+
+ return true;
+}
+
+/*
+ * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
+ * non-early mapping of the UEFI system table and virtual mappings for all
+ * EFI_MEMORY_RUNTIME regions.
+ */
+static int __init riscv_enable_runtime_services(void)
+{
+ u64 mapsize;
+
+ if (!efi_enabled(EFI_BOOT)) {
+ pr_info("EFI services will not be available.\n");
+ return 0;
+ }
+
+ efi_memmap_unmap();
+
+ mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
+
+ if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
+ pr_err("Failed to remap EFI memory map\n");
+ return 0;
+ }
+
+ if (efi_soft_reserve_enabled()) {
+ efi_memory_desc_t *md;
+
+ for_each_efi_memory_desc(md) {
+ int md_size = md->num_pages << EFI_PAGE_SHIFT;
+ struct resource *res;
+
+ if (!(md->attribute & EFI_MEMORY_SP))
+ continue;
+
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (WARN_ON(!res))
+ break;
+
+ res->start = md->phys_addr;
+ res->end = md->phys_addr + md_size - 1;
+ res->name = "Soft Reserved";
+ res->flags = IORESOURCE_MEM;
+ res->desc = IORES_DESC_SOFT_RESERVED;
+
+ insert_resource(&iomem_resource, res);
+ }
+ }
+
+ if (efi_runtime_disabled()) {
+ pr_info("EFI runtime services will be disabled.\n");
+ return 0;
+ }
+
+ if (efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_info("EFI runtime services access via paravirt.\n");
+ return 0;
+ }
+
+ pr_info("Remapping and enabling EFI services.\n");
+
+ if (!efi_virtmap_init()) {
+ pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
+ return -ENOMEM;
+ }
+
+ /* Set up runtime services function pointers */
+ efi_native_runtime_setup();
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
+ return 0;
+}
+early_initcall(riscv_enable_runtime_services);
+
+void efi_virtmap_load(void)
+{
+ preempt_disable();
+ switch_mm(&efi_mm, current->active_mm, NULL);
+}
+
+void efi_virtmap_unload(void)
+{
+ switch_mm(current->active_mm, &efi_mm, NULL);
+ preempt_enable();
+}
--
2.24.0

2020-07-06 17:31:22

by Atish Patra

[permalink] [raw]
Subject: [RFC PATCH v2 01/11] efi/libstub: Move the function prototypes to header file

The prototype of the functions handle_kernel_image & efi_enter_kernel
are defined in efi-stub.c which may result in a compiler warnings if
-Wmissing-prototypes is set in gcc compiler.

Move the prototype to efistub.h to make the compiler happy.

Signed-off-by: Atish Patra <[email protected]>
---
drivers/firmware/efi/libstub/efi-stub.c | 17 -----------------
drivers/firmware/efi/libstub/efistub.h | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 3318ec3f8e5b..a5a405d8ab44 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -121,23 +121,6 @@ static unsigned long get_dram_base(void)
return membase;
}

-/*
- * This function handles the architcture specific differences between arm and
- * arm64 regarding where the kernel image must be loaded and any memory that
- * must be reserved. On failure it is required to free all
- * all allocations it has made.
- */
-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);
-
-asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
- unsigned long fdt_addr,
- unsigned long fdt_size);
-
/*
* EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
* that is described in the PE/COFF header. Most of the code is the same
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 2c9d42264c29..85050f5a1b28 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -776,6 +776,22 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
unsigned long *load_size,
unsigned long soft_limit,
unsigned long hard_limit);
+/*
+ * This function handles the architcture specific differences between arm and
+ * arm64 regarding where the kernel image must be loaded and any memory that
+ * must be reserved. On failure it is required to free all
+ * all allocations it has made.
+ */
+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);
+
+asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
+ unsigned long fdt_addr,
+ unsigned long fdt_size);

void efi_handle_post_ebs_state(void);

--
2.24.0

2020-07-07 06:45:12

by Ard Biesheuvel

[permalink] [raw]
Subject: Re: [RFC PATCH v2 00/11] Add UEFI support for RISC-V

On Mon, 6 Jul 2020 at 20:26, Atish Patra <[email protected]> wrote:
>
> This series adds UEFI support for RISC-V.
>
> Linux kernel: 5.8-rc4
> U-Boot: master
> OpenSBI: master
>
> Patch 1-6 are preparatory patches that fixes some of the geric efi and riscv issues.
>
> Patch 7-9 adds the efi stub support for RISC-V which was reviewed few months back.
> https://www.spinics.net/lists/linux-efi/msg19144.html
>
> Patch 10 just renames arm-init code so that it can be used across different
> architectures. Patch 11 adds the runtime services for RISC-V.
>
> The patches can also be found in following git repo.
> https://github.com/atishp04/linux/tree/uefi_riscv_5.9_v2
>
> The patches have been verified on Qemu using bootefi command in U-Boot for both
> RV32 and RV64.
>
> For RV32, maximum allocated memory should be 1G as RISC-V kernel can not map
> beyond 1G of physical memory for RV32.
>
> EDK2 can boot quite far into Linux with current series. Currently, we are seeing
> some traps from drivers (spi/network). At first glance, they don't seem to be
> caused by efi. I thought it is better to get some early feedback on the series
> while EDK2 issue is being debugged.
>
> That's why uefi runtime services are not actually well tested in RISC-V.
> Any suggestions to test the efi run time services are appreciated.
>
> Changes from v1->v2:
> 1. Removed patch 1 as it is already taken into efi-tree.
> 2. Fixed compilation issues with patch 9.
> 3. Moved few function prototype declaration to header file to keep kbuild happy.
>
> Changes from previous version:
> 1. Added full ioremap support.
> 2. Added efi runtime services support.
> 3. Fixes mm issues
>

Hi Atish,

This all looks reasonable to me, so I think we can merge this once you
can confirm that the runtime services actually work.

Could you explain how you are dealing with the memory map? Are memory
nodes in DT ignored entirely as they should be? What about memory
reservations?

In any case, I will take the first patch as a fix, so it should turn
up in mainline in 1~2 weeks.

Thanks,
Ard.

2020-07-07 07:50:35

by Atish Patra

[permalink] [raw]
Subject: Re: [RFC PATCH v2 00/11] Add UEFI support for RISC-V

On Mon, Jul 6, 2020 at 11:41 PM Ard Biesheuvel <[email protected]> wrote:
>
> On Mon, 6 Jul 2020 at 20:26, Atish Patra <[email protected]> wrote:
> >
> > This series adds UEFI support for RISC-V.
> >
> > Linux kernel: 5.8-rc4
> > U-Boot: master
> > OpenSBI: master
> >
> > Patch 1-6 are preparatory patches that fixes some of the geric efi and riscv issues.
> >
> > Patch 7-9 adds the efi stub support for RISC-V which was reviewed few months back.
> > https://www.spinics.net/lists/linux-efi/msg19144.html
> >
> > Patch 10 just renames arm-init code so that it can be used across different
> > architectures. Patch 11 adds the runtime services for RISC-V.
> >
> > The patches can also be found in following git repo.
> > https://github.com/atishp04/linux/tree/uefi_riscv_5.9_v2
> >
> > The patches have been verified on Qemu using bootefi command in U-Boot for both
> > RV32 and RV64.
> >
> > For RV32, maximum allocated memory should be 1G as RISC-V kernel can not map
> > beyond 1G of physical memory for RV32.
> >
> > EDK2 can boot quite far into Linux with current series. Currently, we are seeing
> > some traps from drivers (spi/network). At first glance, they don't seem to be
> > caused by efi. I thought it is better to get some early feedback on the series
> > while EDK2 issue is being debugged.
> >
> > That's why uefi runtime services are not actually well tested in RISC-V.
> > Any suggestions to test the efi run time services are appreciated.
> >
> > Changes from v1->v2:
> > 1. Removed patch 1 as it is already taken into efi-tree.
> > 2. Fixed compilation issues with patch 9.
> > 3. Moved few function prototype declaration to header file to keep kbuild happy.
> >
> > Changes from previous version:
> > 1. Added full ioremap support.
> > 2. Added efi runtime services support.
> > 3. Fixes mm issues
> >
>
> Hi Atish,
>
> This all looks reasonable to me, so I think we can merge this once you
> can confirm that the runtime services actually work.
>

Blibbet pointed me towards the Firmware Test Suite (FWTS). I will try
to use that to verify basic runtime services
in addition to EDK2 testing (Abner is debugging that).

> Could you explain how you are dealing with the memory map? Are memory
> nodes in DT ignored entirely as they should be?

Yes. That is handled by the generic code (patch 10 renames arm-init to
efi-init) in the following path.
setup_arch->efi_init->reserve_regions()

What about memory
> reservations?
>

I added patches in U-Boot that parses the /reserved-memory nodes from
DT and add it to the efi reserved mappings.
As a result, Linux kernel takes care of memory reservations as per the
reserved memory regions present in efi memory map.
I am expecting EDK2 already does that as well.

Here is the relevant boot log:
----------------------------------------------------------------------------------------------------------------------
[ 0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000

[ 0.000000] earlycon: sbi0 at I/O port 0x0 (options '')

[ 0.000000] printk: bootconsole [sbi0] enabled

[ 0.000000] efi: Getting UEFI parameters from /chosen in DT:

[ 0.000000] efi: System Table : 0x00000000bff61528

[ 0.000000] efi: MemMap Address : 0x00000000bd46e020

[ 0.000000] efi: MemMap Size : 0x00000000000002d0

[ 0.000000] efi: MemMap Desc. Size : 0x0000000000000028

[ 0.000000] efi: MemMap Desc. Version : 0x0000000000000001

[ 0.000000] efi: EFI v2.80 by Das U-Boot

[ 0.000000] efi: RTPROP=0xbe73c020 SMBIOS=0xbe736000 MEMRESERVE=0xbd671020

[ 0.000000] memblock_reserve:
[0x00000000bd671020-0x00000000bd67102f]
efi_config_parse_tables+0x192/0x1e6

[ 0.000000] efi: Processing EFI memory map:

[ 0.000000] MEMBLOCK configuration:

[ 0.000000] memory size = 0x000000003fe00000 reserved size =
0x0000000000000010

[ 0.000000] memory.cnt = 0x1

[ 0.000000] memory[0x0] [0x0000000080200000-0x00000000bfffffff],
0x000000003fe00000 bytes flags: 0x0

[ 0.000000] reserved.cnt = 0x1

[ 0.000000] reserved[0x0] [0x00000000bd671020-0x00000000bd67102f],
0x0000000000000010 bytes flags: 0x0

[ 0.000000] memblock_remove:
[0x0000000000000000-0xfffffffffffffffe] reserve_regions+0x56/0x134

[ 0.000000] efi: 0x000080000000-0x00008003ffff [Reserved
| | | | | | | | | |WB| | | ]

[ 0.000000] OF: fdt: Ignoring memory block 0x80000000 - 0x80040000

[ 0.000000] efi: 0x000080040000-0x0000801fffff [Conventional
Memory| | | | | | | | | |WB| | | ]

[ 0.000000] OF: fdt: Ignoring memory range 0x80040000 - 0x80200000

[ 0.000000] memblock_add: [0x0000000080200000-0x00000000801fffff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x000080200000-0x0000812befff [Loader Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x0000000080200000-0x00000000812befff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000812bf000-0x000087efffff [Conventional
Memory| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000812bf000-0x0000000087efffff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x000087f00000-0x000087f04fff [ACPI Reclaim
Memory| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x0000000087f00000-0x0000000087f04fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] memblock_reserve:
[0x0000000087f00000-0x0000000087f04fff] reserve_regions+0x110/0x134

[ 0.000000] efi: 0x000087f05000-0x0000bd46dfff [Conventional
Memory| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x0000000087f05000-0x00000000bd46dfff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000bd46e000-0x0000bd672fff [Loader Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000bd46e000-0x00000000bd672fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000bd673000-0x0000be731fff [Loader Code
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000bd673000-0x00000000be731fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be732000-0x0000be734fff [Reserved
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be732000-0x00000000be734fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be735000-0x0000be735fff [Boot Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be735000-0x00000000be735fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be736000-0x0000be736fff [Runtime Data
|RUN| | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be736000-0x00000000be736fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be737000-0x0000be738fff [Boot Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be737000-0x00000000be738fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be739000-0x0000be739fff [Reserved
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be739000-0x00000000be739fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be73a000-0x0000be73bfff [Boot Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be73a000-0x00000000be73bfff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be73c000-0x0000be73dfff [Runtime Data
|RUN| | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be73c000-0x00000000be73dfff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000be73e000-0x0000bff60fff [Loader Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000be73e000-0x00000000bff60fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000bff61000-0x0000bff61fff [Runtime Code
|RUN| | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000bff61000-0x00000000bff61fff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] efi: 0x0000bff62000-0x0000bfffffff [Loader Data
| | | | | | | | | |WB| | | ]

[ 0.000000] memblock_add: [0x00000000bff62000-0x00000000bfffffff]
early_init_dt_add_memory_arch+0xac/0xbc

[ 0.000000] memblock_reserve:
[0x00000000bd46e000-0x00000000bd46efff] efi_init+0x132/0x1e6

[ 0.000000] memblock_reserve:
[0x0000000080200000-0x00000000812befff] setup_bootmem+0x98/0x1d0

[ 0.000000] initrd not found or empty - disabling initrd

[ 0.000000] memblock_reserve:
[0x0000000080233000-0x00000000802348f7]
early_init_dt_reserve_memory_arch+0x14/0x1c

[ 0.000000] memblock_reserve:
[0x0000000080000000-0x000000008003ffff]
early_init_dt_reserve_memory_arch+0x14/0x1c

[ 0.000000] MEMBLOCK configuration:

[ 0.000000] memory size = 0x000000003fe00000 reserved size =
0x0000000001105010

[ 0.000000] memory.cnt = 0xb

[ 0.000000] memory[0x0] [0x0000000080200000-0x00000000be731fff],
0x000000003e532000 bytes flags: 0x0

[ 0.000000] memory[0x1] [0x00000000be732000-0x00000000be734fff],
0x0000000000003000 bytes flags: 0x4

[ 0.000000] memory[0x2] [0x00000000be735000-0x00000000be735fff],
0x0000000000001000 bytes flags: 0x0

[ 0.000000] memory[0x3] [0x00000000be736000-0x00000000be736fff],
0x0000000000001000 bytes flags: 0x4

[ 0.000000] memory[0x4] [0x00000000be737000-0x00000000be738fff],
0x0000000000002000 bytes flags: 0x0

[ 0.000000] memory[0x5] [0x00000000be739000-0x00000000be739fff],
0x0000000000001000 bytes flags: 0x4

[ 0.000000] memory[0x6] [0x00000000be73a000-0x00000000be73bfff],
0x0000000000002000 bytes flags: 0x0

[ 0.000000] memory[0x7] [0x00000000be73c000-0x00000000be73dfff],
0x0000000000002000 bytes flags: 0x4

[ 0.000000] memory[0x8] [0x00000000be73e000-0x00000000bff60fff],
0x0000000001823000 bytes flags: 0x0

[ 0.000000] memory[0x9] [0x00000000bff61000-0x00000000bff61fff],
0x0000000000001000 bytes flags: 0x4

[ 0.000000] memory[0xa] [0x00000000bff62000-0x00000000bfffffff],
0x000000000009e000 bytes flags: 0x0

[ 0.000000] reserved.cnt = 0x5

[ 0.000000] reserved[0x0] [0x0000000080000000-0x000000008003ffff],
0x0000000000040000 bytes flags: 0x0

[ 0.000000] reserved[0x1] [0x0000000080200000-0x00000000812befff],
0x00000000010bf000 bytes flags: 0x0

[ 0.000000] reserved[0x2] [0x0000000087f00000-0x0000000087f04fff],
0x0000000000005000 bytes flags: 0x0

[ 0.000000] reserved[0x3] [0x00000000bd46e000-0x00000000bd46efff],
0x0000000000001000 bytes flags: 0x0

[ 0.000000] reserved[0x4] [0x00000000bd671020-0x00000000bd67102f],
0x0000000000000010 bytes flags: 0x0

----------------------------------------------------------------------------------------------------------------------

Here is the detailed boot log.

https://pastebin.com/4LE2SY4c

> In any case, I will take the first patch as a fix, so it should turn
> up in mainline in 1~2 weeks.
>
Thanks.

> Thanks,
> Ard.



--
Regards,
Atish

Subject: [tip: efi/urgent] efi/libstub: Move the function prototypes to header file

The following commit has been merged into the efi/urgent branch of tip:

Commit-ID: 3230d95cea0515a6acf3f5ff360663de4c40fd07
Gitweb: https://git.kernel.org/tip/3230d95cea0515a6acf3f5ff360663de4c40fd07
Author: Atish Patra <[email protected]>
AuthorDate: Mon, 06 Jul 2020 10:25:59 -07:00
Committer: Ard Biesheuvel <[email protected]>
CommitterDate: Thu, 09 Jul 2020 09:45:09 +03:00

efi/libstub: Move the function prototypes to header file

The prototype of the functions handle_kernel_image & efi_enter_kernel
are defined in efi-stub.c which may result in a compiler warnings if
-Wmissing-prototypes is set in gcc compiler.

Move the prototype to efistub.h to make the compiler happy.

Signed-off-by: Atish Patra <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Ard Biesheuvel <[email protected]>
---
drivers/firmware/efi/libstub/efi-stub.c | 17 -----------------
drivers/firmware/efi/libstub/efistub.h | 16 ++++++++++++++++
2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index 3318ec3..a5a405d 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -122,23 +122,6 @@ static unsigned long get_dram_base(void)
}

/*
- * This function handles the architcture specific differences between arm and
- * arm64 regarding where the kernel image must be loaded and any memory that
- * must be reserved. On failure it is required to free all
- * all allocations it has made.
- */
-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);
-
-asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
- unsigned long fdt_addr,
- unsigned long fdt_size);
-
-/*
* EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
* that is described in the PE/COFF header. Most of the code is the same
* for both archictectures, with the arch-specific code provided in the
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 2c9d422..85050f5 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -776,6 +776,22 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
unsigned long *load_size,
unsigned long soft_limit,
unsigned long hard_limit);
+/*
+ * This function handles the architcture specific differences between arm and
+ * arm64 regarding where the kernel image must be loaded and any memory that
+ * must be reserved. On failure it is required to free all
+ * all allocations it has made.
+ */
+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);
+
+asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
+ unsigned long fdt_addr,
+ unsigned long fdt_size);

void efi_handle_post_ebs_state(void);