summaryrefslogtreecommitdiff
path: root/usr/src/boot/efi/loader/memmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/boot/efi/loader/memmap.c')
-rw-r--r--usr/src/boot/efi/loader/memmap.c181
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);
+}