Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/kboot/libkboot/efi.c
34870 views
1
/*
2
* Copyright (c) 2024 Netflix, Inc
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
#include <sys/param.h>
8
#include <sys/linker.h>
9
#include "stand.h"
10
#include "bootstrap.h"
11
#include "efi.h"
12
#include "seg.h"
13
#include "util.h"
14
15
vm_paddr_t efi_systbl_phys;
16
struct efi_map_header *efi_map_hdr;
17
uint32_t efi_map_size;
18
vm_paddr_t efi_map_phys_src; /* From DTB */
19
vm_paddr_t efi_map_phys_dst; /* From our memory map metadata module */
20
21
void
22
efi_set_systbl(uint64_t tbl)
23
{
24
efi_systbl_phys = tbl;
25
}
26
27
#if 0
28
/* Note: This is useless since runtime-map is a subset */
29
void
30
efi_read_from_sysfs(void)
31
{
32
uint32_t efisz, sz, map_size;
33
int entries = 0;
34
struct efi_md *map; /* Really an array */
35
char *buf;
36
struct stat sb;
37
char fn[100];
38
39
/*
40
* Count the number of entries we have. They are numbered from 0
41
* through entries - 1.
42
*/
43
do {
44
printf("Looking at index %d\n", entries);
45
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", entries++);
46
} while (stat(fn, &sb) == 0);
47
48
/*
49
* We incremented entries one past the first failure, so we need to
50
* adjust the count and the test for 'nothing found' is against 1.
51
*/
52
if (entries == 1)
53
goto err;
54
entries--;
55
56
/* XXX lots of copied code, refactor? */
57
map_size = sizeof(struct efi_md) * entries;
58
efisz = roundup2(sizeof(*efi_map_hdr), 16);
59
sz = efisz + map_size;
60
buf = malloc(efisz + map_size);
61
if (buf == NULL)
62
return;
63
efi_map_hdr = (struct efi_map_header *)buf;
64
efi_map_size = sz;
65
map = (struct efi_md *)(buf + efisz);
66
bzero(map, sz);
67
efi_map_hdr->memory_size = map_size;
68
efi_map_hdr->descriptor_size = sizeof(struct efi_md);
69
efi_map_hdr->descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
70
for (int i = 0; i < entries; i++) {
71
struct efi_md *m;
72
73
printf("Populating index %d\n", i);
74
m = map + i;
75
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/type", i);
76
if (!file2u32(fn, &m->md_type))
77
goto err;
78
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", i);
79
if (!file2u64(fn, &m->md_phys))
80
goto err;
81
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/virt_addr", i);
82
if (!file2u64(fn, &m->md_virt))
83
goto err;
84
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/num_pages", i);
85
if (!file2u64(fn, &m->md_pages))
86
goto err;
87
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/attribute", i);
88
if (!file2u64(fn, &m->md_attr))
89
goto err;
90
}
91
efi_map_phys_src = 0;
92
printf("UEFI MAP:\n");
93
print_efi_map(efi_map_hdr);
94
printf("DONE\n");
95
return;
96
err:
97
printf("Parse error in reading current memory map\n");
98
}
99
#endif
100
101
/*
102
* We may have no ability to read the PA that this map is in, so pass
103
* the address to FreeBSD via a rather odd flag entry as the first map
104
* so early boot can copy the memory map into this space and have the
105
* rest of the code cope.
106
*/
107
bool
108
efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers)
109
{
110
uint32_t efisz, sz;
111
char *buf;
112
int fd2, len;
113
struct efi_md *map; /* Really an array */
114
115
/*
116
* We may have no ability to read the PA that this map is in, so pass
117
* the address to FreeBSD via a rather odd flag entry as the first map
118
* so early boot can copy the memory map into this space and have the
119
* rest of the code cope. We also have to round the size of the header
120
* to 16 byte boundary.
121
*/
122
efisz = roundup2(sizeof(*efi_map_hdr), 16);
123
sz = efisz + map_size;
124
buf = malloc(efisz + map_size);
125
if (buf == NULL)
126
return false;
127
efi_map_hdr = (struct efi_map_header *)buf;
128
efi_map_size = sz;
129
map = (struct efi_md *)(buf + efisz);
130
bzero(map, sz);
131
efi_map_hdr->memory_size = map_size;
132
efi_map_hdr->descriptor_size = desc_size;
133
efi_map_hdr->descriptor_version = vers;
134
135
/*
136
* Try to read in the actual UEFI map. This may fail, and that's OK. We just
137
* won't print the map.
138
*/
139
fd2 = open("host:/dev/mem", O_RDONLY);
140
if (fd2 < 0)
141
goto no_read;
142
if (lseek(fd2, pa, SEEK_SET) < 0)
143
goto no_read;
144
len = read(fd2, map, sz);
145
if (len != sz)
146
goto no_read;
147
efi_map_phys_src = 0; /* Mark MODINFOMD_EFI_MAP as valid */
148
close(fd2);
149
printf("UEFI MAP:\n");
150
print_efi_map(efi_map_hdr);
151
return (true);
152
153
no_read: /* Just get it the trampoline */
154
efi_map_phys_src = pa;
155
close(fd2);
156
return (true);
157
}
158
159
void
160
foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp)
161
{
162
struct efi_md *map, *p;
163
size_t efisz;
164
int ndesc, i;
165
166
/*
167
* Memory map data provided by UEFI via the GetMemoryMap
168
* Boot Services API.
169
*/
170
efisz = roundup2(sizeof(struct efi_map_header), 16);
171
map = (struct efi_md *)((uint8_t *)efihdr + efisz);
172
173
if (efihdr->descriptor_size == 0)
174
return;
175
ndesc = efihdr->memory_size / efihdr->descriptor_size;
176
177
for (i = 0, p = map; i < ndesc; i++,
178
p = efi_next_descriptor(p, efihdr->descriptor_size)) {
179
cb(p, argp);
180
}
181
}
182
183
/* XXX REFACTOR WITH KERNEL */
184
static void
185
print_efi_map_entry(struct efi_md *p, void *argp __unused)
186
{
187
const char *type;
188
static const char *types[] = {
189
"Reserved",
190
"LoaderCode",
191
"LoaderData",
192
"BootServicesCode",
193
"BootServicesData",
194
"RuntimeServicesCode",
195
"RuntimeServicesData",
196
"ConventionalMemory",
197
"UnusableMemory",
198
"ACPIReclaimMemory",
199
"ACPIMemoryNVS",
200
"MemoryMappedIO",
201
"MemoryMappedIOPortSpace",
202
"PalCode",
203
"PersistentMemory"
204
};
205
206
if (p->md_type < nitems(types))
207
type = types[p->md_type];
208
else
209
type = "<INVALID>";
210
printf("%23s %012lx %012lx %08lx ", type, p->md_phys,
211
p->md_virt, p->md_pages);
212
if (p->md_attr & EFI_MD_ATTR_UC)
213
printf("UC ");
214
if (p->md_attr & EFI_MD_ATTR_WC)
215
printf("WC ");
216
if (p->md_attr & EFI_MD_ATTR_WT)
217
printf("WT ");
218
if (p->md_attr & EFI_MD_ATTR_WB)
219
printf("WB ");
220
if (p->md_attr & EFI_MD_ATTR_UCE)
221
printf("UCE ");
222
if (p->md_attr & EFI_MD_ATTR_WP)
223
printf("WP ");
224
if (p->md_attr & EFI_MD_ATTR_RP)
225
printf("RP ");
226
if (p->md_attr & EFI_MD_ATTR_XP)
227
printf("XP ");
228
if (p->md_attr & EFI_MD_ATTR_NV)
229
printf("NV ");
230
if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
231
printf("MORE_RELIABLE ");
232
if (p->md_attr & EFI_MD_ATTR_RO)
233
printf("RO ");
234
if (p->md_attr & EFI_MD_ATTR_RT)
235
printf("RUNTIME");
236
printf("\n");
237
}
238
239
void
240
print_efi_map(struct efi_map_header *efihdr)
241
{
242
printf("%23s %12s %12s %8s %4s\n",
243
"Type", "Physical", "Virtual", "#Pages", "Attr");
244
245
foreach_efi_map_entry(efihdr, print_efi_map_entry, NULL);
246
}
247
248
void
249
efi_bi_loadsmap(struct preloaded_file *kfp)
250
{
251
/*
252
* Make a note of a systbl. This is nearly mandatory on AARCH64.
253
*/
254
if (efi_systbl_phys)
255
file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys);
256
257
/*
258
* If we have efi_map_hdr, then it's a pointer to the PA where this
259
* memory map lives. The trampoline code will copy it over. If we don't
260
* have it, panic because /proc/iomem isn't sufficient and there's no
261
* hope.
262
*/
263
if (efi_map_hdr != NULL) {
264
file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr);
265
return;
266
}
267
268
panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n");
269
}
270
271