summaryrefslogtreecommitdiffstats
path: root/common/efi/efi-iomem.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/efi/efi-iomem.c')
-rw-r--r--common/efi/efi-iomem.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/common/efi/efi-iomem.c b/common/efi/efi-iomem.c
new file mode 100644
index 0000000000..e223c595c4
--- /dev/null
+++ b/common/efi/efi-iomem.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Ahmad Fatoum, Pengutronix
+
+#define pr_fmt(fmt) "efi-iomem: " fmt
+
+#include <common.h>
+#include <init.h>
+#include <efi.h>
+#include <efi/efi.h>
+#include <memory.h>
+#include <linux/sizes.h>
+
+static int efi_parse_mmap(struct efi_memory_desc *desc)
+{
+ struct resource *res;
+ u32 flags;
+ const char *name;
+ char *fullname;
+ resource_size_t va_base, va_size;
+ int ret = 0;
+
+ va_size = desc->npages * SZ_4K;
+ if (!va_size)
+ return 0;
+
+ /* XXX At least OVMF doesn't populate ->virt_start and leaves it at zero
+ * for all mapping. Thus assume a 1:1 mapping and ignore virt_start
+ */
+ va_base = desc->phys_start;
+
+ switch (desc->type) {
+ case EFI_RESERVED_TYPE:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "reserved";
+ flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
+ break;
+ case EFI_LOADER_CODE:
+ return barebox_add_memory_bank("loader code", va_base, va_size);
+ case EFI_LOADER_DATA:
+ return barebox_add_memory_bank("loader data", va_base, va_size);
+ case EFI_BOOT_SERVICES_CODE:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "boot services code";
+ flags = IORESOURCE_MEM | IORESOURCE_READONLY;
+ break;
+ case EFI_BOOT_SERVICES_DATA:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "boot services data";
+ flags = IORESOURCE_MEM;
+ break;
+ case EFI_RUNTIME_SERVICES_CODE:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "runtime services code";
+ flags = IORESOURCE_MEM | IORESOURCE_READONLY;
+ break;
+ case EFI_RUNTIME_SERVICES_DATA:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "runtime services data";
+ flags = IORESOURCE_MEM;
+ break;
+ case EFI_CONVENTIONAL_MEMORY:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "conventional memory";
+ flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_CACHEABLE;
+ break;
+ case EFI_UNUSABLE_MEMORY:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "unusable";
+ flags = IORESOURCE_MEM | IORESOURCE_DISABLED;
+ break;
+ case EFI_ACPI_RECLAIM_MEMORY:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "ACPI reclaim memory";
+ flags = IORESOURCE_MEM | IORESOURCE_READONLY;
+ break;
+ case EFI_ACPI_MEMORY_NVS:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "ACPI NVS memory";
+ flags = IORESOURCE_MEM | IORESOURCE_READONLY;
+ break;
+ case EFI_MEMORY_MAPPED_IO:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "MMIO";
+ flags = IORESOURCE_MEM;
+ break;
+ case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "MMIOPORT";
+ flags = IORESOURCE_IO;
+ break;
+ case EFI_PAL_CODE:
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+ name = "PAL code";
+ flags = IORESOURCE_MEM | IORESOURCE_ROM_BIOS_COPY;
+ break;
+ default:
+ if (!(desc->type & (1U << 31))) {
+ pr_warn("illegal memory type = %u >= %u\n",
+ desc->type, EFI_MAX_MEMORY_TYPE);
+ return -EINVAL;
+ }
+
+ if (!IS_ENABLED(DEBUG))
+ return 0;
+
+ name = "vendor reserved";
+ flags = IORESOURCE_MEM | IORESOURCE_ROM_BIOS_COPY;
+ }
+
+ fullname = xasprintf("%s@%llx", name, desc->phys_start);
+
+ pr_debug("%s: (0x%llx+0x%llx)\n", fullname, va_base, va_size);
+
+ res = request_iomem_region(fullname, va_base, va_base + va_size - 1);
+ if (IS_ERR(res)) {
+ ret = PTR_ERR(res);
+ goto out;
+ }
+
+ res->flags |= flags;
+
+out:
+ free(fullname);
+ return ret;
+}
+
+static int efi_barebox_populate_mmap(void)
+{
+ void *desc;
+ u8 *mmap_buf = NULL;
+ efi_status_t efiret;
+ size_t mmap_size;
+ size_t mapkey;
+ size_t descsz;
+ u32 descver;
+ int ret = 0;
+
+ mmap_size = sizeof(struct efi_memory_desc);
+
+ do {
+ mmap_buf = xrealloc(mmap_buf, mmap_size);
+ efiret = BS->get_memory_map(&mmap_size, mmap_buf,
+ &mapkey, &descsz, &descver);
+ } while (efiret == EFI_BUFFER_TOO_SMALL);
+
+ if (EFI_ERROR(efiret)) {
+ ret = -efi_errno(efiret);
+ goto out;
+ }
+
+ if (descver != 1) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ for (desc = mmap_buf; (u8 *)desc < &mmap_buf[mmap_size]; desc += descsz)
+ efi_parse_mmap(desc);
+
+out:
+ free(mmap_buf);
+ return ret;
+}
+mem_initcall(efi_barebox_populate_mmap);