mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
Reduce code duplication by switching to the new shared interface. Practically, the kernel may lose a few pages to (unused) EFI runtime services. Reviewed by: andrew Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D49132
179 lines
4.4 KiB
C
179 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2014 The FreeBSD Foundation
|
|
* Copyright (c) 2018 Andrew Turner
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/efi.h>
|
|
#include <sys/efi_map.h>
|
|
#include <sys/physmem.h>
|
|
|
|
#include <machine/efi.h>
|
|
#include <machine/vmparam.h>
|
|
|
|
void
|
|
efi_map_foreach_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp)
|
|
{
|
|
struct efi_md *map, *p;
|
|
size_t efisz;
|
|
int ndesc, i;
|
|
|
|
/*
|
|
* Memory map data provided by UEFI via the GetMemoryMap
|
|
* Boot Services API.
|
|
*/
|
|
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
|
|
map = (struct efi_md *)((uint8_t *)efihdr + efisz);
|
|
|
|
if (efihdr->descriptor_size == 0)
|
|
return;
|
|
ndesc = efihdr->memory_size / efihdr->descriptor_size;
|
|
|
|
for (i = 0, p = map; i < ndesc; i++,
|
|
p = efi_next_descriptor(p, efihdr->descriptor_size)) {
|
|
cb(p, argp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle the EFI memory map list.
|
|
*
|
|
* We will make two passes at this, the first (exclude == false) to populate
|
|
* physmem with valid physical memory ranges from recognized map entry types.
|
|
* In the second pass we will exclude memory ranges from physmem which must not
|
|
* be used for general allocations, either because they are used by runtime
|
|
* firmware or otherwise reserved.
|
|
*
|
|
* Adding the runtime-reserved memory ranges to physmem and excluding them
|
|
* later ensures that they are included in the DMAP, but excluded from
|
|
* phys_avail[].
|
|
*
|
|
* Entry types not explicitly listed here are ignored and not mapped.
|
|
*/
|
|
static void
|
|
handle_efi_map_entry(struct efi_md *p, void *argp)
|
|
{
|
|
bool exclude = *(bool *)argp;
|
|
|
|
switch (p->md_type) {
|
|
case EFI_MD_TYPE_RECLAIM:
|
|
/*
|
|
* The recomended location for ACPI tables. Map into the
|
|
* DMAP so we can access them from userspace via /dev/mem.
|
|
*/
|
|
case EFI_MD_TYPE_RT_CODE:
|
|
/*
|
|
* Some UEFI implementations put the system table in the
|
|
* runtime code section. Include it in the DMAP, but will
|
|
* be excluded from phys_avail.
|
|
*/
|
|
case EFI_MD_TYPE_RT_DATA:
|
|
/*
|
|
* Runtime data will be excluded after the DMAP
|
|
* region is created to stop it from being added
|
|
* to phys_avail.
|
|
*/
|
|
if (exclude) {
|
|
physmem_exclude_region(p->md_phys,
|
|
p->md_pages * EFI_PAGE_SIZE, EXFLAG_NOALLOC);
|
|
break;
|
|
}
|
|
/* FALLTHROUGH */
|
|
case EFI_MD_TYPE_CODE:
|
|
case EFI_MD_TYPE_DATA:
|
|
case EFI_MD_TYPE_BS_CODE:
|
|
case EFI_MD_TYPE_BS_DATA:
|
|
case EFI_MD_TYPE_FREE:
|
|
/*
|
|
* We're allowed to use any entry with these types.
|
|
*/
|
|
if (!exclude)
|
|
physmem_hardware_region(p->md_phys,
|
|
p->md_pages * EFI_PAGE_SIZE);
|
|
break;
|
|
default:
|
|
/* Other types shall not be handled by physmem. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
efi_map_add_entries(struct efi_map_header *efihdr)
|
|
{
|
|
bool exclude = false;
|
|
efi_map_foreach_entry(efihdr, handle_efi_map_entry, &exclude);
|
|
}
|
|
|
|
void
|
|
efi_map_exclude_entries(struct efi_map_header *efihdr)
|
|
{
|
|
bool exclude = true;
|
|
efi_map_foreach_entry(efihdr, handle_efi_map_entry, &exclude);
|
|
}
|
|
|
|
static void
|
|
print_efi_map_entry(struct efi_md *p, void *argp __unused)
|
|
{
|
|
const char *type;
|
|
static const char *types[] = {
|
|
"Reserved",
|
|
"LoaderCode",
|
|
"LoaderData",
|
|
"BootServicesCode",
|
|
"BootServicesData",
|
|
"RuntimeServicesCode",
|
|
"RuntimeServicesData",
|
|
"ConventionalMemory",
|
|
"UnusableMemory",
|
|
"ACPIReclaimMemory",
|
|
"ACPIMemoryNVS",
|
|
"MemoryMappedIO",
|
|
"MemoryMappedIOPortSpace",
|
|
"PalCode",
|
|
"PersistentMemory"
|
|
};
|
|
|
|
if (p->md_type < nitems(types))
|
|
type = types[p->md_type];
|
|
else
|
|
type = "<INVALID>";
|
|
printf("%23s %012jx %012jx %08jx ", type, (uintmax_t)p->md_phys,
|
|
(uintmax_t)p->md_virt, (uintmax_t)p->md_pages);
|
|
if (p->md_attr & EFI_MD_ATTR_UC)
|
|
printf("UC ");
|
|
if (p->md_attr & EFI_MD_ATTR_WC)
|
|
printf("WC ");
|
|
if (p->md_attr & EFI_MD_ATTR_WT)
|
|
printf("WT ");
|
|
if (p->md_attr & EFI_MD_ATTR_WB)
|
|
printf("WB ");
|
|
if (p->md_attr & EFI_MD_ATTR_UCE)
|
|
printf("UCE ");
|
|
if (p->md_attr & EFI_MD_ATTR_WP)
|
|
printf("WP ");
|
|
if (p->md_attr & EFI_MD_ATTR_RP)
|
|
printf("RP ");
|
|
if (p->md_attr & EFI_MD_ATTR_XP)
|
|
printf("XP ");
|
|
if (p->md_attr & EFI_MD_ATTR_NV)
|
|
printf("NV ");
|
|
if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE)
|
|
printf("MORE_RELIABLE ");
|
|
if (p->md_attr & EFI_MD_ATTR_RO)
|
|
printf("RO ");
|
|
if (p->md_attr & EFI_MD_ATTR_RT)
|
|
printf("RUNTIME");
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
efi_map_print_entries(struct efi_map_header *efihdr)
|
|
{
|
|
|
|
printf("%23s %12s %12s %8s %4s\n",
|
|
"Type", "Physical", "Virtual", "#Pages", "Attr");
|
|
efi_map_foreach_entry(efihdr, print_efi_map_entry, NULL);
|
|
}
|