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