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