Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/arm-runtime.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Extensible Firmware Interface
4
*
5
* Based on Extensible Firmware Interface Specification version 2.4
6
*
7
* Copyright (C) 2013, 2014 Linaro Ltd.
8
*/
9
10
#include <linux/dmi.h>
11
#include <linux/efi.h>
12
#include <linux/io.h>
13
#include <linux/memblock.h>
14
#include <linux/mm_types.h>
15
#include <linux/preempt.h>
16
#include <linux/rbtree.h>
17
#include <linux/rwsem.h>
18
#include <linux/sched.h>
19
#include <linux/slab.h>
20
#include <linux/spinlock.h>
21
#include <linux/pgtable.h>
22
23
#include <asm/cacheflush.h>
24
#include <asm/efi.h>
25
#include <asm/mmu.h>
26
#include <asm/pgalloc.h>
27
28
#if defined(CONFIG_PTDUMP_DEBUGFS) || defined(CONFIG_ARM_PTDUMP_DEBUGFS)
29
#include <asm/ptdump.h>
30
31
static struct ptdump_info efi_ptdump_info = {
32
.mm = &efi_mm,
33
.markers = (struct addr_marker[]){
34
{ 0, "UEFI runtime start" },
35
{ EFI_RUNTIME_MAP_END, "UEFI runtime end" },
36
{ -1, NULL }
37
},
38
.base_addr = 0,
39
};
40
41
static int __init ptdump_init(void)
42
{
43
if (efi_enabled(EFI_RUNTIME_SERVICES))
44
ptdump_debugfs_register(&efi_ptdump_info, "efi_page_tables");
45
46
return 0;
47
}
48
device_initcall(ptdump_init);
49
50
#endif
51
52
static bool __init efi_virtmap_init(void)
53
{
54
efi_memory_desc_t *md;
55
56
efi_mm.pgd = pgd_alloc(&efi_mm);
57
mm_init_cpumask(&efi_mm);
58
init_new_context(NULL, &efi_mm);
59
60
for_each_efi_memory_desc(md) {
61
phys_addr_t phys = md->phys_addr;
62
int ret;
63
64
if (!(md->attribute & EFI_MEMORY_RUNTIME))
65
continue;
66
if (md->virt_addr == U64_MAX)
67
return false;
68
69
ret = efi_create_mapping(&efi_mm, md);
70
if (ret) {
71
pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
72
&phys, ret);
73
return false;
74
}
75
}
76
77
if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
78
return false;
79
80
return true;
81
}
82
83
/*
84
* Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
85
* non-early mapping of the UEFI system table and virtual mappings for all
86
* EFI_MEMORY_RUNTIME regions.
87
*/
88
static int __init arm_enable_runtime_services(void)
89
{
90
u64 mapsize;
91
92
if (!efi_enabled(EFI_BOOT)) {
93
pr_info("EFI services will not be available.\n");
94
return 0;
95
}
96
97
efi_memmap_unmap();
98
99
mapsize = efi.memmap.desc_size * efi.memmap.nr_map;
100
101
if (efi_memmap_init_late(efi.memmap.phys_map, mapsize)) {
102
pr_err("Failed to remap EFI memory map\n");
103
return 0;
104
}
105
106
if (efi_soft_reserve_enabled()) {
107
efi_memory_desc_t *md;
108
109
for_each_efi_memory_desc(md) {
110
u64 md_size = md->num_pages << EFI_PAGE_SHIFT;
111
struct resource *res;
112
113
if (!(md->attribute & EFI_MEMORY_SP))
114
continue;
115
116
res = kzalloc(sizeof(*res), GFP_KERNEL);
117
if (WARN_ON(!res))
118
break;
119
120
res->start = md->phys_addr;
121
res->end = md->phys_addr + md_size - 1;
122
res->name = "Soft Reserved";
123
res->flags = IORESOURCE_MEM;
124
res->desc = IORES_DESC_SOFT_RESERVED;
125
126
insert_resource(&iomem_resource, res);
127
}
128
}
129
130
if (efi_runtime_disabled()) {
131
pr_info("EFI runtime services will be disabled.\n");
132
return 0;
133
}
134
135
if (efi_enabled(EFI_RUNTIME_SERVICES)) {
136
pr_info("EFI runtime services access via paravirt.\n");
137
return 0;
138
}
139
140
pr_info("Remapping and enabling EFI services.\n");
141
142
if (!efi_virtmap_init()) {
143
pr_err("UEFI virtual mapping missing or invalid -- runtime services will not be available\n");
144
return -ENOMEM;
145
}
146
147
/* Set up runtime services function pointers */
148
efi_native_runtime_setup();
149
set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
150
151
return 0;
152
}
153
early_initcall(arm_enable_runtime_services);
154
155
void efi_virtmap_load(void)
156
{
157
preempt_disable();
158
efi_set_pgd(&efi_mm);
159
}
160
161
void efi_virtmap_unload(void)
162
{
163
efi_set_pgd(current->active_mm);
164
preempt_enable();
165
}
166
167
168
static int __init arm_dmi_init(void)
169
{
170
/*
171
* On arm64/ARM, DMI depends on UEFI, and dmi_setup() needs to
172
* be called early because dmi_id_init(), which is an arch_initcall
173
* itself, depends on dmi_scan_machine() having been called already.
174
*/
175
dmi_setup();
176
return 0;
177
}
178
core_initcall(arm_dmi_init);
179
180