diff options
Diffstat (limited to 'usr/src/boot/efi/loader/memmap.c')
| -rw-r--r-- | usr/src/boot/efi/loader/memmap.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/usr/src/boot/efi/loader/memmap.c b/usr/src/boot/efi/loader/memmap.c new file mode 100644 index 0000000000..f3545a4d64 --- /dev/null +++ b/usr/src/boot/efi/loader/memmap.c @@ -0,0 +1,181 @@ +/* + * 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 __unused, char *argv[] __unused) +{ + 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); +} |
