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