Skip to content

Commit b91540d

Browse files
atishp04palmer-dabbelt
authored andcommitted
RISC-V: Add EFI runtime services
This patch adds EFI runtime service support for RISC-V. Signed-off-by: Atish Patra <[email protected]> [ardb: - Remove the page check] Signed-off-by: Ard Biesheuvel <[email protected]> Acked-by: Ard Biesheuvel <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent d707174 commit b91540d

File tree

11 files changed

+287
-4
lines changed

11 files changed

+287
-4
lines changed

arch/riscv/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,9 @@ config EFI
412412
select EFI_PARAMS_FROM_FDT
413413
select EFI_STUB
414414
select EFI_GENERIC_STUB
415+
select EFI_RUNTIME_WRAPPERS
415416
select RISCV_ISA_C
417+
depends on MMU
416418
default y
417419
help
418420
This option provides support for runtime services provided

arch/riscv/include/asm/efi.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,28 @@
55
#ifndef _ASM_EFI_H
66
#define _ASM_EFI_H
77

8+
#include <asm/csr.h>
89
#include <asm/io.h>
910
#include <asm/mmu_context.h>
1011
#include <asm/ptrace.h>
1112
#include <asm/tlbflush.h>
1213

14+
#ifdef CONFIG_EFI
15+
extern void efi_init(void);
16+
#else
17+
#define efi_init()
18+
#endif
19+
20+
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
21+
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
22+
23+
#define arch_efi_call_virt_setup() efi_virtmap_load()
24+
#define arch_efi_call_virt_teardown() efi_virtmap_unload()
25+
26+
#define arch_efi_call_virt(p, f, args...) p->f(args)
27+
28+
#define ARCH_EFI_IRQ_FLAGS_MASK (SR_IE | SR_SPIE)
29+
1330
/* on RISC-V, the FDT may be located anywhere in system RAM */
1431
static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
1532
{
@@ -32,4 +49,7 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
3249
{
3350
}
3451

52+
void efi_virtmap_load(void);
53+
void efi_virtmap_unload(void);
54+
3555
#endif /* _ASM_EFI_H */

arch/riscv/include/asm/mmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ typedef struct {
2020
#endif
2121
} mm_context_t;
2222

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

2527
#endif /* _ASM_RISCV_MMU_H */

arch/riscv/include/asm/pgtable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@
100100

101101
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
102102
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
103+
#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
104+
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
105+
#define PAGE_KERNEL_READ_EXEC __pgprot((_PAGE_KERNEL & ~_PAGE_WRITE) \
106+
| _PAGE_EXEC)
103107

104108
#define PAGE_TABLE __pgprot(_PAGE_TABLE)
105109

arch/riscv/kernel/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,6 @@ obj-$(CONFIG_KGDB) += kgdb.o
5555

5656
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
5757

58+
obj-$(CONFIG_EFI) += efi.o
59+
5860
clean:

arch/riscv/kernel/efi.c

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2020 Western Digital Corporation or its affiliates.
4+
* Adapted from arch/arm64/kernel/efi.c
5+
*/
6+
7+
#include <linux/efi.h>
8+
#include <linux/init.h>
9+
10+
#include <asm/efi.h>
11+
#include <asm/pgtable.h>
12+
#include <asm/pgtable-bits.h>
13+
14+
/*
15+
* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
16+
* executable, everything else can be mapped with the XN bits
17+
* set. Also take the new (optional) RO/XP bits into account.
18+
*/
19+
static __init pgprot_t efimem_to_pgprot_map(efi_memory_desc_t *md)
20+
{
21+
u64 attr = md->attribute;
22+
u32 type = md->type;
23+
24+
if (type == EFI_MEMORY_MAPPED_IO)
25+
return PAGE_KERNEL;
26+
27+
/* R-- */
28+
if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
29+
(EFI_MEMORY_XP | EFI_MEMORY_RO))
30+
return PAGE_KERNEL_READ;
31+
32+
/* R-X */
33+
if (attr & EFI_MEMORY_RO)
34+
return PAGE_KERNEL_READ_EXEC;
35+
36+
/* RW- */
37+
if (((attr & (EFI_MEMORY_RP | EFI_MEMORY_WP | EFI_MEMORY_XP)) ==
38+
EFI_MEMORY_XP) ||
39+
type != EFI_RUNTIME_SERVICES_CODE)
40+
return PAGE_KERNEL;
41+
42+
/* RWX */
43+
return PAGE_KERNEL_EXEC;
44+
}
45+
46+
int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
47+
{
48+
pgprot_t prot = __pgprot(pgprot_val(efimem_to_pgprot_map(md)) &
49+
~(_PAGE_GLOBAL));
50+
int i;
51+
52+
/* RISC-V maps one page at a time */
53+
for (i = 0; i < md->num_pages; i++)
54+
create_pgd_mapping(mm->pgd, md->virt_addr + i * PAGE_SIZE,
55+
md->phys_addr + i * PAGE_SIZE,
56+
PAGE_SIZE, prot);
57+
return 0;
58+
}
59+
60+
static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
61+
{
62+
efi_memory_desc_t *md = data;
63+
pte_t pte = READ_ONCE(*ptep);
64+
unsigned long val;
65+
66+
if (md->attribute & EFI_MEMORY_RO) {
67+
val = pte_val(pte) & ~_PAGE_WRITE;
68+
val = pte_val(pte) | _PAGE_READ;
69+
pte = __pte(val);
70+
}
71+
if (md->attribute & EFI_MEMORY_XP) {
72+
val = pte_val(pte) & ~_PAGE_EXEC;
73+
pte = __pte(val);
74+
}
75+
set_pte(ptep, pte);
76+
77+
return 0;
78+
}
79+
80+
int __init efi_set_mapping_permissions(struct mm_struct *mm,
81+
efi_memory_desc_t *md)
82+
{
83+
BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
84+
md->type != EFI_RUNTIME_SERVICES_DATA);
85+
86+
/*
87+
* Calling apply_to_page_range() is only safe on regions that are
88+
* guaranteed to be mapped down to pages. Since we are only called
89+
* for regions that have been mapped using efi_create_mapping() above
90+
* (and this is checked by the generic Memory Attributes table parsing
91+
* routines), there is no need to check that again here.
92+
*/
93+
return apply_to_page_range(mm, md->virt_addr,
94+
md->num_pages << EFI_PAGE_SHIFT,
95+
set_permissions, md);
96+
}

