efimemory.c revision 1.5 1 1.5 nonaka /* $NetBSD: efimemory.c,v 1.5 2018/03/27 14:15:05 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.1 nonaka static int
68 1.1 nonaka getmemtype(EFI_MEMORY_DESCRIPTOR *md)
69 1.1 nonaka {
70 1.1 nonaka
71 1.1 nonaka switch (md->Type) {
72 1.1 nonaka case EfiLoaderCode:
73 1.1 nonaka case EfiLoaderData:
74 1.1 nonaka case EfiBootServicesCode:
75 1.1 nonaka case EfiBootServicesData:
76 1.1 nonaka case EfiConventionalMemory:
77 1.1 nonaka return (md->Attribute & EFI_MEMORY_WB) ?
78 1.1 nonaka BIM_Memory : BIM_Reserved;
79 1.1 nonaka
80 1.1 nonaka case EfiACPIReclaimMemory:
81 1.1 nonaka return BIM_ACPI;
82 1.1 nonaka
83 1.1 nonaka case EfiACPIMemoryNVS:
84 1.1 nonaka return BIM_NVS;
85 1.1 nonaka
86 1.4 nonaka case EfiPersistentMemory:
87 1.4 nonaka return BIM_PMEM;
88 1.4 nonaka
89 1.1 nonaka case EfiReservedMemoryType:
90 1.1 nonaka case EfiRuntimeServicesCode:
91 1.1 nonaka case EfiRuntimeServicesData:
92 1.1 nonaka case EfiUnusableMemory:
93 1.1 nonaka case EfiMemoryMappedIO:
94 1.1 nonaka case EfiMemoryMappedIOPortSpace:
95 1.1 nonaka case EfiPalCode:
96 1.1 nonaka case EfiMaxMemoryType:
97 1.4 nonaka default:
98 1.1 nonaka return BIM_Reserved;
99 1.1 nonaka }
100 1.1 nonaka }
101 1.1 nonaka
102 1.3 nonaka EFI_MEMORY_DESCRIPTOR *
103 1.3 nonaka efi_memory_get_map(UINTN *NoEntries, UINTN *MapKey, UINTN *DescriptorSize,
104 1.3 nonaka UINT32 *DescriptorVersion, bool sorted)
105 1.1 nonaka {
106 1.1 nonaka EFI_MEMORY_DESCRIPTOR *desc, *md, *next, *target, tmp;
107 1.1 nonaka UINTN i, j;
108 1.1 nonaka
109 1.1 nonaka *NoEntries = 0;
110 1.1 nonaka desc = LibMemoryMap(NoEntries, MapKey, DescriptorSize,
111 1.1 nonaka DescriptorVersion);
112 1.1 nonaka if (desc == NULL)
113 1.5 nonaka panic("efi_memory_get_map failed");
114 1.1 nonaka
115 1.1 nonaka if (!sorted)
116 1.1 nonaka return desc;
117 1.1 nonaka
118 1.1 nonaka for (i = 0, md = desc; i < *NoEntries - 1; i++, md = next) {
119 1.1 nonaka target = next = NextMemoryDescriptor(md, *DescriptorSize);
120 1.1 nonaka for (j = i + 1; j < *NoEntries; j++) {
121 1.1 nonaka if (md->PhysicalStart > target->PhysicalStart) {
122 1.1 nonaka CopyMem(&tmp, md, sizeof(*md));
123 1.1 nonaka CopyMem(md, target, sizeof(*md));
124 1.1 nonaka CopyMem(target, &tmp, sizeof(*md));
125 1.1 nonaka }
126 1.1 nonaka target = NextMemoryDescriptor(target, *DescriptorSize);
127 1.1 nonaka }
128 1.1 nonaka }
129 1.1 nonaka return desc;
130 1.1 nonaka }
131 1.1 nonaka
132 1.1 nonaka /*
133 1.1 nonaka * get memory size below 1MB
134 1.1 nonaka */
135 1.1 nonaka int
136 1.1 nonaka getbasemem(void)
137 1.1 nonaka {
138 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
139 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize, MappingSize;
140 1.1 nonaka UINT32 DescriptorVersion;
141 1.1 nonaka EFI_PHYSICAL_ADDRESS basemem = 0, epa;
142 1.1 nonaka
143 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
144 1.1 nonaka &DescriptorVersion, true);
145 1.1 nonaka
146 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
147 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
148 1.1 nonaka if (getmemtype(md) != BIM_Memory)
149 1.1 nonaka continue;
150 1.1 nonaka if (md->PhysicalStart >= 1 * 1024 * 1024)
151 1.1 nonaka continue;
152 1.1 nonaka if (basemem != md->PhysicalStart)
153 1.1 nonaka continue;
154 1.1 nonaka
155 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
156 1.1 nonaka epa = md->PhysicalStart + MappingSize;
157 1.1 nonaka if (epa == 0 || epa > 1 * 1024 * 1024)
158 1.1 nonaka epa = 1 * 1024 * 1024;
159 1.1 nonaka basemem = epa;
160 1.1 nonaka }
161 1.1 nonaka
162 1.1 nonaka FreePool(mdtop);
163 1.1 nonaka
164 1.1 nonaka return basemem / 1024; /* KiB */
165 1.1 nonaka }
166 1.1 nonaka
167 1.1 nonaka /*
168 1.1 nonaka * get memory size above 1MB below 4GB
169 1.1 nonaka */
170 1.1 nonaka int
171 1.1 nonaka getextmemx(void)
172 1.1 nonaka {
173 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
174 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize, MappingSize;
175 1.1 nonaka UINT32 DescriptorVersion;
176 1.1 nonaka EFI_PHYSICAL_ADDRESS extmem16m = 0; /* 0-16MB */
177 1.1 nonaka EFI_PHYSICAL_ADDRESS extmem4g = 0; /* 16MB-4GB */
178 1.1 nonaka EFI_PHYSICAL_ADDRESS pa, epa;
179 1.1 nonaka bool first16m = true, first4g = true;
180 1.1 nonaka int extmem;
181 1.1 nonaka
182 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
183 1.1 nonaka &DescriptorVersion, true);
184 1.1 nonaka
185 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
186 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
187 1.1 nonaka if (getmemtype(md) == BIM_Reserved)
188 1.1 nonaka continue;
189 1.1 nonaka if (md->PhysicalStart >= 4 * 1024 * 1024 * 1024ULL)
190 1.1 nonaka continue;
191 1.1 nonaka
192 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
193 1.1 nonaka epa = md->PhysicalStart + MappingSize;
194 1.1 nonaka if (epa == 0 || epa > 4 * 1024 * 1024 * 1024LL)
195 1.1 nonaka epa = 4 * 1024 * 1024 * 1024LL;
196 1.1 nonaka
197 1.1 nonaka if (epa <= 1 * 1024 * 1024)
198 1.1 nonaka continue;
199 1.1 nonaka
200 1.1 nonaka pa = md->PhysicalStart;
201 1.1 nonaka if (pa < 16 * 1024 * 1024) {
202 1.1 nonaka if (first16m || extmem16m == pa) {
203 1.1 nonaka first16m = false;
204 1.1 nonaka if (epa >= 16 * 1024 * 1024) {
205 1.1 nonaka extmem16m = 16 * 1024 * 1024;
206 1.1 nonaka pa = 16 * 1024 * 1024;
207 1.1 nonaka } else
208 1.1 nonaka extmem16m = epa;
209 1.1 nonaka }
210 1.1 nonaka }
211 1.1 nonaka if (pa >= 16 * 1024 * 1024) {
212 1.1 nonaka if (first4g || extmem4g == pa) {
213 1.1 nonaka first4g = false;
214 1.1 nonaka extmem4g = epa;
215 1.1 nonaka }
216 1.1 nonaka }
217 1.1 nonaka }
218 1.1 nonaka
219 1.1 nonaka FreePool(mdtop);
220 1.1 nonaka
221 1.1 nonaka if (extmem16m > 1 * 1024 * 1024)
222 1.1 nonaka extmem16m -= 1 * 1024 * 1024; /* below 1MB */
223 1.1 nonaka
224 1.1 nonaka extmem = extmem16m / 1024;
225 1.1 nonaka if (extmem == 15 * 1024)
226 1.1 nonaka extmem += extmem4g / 1024;
227 1.1 nonaka return extmem;
228 1.1 nonaka }
229 1.1 nonaka
230 1.1 nonaka void
231 1.1 nonaka efi_memory_probe(void)
232 1.1 nonaka {
233 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
234 1.1 nonaka UINTN i, n, NoEntries, MapKey, DescriptorSize, MappingSize;
235 1.1 nonaka UINT32 DescriptorVersion;
236 1.1 nonaka int memtype;
237 1.1 nonaka
238 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
239 1.1 nonaka &DescriptorVersion, false);
240 1.1 nonaka
241 1.5 nonaka printf(" mem[");
242 1.1 nonaka for (i = 0, n = 0, md = mdtop; i < NoEntries; i++, md = next) {
243 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
244 1.1 nonaka
245 1.1 nonaka memtype = getmemtype(md);
246 1.1 nonaka if (memtype != BIM_Memory)
247 1.1 nonaka continue;
248 1.1 nonaka
249 1.1 nonaka MappingSize = md->NumberOfPages * EFI_PAGE_SIZE;
250 1.1 nonaka if (MappingSize < 12 * 1024) /* XXX Why? from OpenBSD */
251 1.1 nonaka continue;
252 1.1 nonaka
253 1.1 nonaka if (n++ > 0)
254 1.5 nonaka printf(" ");
255 1.5 nonaka printf("0x%" PRIxMAX "-0x%" PRIxMAX, (uintmax_t)md->PhysicalStart,
256 1.5 nonaka (uintmax_t)(md->PhysicalStart + MappingSize - 1));
257 1.1 nonaka }
258 1.5 nonaka printf("]\n");
259 1.1 nonaka
260 1.1 nonaka FreePool(mdtop);
261 1.1 nonaka }
262 1.1 nonaka
263 1.1 nonaka void
264 1.1 nonaka efi_memory_show_map(bool sorted)
265 1.1 nonaka {
266 1.1 nonaka EFI_STATUS status;
267 1.1 nonaka EFI_MEMORY_DESCRIPTOR *mdtop, *md, *next;
268 1.1 nonaka UINTN i, NoEntries, MapKey, DescriptorSize;
269 1.1 nonaka UINT32 DescriptorVersion;
270 1.1 nonaka char memstr[32], efimemstr[32];
271 1.1 nonaka int memtype;
272 1.1 nonaka UINTN cols, rows, row = 0;
273 1.1 nonaka
274 1.1 nonaka status = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
275 1.1 nonaka ST->ConOut->Mode->Mode, &cols, &rows);
276 1.1 nonaka if (EFI_ERROR(status) || rows <= 2)
277 1.1 nonaka rows = 0;
278 1.1 nonaka else
279 1.1 nonaka rows -= 2;
280 1.1 nonaka
281 1.3 nonaka mdtop = efi_memory_get_map(&NoEntries, &MapKey, &DescriptorSize,
282 1.1 nonaka &DescriptorVersion, sorted);
283 1.1 nonaka
284 1.1 nonaka for (i = 0, md = mdtop; i < NoEntries; i++, md = next) {
285 1.1 nonaka next = NextMemoryDescriptor(md, DescriptorSize);
286 1.1 nonaka
287 1.1 nonaka memtype = getmemtype(md);
288 1.1 nonaka if (memtype >= __arraycount(memtypes))
289 1.1 nonaka snprintf(memstr, sizeof(memstr), "unknown (%d)",
290 1.1 nonaka memtype);
291 1.1 nonaka if (md->Type >= __arraycount(efimemtypes))
292 1.1 nonaka snprintf(efimemstr, sizeof(efimemstr), "unknown (%d)",
293 1.1 nonaka md->Type);
294 1.1 nonaka printf("%016" PRIxMAX "/%016" PRIxMAX ": %s [%s]\n",
295 1.1 nonaka (uintmax_t)md->PhysicalStart,
296 1.1 nonaka (uintmax_t)md->PhysicalStart +
297 1.1 nonaka md->NumberOfPages * EFI_PAGE_SIZE - 1,
298 1.1 nonaka memtype >= __arraycount(memtypes) ?
299 1.1 nonaka memstr : memtypes[memtype],
300 1.1 nonaka md->Type >= __arraycount(efimemtypes) ?
301 1.1 nonaka efimemstr : efimemtypes[md->Type]);
302 1.1 nonaka
303 1.2 roy if (++row >= rows) {
304 1.1 nonaka row = 0;
305 1.5 nonaka printf("Press Any Key to continue :");
306 1.1 nonaka (void) awaitkey(-1, 0);
307 1.5 nonaka printf("\n");
308 1.1 nonaka }
309 1.1 nonaka }
310 1.1 nonaka
311 1.1 nonaka FreePool(mdtop);
312 1.1 nonaka }
313 1.1 nonaka
314 1.1 nonaka void
315 1.1 nonaka vpbcopy(const void *va, void *pa, size_t n)
316 1.1 nonaka {
317 1.1 nonaka memmove(pa, va, n);
318 1.1 nonaka }
319 1.1 nonaka
320 1.1 nonaka void
321 1.1 nonaka pvbcopy(const void *pa, void *va, size_t n)
322 1.1 nonaka {
323 1.1 nonaka memmove(va, pa, n);
324 1.1 nonaka }
325 1.1 nonaka
326 1.1 nonaka void
327 1.1 nonaka pbzero(void *pa, size_t n)
328 1.1 nonaka {
329 1.1 nonaka memset(pa, 0, n);
330 1.1 nonaka }
331 1.1 nonaka
332 1.1 nonaka physaddr_t
333 1.1 nonaka vtophys(void *va)
334 1.1 nonaka {
335 1.1 nonaka return (physaddr_t)va;
336 1.1 nonaka }
337