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