arch/riscv/kernel/setup.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/sched/task.h>
1818
#include <linux/swiotlb.h>
1919
#include <linux/smp.h>
20+
#include <linux/efi.h>
2021

2122
#include <asm/cpu_ops.h>
2223
#include <asm/early_ioremap.h>
@@ -26,11 +27,12 @@
2627
#include <asm/tlbflush.h>
2728
#include <asm/thread_info.h>
2829
#include <asm/kasan.h>
30+
#include <asm/efi.h>
2931

3032
#include "head.h"
3133

32-
#ifdef CONFIG_DUMMY_CONSOLE
33-
struct screen_info screen_info = {
34+
#if defined(CONFIG_DUMMY_CONSOLE) || defined(CONFIG_EFI)
35+
struct screen_info screen_info __section(.data) = {
3436
.orig_video_lines = 30,
3537
.orig_video_cols = 80,
3638
.orig_video_mode = 0,
@@ -75,6 +77,7 @@ void __init setup_arch(char **cmdline_p)
7577
early_ioremap_setup();
7678
parse_early_param();
7779

80+
efi_init();
7881
setup_bootmem();
7982
paging_init();
8083
#if IS_ENABLED(CONFIG_BUILTIN_DTB)

arch/riscv/mm/init.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ static void __init create_pmd_mapping(pmd_t *pmdp,
390390
#define fixmap_pgd_next fixmap_pte
391391
#endif
392392

393-
static void __init create_pgd_mapping(pgd_t *pgdp,
393+
void __init create_pgd_mapping(pgd_t *pgdp,
394394
uintptr_t va, phys_addr_t pa,
395395
phys_addr_t sz, pgprot_t prot)
396396
{

drivers/firmware/efi/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ fake_map-$(CONFIG_X86) += x86_fake_mem.o
3535
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
3636
obj-$(CONFIG_ARM) += $(arm-obj-y)
3737
obj-$(CONFIG_ARM64) += $(arm-obj-y)
38+
riscv-obj-$(CONFIG_EFI) := efi-init.o riscv-runtime.o
39+
obj-$(CONFIG_RISCV) += $(riscv-obj-y)
3840
obj-$(CONFIG_EFI_CAPSULE_LOADER) += capsule-loader.o
3941
obj-$(CONFIG_EFI_EARLYCON) += earlycon.o
4042
obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o

drivers/firmware/efi/libstub/efi-stub.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,23 @@
1717

1818
/*
1919
* This is the base address at which to start allocating virtual memory ranges
20-
* for UEFI Runtime Services. This is in the low TTBR0 range so that we can use
20+
* for UEFI Runtime Services.
21+
*
22+
* For ARM/ARM64:
23+
* This is in the low TTBR0 range so that we can use
2124
* any allocation we choose, and eliminate the risk of a conflict after kexec.
2225
* The value chosen is the largest non-zero power of 2 suitable for this purpose
2326
* both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
2427
* be mapped efficiently.
2528
* Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
2629
* map everything below 1 GB. (512 MB is a reasonable upper bound for the
2730
* entire footprint of the UEFI runtime services memory regions)
31+
*
32+
* For RISC-V:
33+
* There is no specific reason for which, this address (512MB) can't be used
34+
* EFI runtime virtual address for RISC-V. It also helps to use EFI runtime
35+
* services on both RV32/RV64. Keep the same runtime virtual address for RISC-V
36+
* as well to minimize the code churn.
2837
*/
2938
#define EFI_RT_VIRTUAL_BASE SZ_512M
3039
#define EFI_RT_VIRTUAL_SIZE SZ_512M

0 commit comments

Comments
 (0)