1 /* $NetBSD: efimemory.c,v 1.5 2018/03/27 14:15:05 nonaka Exp $ */ 2 3 /*- 4 * Copyright (c) 2016 Kimihiro Nonaka <nonaka@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("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 printf(" 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 printf(" "); 255 printf("0x%" PRIxMAX "-0x%" PRIxMAX, (uintmax_t)md->PhysicalStart, 256 (uintmax_t)(md->PhysicalStart + MappingSize - 1)); 257 } 258 printf("]\n"); 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 printf("Press Any Key to continue :"); 306 (void) awaitkey(-1, 0); 307 printf("\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