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