xref: /openbmc/linux/drivers/firmware/efi/riscv-runtime.c (revision b91540d52a08b65eb6a2b09132e1bd54fa82754c)
1*b91540d5SAtish Patra // SPDX-License-Identifier: GPL-2.0
2*b91540d5SAtish Patra /*
3*b91540d5SAtish Patra  * Extensible Firmware Interface
4*b91540d5SAtish Patra  *
5*b91540d5SAtish Patra  * Copyright (C) 2020 Western Digital Corporation or its affiliates.
6*b91540d5SAtish Patra  *
7*b91540d5SAtish Patra  * Based on Extensible Firmware Interface Specification version 2.4
8*b91540d5SAtish Patra  * Adapted from drivers/firmware/efi/arm-runtime.c
9*b91540d5SAtish Patra  *
10*b91540d5SAtish Patra  */
11*b91540d5SAtish Patra 
12*b91540d5SAtish Patra #include <linux/dmi.h>
13*b91540d5SAtish Patra #include <linux/efi.h>
14*b91540d5SAtish Patra #include <linux/io.h>
15*b91540d5SAtish Patra #include <linux/memblock.h>
16*b91540d5SAtish Patra #include <linux/mm_types.h>
17*b91540d5SAtish Patra #include <linux/preempt.h>
18*b91540d5SAtish Patra #include <linux/rbtree.h>
19*b91540d5SAtish Patra #include <linux/rwsem.h>
20*b91540d5SAtish Patra #include <linux/sched.h>
21*b91540d5SAtish Patra #include <linux/slab.h>
22*b91540d5SAtish Patra #include <linux/spinlock.h>
23*b91540d5SAtish Patra #include <linux/pgtable.h>
24*b91540d5SAtish Patra 
25*b91540d5SAtish Patra #include <asm/cacheflush.h>
26*b91540d5SAtish Patra #include <asm/efi.h>
27*b91540d5SAtish Patra #include <asm/mmu.h>
28*b91540d5SAtish Patra #include <asm/pgalloc.h>
29*b91540d5SAtish Patra 
30*b91540d5SAtish Patra static bool __init efi_virtmap_init(void)
31*b91540d5SAtish Patra {
32*b91540d5SAtish Patra 	efi_memory_desc_t *md;
33*b91540d5SAtish Patra 
34*b91540d5SAtish Patra 	efi_mm.pgd = pgd_alloc(&efi_mm);
35*b91540d5SAtish Patra 	mm_init_cpumask(&efi_mm);
36*b91540d5SAtish Patra 	init_new_context(NULL, &efi_mm);
37*b91540d5SAtish Patra 
38*b91540d5SAtish Patra 	for_each_efi_memory_desc(md) {
39*b91540d5SAtish Patra 		phys_addr_t phys = md->phys_addr;
40*b91540d5SAtish Patra 		int ret;
41*b91540d5SAtish Patra 
42*b91540d5SAtish Patra 		if (!(md->attribute & EFI_MEMORY_RUNTIME))
43*b91540d5SAtish Patra 			continue;
44*b91540d5SAtish Patra 		if (md->virt_addr == 0)
45*b91540d5SAtish Patra 			return false;
46*b91540d5SAtish Patra 
47*b91540d5SAtish Patra 		ret = efi_create_mapping(&efi_mm, md);
48*b91540d5SAtish Patra 		if (ret) {
49*b91540d5SAtish Patra 			pr_warn("  EFI remap %pa: failed to create mapping (%d)\n",
50*b91540d5SAtish Patra 				&phys, ret);
51*b91540d5SAtish Patra 			return false;
52*b91540d5SAtish Patra 		}
53*b91540d5SAtish Patra 	}
54*b91540d5SAtish Patra 
55*b91540d5SAtish Patra 	if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
56*b91540d5SAtish Patra 		return false;
57*b91540d5SAtish Patra 
58*b91540d5SAtish Patra 	return true;
59*b91540d5SAtish Patra }
60*b91540d5SAtish Patra 
61*b91540d5SAtish Patra /*
62*b91540d5SAtish Patra  * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
63*b91540d5SAtish Patra  * non-early mapping of the UEFI system table and virtual mappings for all
64*b91540d5SAtish Patra  * EFI_MEMORY_RUNTIME regions.
65*b91540d5SAtish Patra  */
66*b91540d5SAtish Patra static int __init riscv_enable_runtime_services(void)
67*b91540d5SAtish Patra {
68*b91540d5SAtish Patra 	u64 mapsize;
69*b91540d5SAtish Patra 
70*b91540d5SAtish Patra 	if (!efi_enabled(EFI_BOOT)) {
71*b91540d5SAtish Patra 		pr_info("EFI services will not be available.\n");
72*b91540d5SAtish Patra 		return 0;
73*b91540d5SAtish Patra 	}
74*b91540d5SAtish Patra 
75*b91540d5SAtish Patra 	efi_memmap_unmap();
76*b91540d5SAtish Patra 
77*b91540d5SAtish Patra 	mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
78*b91540d5SAtish Patra 
79*b91540d5SAtish Patra 	if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
80*b91540d5SAtish Patra 		pr_err("Failed to remap EFI memory map\n");
81*b91540d5SAtish Patra 		return 0;
82*b91540d5SAtish Patra 	}
83*b91540d5SAtish Patra 
84*b91540d5SAtish Patra 	if (efi_soft_reserve_enabled()) {
85*b91540d5SAtish Patra 		efi_memory_desc_t *md;
86*b91540d5SAtish Patra 
87*b91540d5SAtish Patra 		for_each_efi_memory_desc(md) {
88*b91540d5SAtish Patra 			int md_size = md->num_pages << EFI_PAGE_SHIFT;
89*b91540d5SAtish Patra 			struct resource *res;
90*b91540d5SAtish Patra 
91*b91540d5SAtish Patra 			if (!(md->attribute & EFI_MEMORY_SP))
92*b91540d5SAtish Patra 				continue;
93*b91540d5SAtish Patra 
94*b91540d5SAtish Patra 			res = kzalloc(sizeof(*res), GFP_KERNEL);
95*b91540d5SAtish Patra 			if (WARN_ON(!res))
96*b91540d5SAtish Patra 				break;
97*b91540d5SAtish Patra 
98*b91540d5SAtish Patra 			res->start	= md->phys_addr;
99*b91540d5SAtish Patra 			res->end	= md->phys_addr + md_size - 1;
100*b91540d5SAtish Patra 			res->name	= "Soft Reserved";
101*b91540d5SAtish Patra 			res->flags	= IORESOURCE_MEM;
102*b91540d5SAtish Patra 			res->desc	= IORES_DESC_SOFT_RESERVED;
103*b91540d5SAtish Patra 
104*b91540d5SAtish Patra 			insert_resource(&iomem_resource, res);
105*b91540d5SAtish Patra 		}
106*b91540d5SAtish Patra 	}
107*b91540d5SAtish Patra 
108*b91540d5SAtish Patra 	if (efi_runtime_disabled()) {
109*b91540d5SAtish Patra 		pr_info("EFI runtime services will be disabled.\n");
110*b91540d5SAtish Patra 		return 0;
111*b91540d5SAtish Patra 	}
112*b91540d5SAtish Patra 
113*b91540d5SAtish Patra 	if (efi_enabled(EFI_RUNTIME_SERVICES)) {
114*b91540d5SAtish Patra 		pr_info("EFI runtime services access via paravirt.\n");
115*b91540d5SAtish Patra 		return 0;
116*b91540d5SAtish Patra 	}
117*b91540d5SAtish Patra 
118*b91540d5SAtish Patra 	pr_info("Remapping and enabling EFI services.\n");
119*b91540d5SAtish Patra 
120*b91540d5SAtish Patra 	if (!efi_virtmap_init()) {
121*b91540d5SAtish Patra 		pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
122*b91540d5SAtish Patra 		return -ENOMEM;
123*b91540d5SAtish Patra 	}
124*b91540d5SAtish Patra 
125*b91540d5SAtish Patra 	/* Set up runtime services function pointers */
126*b91540d5SAtish Patra 	efi_native_runtime_setup();
127*b91540d5SAtish Patra 	set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
128*b91540d5SAtish Patra 
129*b91540d5SAtish Patra 	return 0;
130*b91540d5SAtish Patra }
131*b91540d5SAtish Patra early_initcall(riscv_enable_runtime_services);
132*b91540d5SAtish Patra 
133*b91540d5SAtish Patra void efi_virtmap_load(void)
134*b91540d5SAtish Patra {
135*b91540d5SAtish Patra 	preempt_disable();
136*b91540d5SAtish Patra 	switch_mm(current->active_mm, &efi_mm, NULL);
137*b91540d5SAtish Patra }
138*b91540d5SAtish Patra 
139*b91540d5SAtish Patra void efi_virtmap_unload(void)
140*b91540d5SAtish Patra {
141*b91540d5SAtish Patra 	switch_mm(&efi_mm, current->active_mm, NULL);
142*b91540d5SAtish Patra 	preempt_enable();
143*b91540d5SAtish Patra }
144