blob: 9862e51b5a805cc353b11ec6a80f37765b651b79 [file] [log] [blame]
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2016 Toomas Soome <tsoome@me.com>
*/
/*
* Build smap like memory map from efi memmap.
*/
#include <stand.h>
#include <inttypes.h>
#include <efi.h>
#include <efilib.h>
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/queue.h>
#include <sys/stddef.h>
#include <machine/metadata.h>
#include <machine/pc/bios.h>
#include "bootstrap.h"
struct smap_buf {
struct bios_smap sb_smap;
STAILQ_ENTRY(smap_buf) sb_bufs;
};
static struct bios_smap *smapbase;
static int smaplen;
/*
* See ACPI 6.1 Table 15-330 UEFI Memory Types and mapping to ACPI address
* range types.
*/
static int
smap_type(int type)
{
switch (type) {
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
return (SMAP_TYPE_MEMORY);
case EfiReservedMemoryType:
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiPalCode:
case EfiUnusableMemory:
return (SMAP_TYPE_RESERVED);
case EfiACPIReclaimMemory:
return (SMAP_TYPE_ACPI_RECLAIM);
case EfiACPIMemoryNVS:
return (SMAP_TYPE_ACPI_NVS);
}
return (SMAP_TYPE_RESERVED);
}
void
efi_getsmap(void)
{
UINTN size, desc_size, key;
EFI_MEMORY_DESCRIPTOR *efi_mmap, *p;
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS status;
STAILQ_HEAD(smap_head, smap_buf) head =
STAILQ_HEAD_INITIALIZER(head);
struct smap_buf *cur, *next;
int i, n, ndesc;
int type = -1;
size = 0;
efi_mmap = NULL;
status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL);
efi_mmap = malloc(size);
status = BS->GetMemoryMap(&size, efi_mmap, &key, &desc_size, NULL);
if (EFI_ERROR(status)) {
printf("GetMemoryMap: error %lu\n", EFI_ERROR_CODE(status));
free(efi_mmap);
return;
}
STAILQ_INIT(&head);
n = 0;
i = 0;
p = efi_mmap;
next = NULL;
ndesc = size / desc_size;
while (i < ndesc) {
if (next == NULL) {
next = malloc(sizeof(*next));
if (next == NULL)
break;
next->sb_smap.base = p->PhysicalStart;
next->sb_smap.length =
p->NumberOfPages << EFI_PAGE_SHIFT;
/*
* ACPI 6.1 tells the lower memory should be
* reported as normal memory, so we enforce
* page 0 type even as vmware maps it as
* acpi reclaimable.
*/
if (next->sb_smap.base == 0)
type = SMAP_TYPE_MEMORY;
else
type = smap_type(p->Type);
next->sb_smap.type = type;
STAILQ_INSERT_TAIL(&head, next, sb_bufs);
n++;
p = NextMemoryDescriptor(p, desc_size);
i++;
continue;
}
addr = next->sb_smap.base + next->sb_smap.length;
if ((smap_type(p->Type) == type) &&
(p->PhysicalStart == addr)) {
next->sb_smap.length +=
(p->NumberOfPages << EFI_PAGE_SHIFT);
p = NextMemoryDescriptor(p, desc_size);
i++;
} else
next = NULL;
}
smaplen = n;
if (smaplen > 0) {
smapbase = malloc(smaplen * sizeof(*smapbase));
if (smapbase != NULL) {
n = 0;
STAILQ_FOREACH(cur, &head, sb_bufs)
smapbase[n++] = cur->sb_smap;
}
cur = STAILQ_FIRST(&head);
while (cur != NULL) {
next = STAILQ_NEXT(cur, sb_bufs);
free(cur);
cur = next;
}
}
free(efi_mmap);
}
void
efi_addsmapdata(struct preloaded_file *kfp)
{
size_t size;
if (smapbase == NULL || smaplen == 0)
return;
size = smaplen * sizeof(*smapbase);
file_addmetadata(kfp, MODINFOMD_SMAP, size, smapbase);
}
COMMAND_SET(smap, "smap", "show BIOS SMAP", command_smap);
static int
command_smap(int argc, char *argv[])
{
u_int i;
if (smapbase == NULL || smaplen == 0)
return (CMD_ERROR);
for (i = 0; i < smaplen; i++)
printf("SMAP type=%02" PRIx32 " base=%016" PRIx64
" len=%016" PRIx64 "\n", smapbase[i].type,
smapbase[i].base, smapbase[i].length);
return (CMD_OK);
}