efimemory.c revision 1.7 1 1.7 nonaka /* $NetBSD: efimemory.c,v 1.7 2019/07/29 11:28:51 nonaka Exp $ */
2 1.1 nonaka
3 1.1 nonaka /*-
4 1.1 nonaka * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
5 1.1 nonaka * All rights reserved.
6 1.1 nonaka *
7 1.1 nonaka * Redistribution and use in source and binary forms, with or without
8 1.1 nonaka * modification, are permitted provided that the following conditions
9 1.1 nonaka * are met:
10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright
11 1.1 nonaka * notice, this list of conditions and the following disclaimer.
12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the
14 1.1 nonaka * documentation and/or other materials provided with the distribution.
15 1.1 nonaka *
16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 nonaka * SUCH DAMAGE.
27 1.1 nonaka */
28 1.1 nonaka
29 1.1 nonaka #include "efiboot.h"
30 1.1 nonaka
31 1.1 nonaka #include <bootinfo.h>
32 1.1 nonaka
33 1.1 nonaka static const char *memtypes[] = {
34 1.1 nonaka "unknown",
35 1.1 nonaka "available",
36 1.1 nonaka "reserved",
37 1.1 nonaka "ACPI reclaimable",
38 1.4 nonaka "ACPI NVS",
39 1.4 nonaka "unusable",
40 1.4 nonaka "disabled",
41 1.4 nonaka "Persistent",
42 1.4 nonaka "undefined (8)",
43 1.4 nonaka "undefined (9)",
44 1.4 nonaka "undefined (10)",
45 1.4 nonaka "undefined (11)",
46 1.4 nonaka "Persistent (Legacy)"
47 1.1 nonaka };
48 1.1 nonaka
49 1.1 nonaka static const char *efimemtypes[] = {
50 1.1 nonaka "Reserved",
51 1.1 nonaka "LoaderCode",
52 1.1 nonaka "LoaderData",
53 1.1 nonaka "BootServicesCode",
54 1.1 nonaka "BootServicesData",
55 1.1 nonaka "RuntimeServicesCode",
56 1.1 nonaka "RuntimeServicesData",
57 1.1 nonaka "ConventionalMemory",
58 1.1 nonaka "UnusableMemory",
59 1.1 nonaka "ACPIReclaimMemory",
60 1.1 nonaka "ACPIMemoryNVS",
61 1.1 nonaka "MemoryMappedIO",
62 1.1 nonaka "MemoryMappedIOPortSpace",
63 1.1 nonaka "PalCode",
64 1.4 nonaka "PersistentMemory",
65 1.1 nonaka };
66 1.1 nonaka
67 1.6 nonaka #ifndef KERN_LOADSPACE_SIZE
68 1.6 nonaka #define KERN_LOADSPACE_SIZE (128 * 1024 * 1024) /* 128MiB */
69 1.6 nonaka #endif
70 1.6 nonaka
71 1.1 nonaka static int
72 1.1 nonaka getmemtype(EFI_MEMORY_DESCRIPTOR *md)
73 1.1 nonaka {
74 1.1 nonaka
75 1.1 nonaka switch (md->Type) {
76 1.1 nonaka case EfiLoaderCode:
77 1.1 nonaka case EfiLoaderData:
78 1.1 nonaka case EfiBootServicesCode:
79 1.1 nonaka case EfiBootServicesData:
80 1.1 nonaka case EfiConventionalMemory:
81 1.1 nonaka return (md->Attribute & EFI_MEMORY_WB) ?
82 1.1 nonaka BIM_Memory : BIM_Reserved;
83 1.1 nonaka
84 1.1 nonaka case EfiACPIReclaimMemory:
85 1.1 nonaka return BIM_ACPI;
86 1.1 nonaka
87 1.1 nonaka case EfiACPIMemoryNVS:
88 1.1 nonaka return BIM_NVS;
89 1.1 nonaka
90 1.4 nonaka case EfiPersistentMemory:
91 1.4 nonaka return BIM_PMEM;
92 1.4 nonaka
93 1.1 nonaka case EfiReservedMemoryType:
94 1.1 nonaka case EfiRuntimeServicesCode:
95 1.1 nonaka case EfiRuntimeServicesData:
96 1.1 nonaka case EfiUnusableMemory:
97 1.1 nonaka case EfiMemoryMappedIO:
98 1.1 nonaka case EfiMemoryMappedIOPortSpace:
99 1.1 nonaka case EfiPalCode:
100 1.1 nonaka case EfiMaxMemoryType:
101 1.4 nonaka default:
102 1.1 nonaka return BIM_Reserved;
103 1.1 nonaka }
104 1.1 nonaka }
105 1.1 nonaka
106 1.3 nonaka EFI_MEMORY_DESCRIPTOR *
107 1.3 nonaka efi_memory_get_map(UINTN *NoEntries, UINTN *MapKey, UINTN *DescriptorSize,
108 1.3 nonaka UINT32 *DescriptorVersion, bool sorted)
109 1.1 nonaka {
110 1.7 nonaka EFI_MEMORY_DESCRIPTOR *desc, *md, *next, *target, *tmp;
111 1.1 nonaka UINTN i, j;
112 1.1 nonaka
113 1.1 nonaka *NoEntries = 0;
114 1.1 nonaka desc = LibMemoryMap(NoEntries, MapKey, DescriptorSize,
115 1.1 nonaka DescriptorVersion);
116 1.1 nonaka if (desc == NULL)
117 1.5 nonaka panic("efi_memory_get_map failed");
118 1.1 nonaka
119 1.1 nonaka if (!sorted)
120 1.1 nonaka return desc;
121 1.1 nonaka
122 1.7 nonaka tmp = alloc(*DescriptorSize);
123 1.7 nonaka if (tmp == NULL)
124 1.7 nonaka return desc;
125 1.7 nonaka
126 1.1 nonaka for (i = 0, md = desc; i < *NoEntries - 1; i++, md = next) {
127 1.1 nonaka target = next = NextMemoryDescriptor(md, *DescriptorSize);
128 1.1 nonaka for (j = i + 1; j < *NoEntries; j++) {
129 1.1 nonaka if (md->PhysicalStart > target->PhysicalStart) {
130 1.7 nonaka CopyMem(tmp, md, *DescriptorSize);
131 1.7 nonaka CopyMem(md, target, *DescriptorSize);
132 1.7 nonaka CopyMem(target, tmp, *DescriptorSize);
133 1.1 nonaka }
134 1.1 nonaka target = NextMemoryDescriptor(target, *DescriptorSize);
135 1.1 nonaka }
136 1.1 nonaka }
137 1.7 nonaka dealloc(tmp, *DescriptorSize);
138 1.7 nonaka
139 1.7 nonaka return desc;
140 1.7 nonaka }
141 1.7 nonaka
142 1.7 nonaka EFI_MEMORY_DESCRIPTOR *
143 1.7 nonaka efi_memory_compact_map(EFI_MEMORY_DESCRIPTOR *desc, UINTN *NoEntries,
144 1.7 nonaka UINTN DescriptorSize)
145 1.7 nonaka {
146 1.7 nonaka EFI_MEMORY_DESCRIPTOR *md, *next, *target, *tmp;
147 1.7 nonaka UINTN i, j;
148 1.7 nonaka UINT32 type;
149 1.7 nonaka bool first = true, do_compact;
150 1.7 nonaka
151 1.7 nonaka for (i = 0, md = target = desc; i < *NoEntries; i++, md = next) {
152 1.7 nonaka type = md->Type;
153 1.7 nonaka switch (type) {
154 1.7 nonaka case EfiLoaderCode:
155 1.7 nonaka case EfiLoaderData:
156 1.7 nonaka case EfiBootServicesCode:
157 1.7 nonaka case EfiBootServicesData:
158 1.7 nonaka case EfiConventionalMemory:
159 1.7 nonaka if ((md->Attribute & EFI_MEMORY_WB) != 0)
160 1.7 nonaka type = EfiConventionalMemory;
161 1.7 nonaka if (md->Attribute == target->Attribute) {
162 1.7 nonaka do_compact = true;
163 1.7 nonaka break;
164 1.7 nonaka }
165 1.7 nonaka /* FALLTHROUGH */
166 1.7 nonaka case EfiACPIReclaimMemory:
167 1.7 nonaka case EfiACPIMemoryNVS:
168 1.7 nonaka case EfiPersistentMemory:
169 1.7 nonaka case EfiReservedMemoryType:
170 1.7 nonaka case EfiRuntimeServicesCode:
171 1.7 nonaka case EfiRuntimeServicesData:
172 1.7 nonaka case EfiUnusableMemory:
173 1.7 nonaka case EfiMemoryMappedIO:
174 1.7 nonaka case EfiMemoryMappedIOPortSpace:
175 1.7 nonaka case EfiPalCode:
176 1.7 nonaka default:
177 1.7 nonaka do_compact = false;
178 1.7 nonaka break;
179 1.7 nonaka }
180 1.7 nonaka
181 1.7 nonaka if (first) {
182 1.7 nonaka first = false;
183 1.7 nonaka } else if (do_compact &&
184 1.7 nonaka type == target->Type &&
185 1.7 nonaka md->Attribute == target->Attribute &&
186 1.7 nonaka md->PhysicalStart == target->PhysicalStart + target->NumberOfPages * EFI_PAGE_SIZE) {
187 1.7 nonaka /* continuous region */
188 1.7 nonaka target->NumberOfPages += md->NumberOfPages;
189 1.7 nonaka
190 1.7 nonaka tmp = md;
191 1.7 nonaka for (j = i + 1; j < *NoEntries; j++) {
192 1.7 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
193 1.7 nonaka CopyMem(md, next, DescriptorSize);
194 1.7 nonaka md = next;
195 1.7 nonaka }
196 1.7 nonaka next = tmp;
197 1.7 nonaka
198 1.7 nonaka i--;
199 1.7 nonaka (*NoEntries)--;
200 1.7 nonaka continue;
201 1.7 nonaka } else {
202 1.7 nonaka target = md;
203 1.7 nonaka }
204 1.7 nonaka
205 1.7 nonaka target->Type = type;
206 1.7 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
207 1.7 nonaka }
208 1.7 nonaka
209 1.1 nonaka return desc;
210 1.1 nonaka }
211 1.1 nonaka
212 1.1 nonaka /*
213 1.1 nonaka * get memory size below 1MB
214 1.1 nonaka */
215 1.1 nonaka int
216 1.1 nonaka getbasemem(void)
217 1.1 nonaka {
218 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
219 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize, MappingSize;
220 1.1 nonaka UINT32 DescriptorVersion;
221 1.1 nonaka EFI_PHYSICAL_ADDRESS basemem = 0, epa;
222 1.1 nonaka
223 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
224 1.1 nonaka &DescriptorVersion, true);
225 1.1 nonaka
226 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
227 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
228 1.1 nonaka if (getmemtype(md) != BIM_Memory)
229 1.1 nonaka continue;
230 1.1 nonaka if (md->PhysicalStart >= 1 * 1024 * 1024)
231 1.1 nonaka continue;
232 1.1 nonaka if (basemem != md->PhysicalStart)
233 1.1 nonaka continue;
234 1.1 nonaka
235 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
236 1.1 nonaka epa = md->PhysicalStart + MappingSize;
237 1.1 nonaka if (epa == 0 || epa > 1 * 1024 * 1024)
238 1.1 nonaka epa = 1 * 1024 * 1024;
239 1.1 nonaka basemem = epa;
240 1.1 nonaka }
241 1.1 nonaka
242 1.1 nonaka FreePool(mdtop);
243 1.1 nonaka
244 1.1 nonaka return basemem / 1024; /* KiB */
245 1.1 nonaka }
246 1.1 nonaka
247 1.1 nonaka /*
248 1.1 nonaka * get memory size above 1MB below 4GB
249 1.1 nonaka */
250 1.1 nonaka int
251 1.1 nonaka getextmemx(void)
252 1.1 nonaka {
253 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
254 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize, MappingSize;
255 1.1 nonaka UINT32 DescriptorVersion;
256 1.1 nonaka EFI_PHYSICAL_ADDRESS extmem16m = 0; /* 0-16MB */
257 1.1 nonaka EFI_PHYSICAL_ADDRESS extmem4g = 0; /* 16MB-4GB */
258 1.1 nonaka EFI_PHYSICAL_ADDRESS pa, epa;
259 1.1 nonaka bool first16m = true, first4g = true;
260 1.1 nonaka int extmem;
261 1.1 nonaka
262 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
263 1.1 nonaka &DescriptorVersion, true);
264 1.1 nonaka
265 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
266 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
267 1.1 nonaka if (getmemtype(md) == BIM_Reserved)
268 1.1 nonaka continue;
269 1.1 nonaka if (md->PhysicalStart >= 4 * 1024 * 1024 * 1024ULL)
270 1.1 nonaka continue;
271 1.1 nonaka
272 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
273 1.1 nonaka epa = md->PhysicalStart + MappingSize;
274 1.1 nonaka if (epa == 0 || epa > 4 * 1024 * 1024 * 1024LL)
275 1.1 nonaka epa = 4 * 1024 * 1024 * 1024LL;
276 1.1 nonaka
277 1.1 nonaka if (epa <= 1 * 1024 * 1024)
278 1.1 nonaka continue;
279 1.1 nonaka
280 1.1 nonaka pa = md->PhysicalStart;
281 1.1 nonaka if (pa < 16 * 1024 * 1024) {
282 1.1 nonaka if (first16m || extmem16m == pa) {
283 1.1 nonaka first16m = false;
284 1.1 nonaka if (epa >= 16 * 1024 * 1024) {
285 1.1 nonaka extmem16m = 16 * 1024 * 1024;
286 1.1 nonaka pa = 16 * 1024 * 1024;
287 1.1 nonaka } else
288 1.1 nonaka extmem16m = epa;
289 1.1 nonaka }
290 1.1 nonaka }
291 1.1 nonaka if (pa >= 16 * 1024 * 1024) {
292 1.1 nonaka if (first4g || extmem4g == pa) {
293 1.1 nonaka first4g = false;
294 1.1 nonaka extmem4g = epa;
295 1.1 nonaka }
296 1.1 nonaka }
297 1.1 nonaka }
298 1.1 nonaka
299 1.1 nonaka FreePool(mdtop);
300 1.1 nonaka
301 1.1 nonaka if (extmem16m > 1 * 1024 * 1024)
302 1.1 nonaka extmem16m -= 1 * 1024 * 1024; /* below 1MB */
303 1.1 nonaka
304 1.1 nonaka extmem = extmem16m / 1024;
305 1.1 nonaka if (extmem == 15 * 1024)
306 1.1 nonaka extmem += extmem4g / 1024;
307 1.1 nonaka return extmem;
308 1.1 nonaka }
309 1.1 nonaka
310 1.1 nonaka void
311 1.1 nonaka efi_memory_probe(void)
312 1.1 nonaka {
313 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
314 1.6 nonaka EFI_STATUS status;
315 1.6 nonaka EFI_PHYSICAL_ADDRESS bouncebuf;
316 1.1 nonaka UINTN i, n, NoEntries, MapKey, DescriptorSize, MappingSize;
317 1.1 nonaka UINT32 DescriptorVersion;
318 1.1 nonaka int memtype;
319 1.1 nonaka
320 1.6 nonaka bouncebuf = EFI_ALLOCATE_MAX_ADDRESS;
321 1.6 nonaka status = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress,
322 1.6 nonaka EfiLoaderData, EFI_SIZE_TO_PAGES(KERN_LOADSPACE_SIZE), &bouncebuf);
323 1.6 nonaka if (EFI_ERROR(status))
324 1.6 nonaka panic("couldn't allocate kernel space.");
325 1.6 nonaka efi_loadaddr = bouncebuf;
326 1.6 nonaka
327 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
328 1.1 nonaka &DescriptorVersion, false);
329 1.5 nonaka printf(" mem[");
330 1.1 nonaka for (i = 0, n = 0, md = mdtop; i < NoEntries; i++, md = next) {
331 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
332 1.1 nonaka
333 1.1 nonaka memtype = getmemtype(md);
334 1.1 nonaka if (memtype != BIM_Memory)
335 1.1 nonaka continue;
336 1.1 nonaka
337 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
338 1.1 nonaka if (MappingSize < 12 * 1024) /* XXX Why? from OpenBSD */
339 1.1 nonaka continue;
340 1.1 nonaka
341 1.1 nonaka if (n++ > 0)
342 1.5 nonaka printf(" ");
343 1.5 nonaka printf("0x%" PRIxMAX "-0x%" PRIxMAX, (uintmax_t)md->PhysicalStart,
344 1.5 nonaka (uintmax_t)(md->PhysicalStart + MappingSize - 1));
345 1.1 nonaka }
346 1.5 nonaka printf("]\n");
347 1.1 nonaka
348 1.1 nonaka FreePool(mdtop);
349 1.1 nonaka }
350 1.1 nonaka
351 1.1 nonaka void
352 1.7 nonaka efi_memory_show_map(bool sorted, bool compact)
353 1.1 nonaka {
354 1.1 nonaka EFI_STATUS status;
355 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
356 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize;
357 1.1 nonaka UINT32 DescriptorVersion;
358 1.1 nonaka char memstr[32], efimemstr[32];
359 1.1 nonaka int memtype;
360 1.1 nonaka UINTN cols, rows, row = 0;
361 1.1 nonaka
362 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
363 1.1 nonaka ST->ConOut->Mode->Mode, &cols, &rows);
364 1.1 nonaka if (EFI_ERROR(status) || rows <= 2)
365 1.1 nonaka rows = 0;
366 1.1 nonaka else
367 1.1 nonaka rows -= 2;
368 1.1 nonaka
369 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
370 1.1 nonaka &DescriptorVersion, sorted);
371 1.7 nonaka if (compact)
372 1.7 nonaka efi_memory_compact_map(mdtop, &NoEntries, DescriptorSize);
373 1.1 nonaka
374 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
375 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
376 1.1 nonaka
377 1.1 nonaka memtype = getmemtype(md);
378 1.1 nonaka if (memtype >= __arraycount(memtypes))
379 1.1 nonaka snprintf(memstr, sizeof(memstr), "unknown (%d)",
380 1.1 nonaka memtype);
381 1.1 nonaka if (md->Type >= __arraycount(efimemtypes))
382 1.1 nonaka snprintf(efimemstr, sizeof(efimemstr), "unknown (%d)",
383 1.1 nonaka md->Type);
384 1.1 nonaka printf("%016" PRIxMAX "/%016" PRIxMAX ": %s [%s]\n",
385 1.1 nonaka (uintmax_t)md->PhysicalStart,
386 1.1 nonaka (uintmax_t)md->PhysicalStart +
387 1.1 nonaka md->NumberOfPages * EFI_PAGE_SIZE - 1,
388 1.1 nonaka memtype >= __arraycount(memtypes) ?
389 1.1 nonaka memstr : memtypes[memtype],
390 1.1 nonaka md->Type >= __arraycount(efimemtypes) ?
391 1.1 nonaka efimemstr : efimemtypes[md->Type]);
392 1.1 nonaka
393 1.2 roy if (++row >= rows) {
394 1.1 nonaka row = 0;
395 1.5 nonaka printf("Press Any Key to continue :");
396 1.1 nonaka (void) awaitkey(-1, 0);
397 1.5 nonaka printf("\n");
398 1.1 nonaka }
399 1.1 nonaka }
400 1.1 nonaka
401 1.1 nonaka FreePool(mdtop);
402 1.1 nonaka }
403 1.1 nonaka
404 1.1 nonaka void
405 1.1 nonaka vpbcopy(const void *va, void *pa, size_t n)
406 1.1 nonaka {
407 1.1 nonaka memmove(pa, va, n);
408 1.1 nonaka }
409 1.1 nonaka
410 1.1 nonaka void
411 1.1 nonaka pvbcopy(const void *pa, void *va, size_t n)
412 1.1 nonaka {
413 1.1 nonaka memmove(va, pa, n);
414 1.1 nonaka }
415 1.1 nonaka
416 1.1 nonaka void
417 1.1 nonaka pbzero(void *pa, size_t n)
418 1.1 nonaka {
419 1.1 nonaka memset(pa, 0, n);
420 1.1 nonaka }
421 1.1 nonaka
422 1.1 nonaka physaddr_t
423 1.1 nonaka vtophys(void *va)
424 1.1 nonaka {
425 1.1 nonaka return (physaddr_t)va;
426 1.1 nonaka }
427