amd64: Parse the EFI memory map if present

With this change (and loader.efi from the projects/uefi branch) we can now
boot under qemu using the OVMF UEFI firmware image with the limitation
that a serial console is required.

(This is largely r246337 from the projects/uefi branch.)

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Ed Maste 2014-03-27 18:23:02 +00:00
parent fe930c5220
commit c018226f1a
2 changed files with 113 additions and 4 deletions

View File

@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <sys/callout.h>
#include <sys/cons.h>
#include <sys/cpu.h>
#include <sys/efi.h>
#include <sys/eventhandler.h>
#include <sys/exec.h>
#include <sys/imgact.h>
@ -1431,10 +1432,105 @@ bios_add_smap_entries(struct bios_smap *smapbase, u_int32_t smapsize,
}
}
#define efi_next_descriptor(ptr, size) \
((struct efi_md *)(((uint8_t *) ptr) + size))
static void
add_efi_map_entries(struct efi_map_header *efihdr, vm_paddr_t *physmap,
int *physmap_idx)
{
struct efi_md *map, *p;
const char *type;
size_t efisz;
int ndesc, i;
static const char *types[] = {
"Reserved",
"LoaderCode",
"LoaderData",
"BootServicesCode",
"BootServicesData",
"RuntimeServicesCode",
"RuntimeServicesData",
"ConventionalMemory",
"UnusableMemory",
"ACPIReclaimMemory",
"ACPIMemoryNVS",
"MemoryMappedIO",
"MemoryMappedIOPortSpace",
"PalCode"
};
/*
* 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;
if (boothowto & RB_VERBOSE)
printf("%23s %12s %12s %8s %4s\n",
"Type", "Physical", "Virtual", "#Pages", "Attr");
for (i = 0, p = map; i < ndesc; i++,
p = efi_next_descriptor(p, efihdr->descriptor_size)) {
if (boothowto & RB_VERBOSE) {
if (p->md_type <= EFI_MD_TYPE_PALCODE)
type = types[p->md_type];
else
type = "<INVALID>";
printf("%23s %012lx %12p %08lx ", type, p->md_phys,
p->md_virt, 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_RT)
printf("RUNTIME");
printf("\n");
}
switch (p->md_type) {
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.
*/
break;
default:
continue;
}
if (!add_physmap_entry(p->md_phys, (p->md_pages * PAGE_SIZE),
physmap, physmap_idx))
break;
}
}
static void
native_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx)
{
struct bios_smap *smap;
struct efi_map_header *efihdr;
u_int32_t size;
/*
@ -1445,13 +1541,19 @@ native_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx)
* ie: an int32_t immediately precedes smap.
*/
efihdr = (struct efi_map_header *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_EFI_MAP);
smap = (struct bios_smap *)preload_search_info(kmdp,
MODINFO_METADATA | MODINFOMD_SMAP);
if (smap == NULL)
panic("No BIOS smap info from loader!");
size = *((u_int32_t *)smap - 1);
if (efihdr == NULL && smap == NULL)
panic("No BIOS smap or EFI map info from loader!");
bios_add_smap_entries(smap, size, physmap, physmap_idx);
if (efihdr != NULL) {
add_efi_map_entries(efihdr, physmap, physmap_idx);
} else {
size = *((u_int32_t *)smap - 1);
bios_add_smap_entries(smap, size, physmap, physmap_idx);
}
}
/*

View File

@ -32,5 +32,12 @@
#define MODINFOMD_SMAP 0x1001
#define MODINFOMD_SMAP_XATTR 0x1002
#define MODINFOMD_DTBP 0x1003
#define MODINFOMD_EFI_MAP 0x1004
struct efi_map_header {
size_t memory_size;
size_t descriptor_size;
uint32_t descriptor_version;
};
#endif /* !_MACHINE_METADATA_H_ */