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