#include <sys/param.h>
#include <sys/linker.h>
#include "stand.h"
#include "bootstrap.h"
#include "efi.h"
#include "seg.h"
#include "util.h"
vm_paddr_t efi_systbl_phys;
struct efi_map_header *efi_map_hdr;
uint32_t efi_map_size;
vm_paddr_t efi_map_phys_src;
vm_paddr_t efi_map_phys_dst;
void
efi_set_systbl(uint64_t tbl)
{
efi_systbl_phys = tbl;
}
#if 0
void
efi_read_from_sysfs(void)
{
uint32_t efisz, sz, map_size;
int entries = 0;
struct efi_md *map;
char *buf;
struct stat sb;
char fn[100];
do {
printf("Looking at index %d\n", entries);
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", entries++);
} while (stat(fn, &sb) == 0);
if (entries == 1)
goto err;
entries--;
map_size = sizeof(struct efi_md) * entries;
efisz = roundup2(sizeof(*efi_map_hdr), 16);
sz = efisz + map_size;
buf = malloc(efisz + map_size);
if (buf == NULL)
return;
efi_map_hdr = (struct efi_map_header *)buf;
efi_map_size = sz;
map = (struct efi_md *)(buf + efisz);
bzero(map, sz);
efi_map_hdr->memory_size = map_size;
efi_map_hdr->descriptor_size = sizeof(struct efi_md);
efi_map_hdr->descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION;
for (int i = 0; i < entries; i++) {
struct efi_md *m;
printf("Populating index %d\n", i);
m = map + i;
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/type", i);
if (!file2u32(fn, &m->md_type))
goto err;
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/phys_addr", i);
if (!file2u64(fn, &m->md_phys))
goto err;
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/virt_addr", i);
if (!file2u64(fn, &m->md_virt))
goto err;
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/num_pages", i);
if (!file2u64(fn, &m->md_pages))
goto err;
snprintf(fn, sizeof(fn), "/sys/firmware/efi/runtime-map/%d/attribute", i);
if (!file2u64(fn, &m->md_attr))
goto err;
}
efi_map_phys_src = 0;
printf("UEFI MAP:\n");
print_efi_map(efi_map_hdr);
printf("DONE\n");
return;
err:
printf("Parse error in reading current memory map\n");
}
#endif
bool
efi_read_from_pa(uint64_t pa, uint32_t map_size, uint32_t desc_size, uint32_t vers)
{
uint32_t efisz, sz;
char *buf;
int fd2, len;
struct efi_md *map;
efisz = roundup2(sizeof(*efi_map_hdr), 16);
sz = efisz + map_size;
buf = malloc(efisz + map_size);
if (buf == NULL)
return false;
efi_map_hdr = (struct efi_map_header *)buf;
efi_map_size = sz;
map = (struct efi_md *)(buf + efisz);
bzero(map, sz);
efi_map_hdr->memory_size = map_size;
efi_map_hdr->descriptor_size = desc_size;
efi_map_hdr->descriptor_version = vers;
fd2 = open("host:/dev/mem", O_RDONLY);
if (fd2 < 0)
goto no_read;
if (lseek(fd2, pa, SEEK_SET) < 0)
goto no_read;
len = read(fd2, map, sz);
if (len != sz)
goto no_read;
efi_map_phys_src = 0;
close(fd2);
printf("UEFI MAP:\n");
print_efi_map(efi_map_hdr);
return (true);
no_read:
efi_map_phys_src = pa;
close(fd2);
return (true);
}
void
foreach_efi_map_entry(struct efi_map_header *efihdr, efi_map_entry_cb cb, void *argp)
{
struct efi_md *map, *p;
size_t efisz;
int ndesc, i;
efisz = roundup2(sizeof(struct efi_map_header), 16);
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);
}
}
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 %012lx %012lx %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_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
print_efi_map(struct efi_map_header *efihdr)
{
printf("%23s %12s %12s %8s %4s\n",
"Type", "Physical", "Virtual", "#Pages", "Attr");
foreach_efi_map_entry(efihdr, print_efi_map_entry, NULL);
}
void
efi_bi_loadsmap(struct preloaded_file *kfp)
{
if (efi_systbl_phys)
file_addmetadata(kfp, MODINFOMD_FW_HANDLE, sizeof(efi_systbl_phys), &efi_systbl_phys);
if (efi_map_hdr != NULL) {
file_addmetadata(kfp, MODINFOMD_EFI_MAP, efi_map_size, efi_map_hdr);
return;
}
panic("Can't get UEFI memory map, nor a pointer to it, can't proceed.\n");
}