Home | History | Annotate | Line # | Download | only in efiboot
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