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