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