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