efi_loader: round the memory area in efi_add_memory_map()
[oweals/u-boot.git] / cmd / bootefi.c
index 56bdff33c64732fc6f6671b08478121133d9e742..9849eb4f9950da0d0c008d3ec1b14760cfcc71bf 100644 (file)
@@ -13,6 +13,7 @@
 #include <efi_selftest.h>
 #include <env.h>
 #include <errno.h>
+#include <malloc.h>
 #include <linux/libfdt.h>
 #include <linux/libfdt_env.h>
 #include <mapmem.h>
@@ -126,13 +127,13 @@ static efi_status_t copy_fdt(void **fdtp)
        new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 +
                                             fdt_size, 0);
        ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
-                                EFI_BOOT_SERVICES_DATA, fdt_pages,
+                                EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
                                 &new_fdt_addr);
        if (ret != EFI_SUCCESS) {
                /* If we can't put it there, put it somewhere */
                new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
                ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
-                                        EFI_BOOT_SERVICES_DATA, fdt_pages,
+                                        EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
                                         &new_fdt_addr);
                if (ret != EFI_SUCCESS) {
                        printf("ERROR: Failed to reserve space for FDT\n");
@@ -148,6 +149,16 @@ done:
        return ret;
 }
 
+static void efi_reserve_memory(u64 addr, u64 size)
+{
+       /* Convert from sandbox address space. */
+       addr = (uintptr_t)map_sysmem(addr, 0);
+       if (efi_add_memory_map(addr, size,
+                              EFI_RESERVED_MEMORY_TYPE) != EFI_SUCCESS)
+               printf("Reserved memory mapping failed addr %llx size %llx\n",
+                      addr, size);
+}
+
 /**
  * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
  *
@@ -160,7 +171,8 @@ done:
 static void efi_carve_out_dt_rsv(void *fdt)
 {
        int nr_rsv, i;
-       uint64_t addr, size, pages;
+       u64 addr, size;
+       int nodeoffset, subnode;
 
        nr_rsv = fdt_num_mem_rsv(fdt);
 
@@ -168,15 +180,26 @@ static void efi_carve_out_dt_rsv(void *fdt)
        for (i = 0; i < nr_rsv; i++) {
                if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0)
                        continue;
+               efi_reserve_memory(addr, size);
+       }
 
-               /* Convert from sandbox address space. */
-               addr = (uintptr_t)map_sysmem(addr, 0);
-
-               pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
-               addr &= ~EFI_PAGE_MASK;
-               if (efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE,
-                                      false) != EFI_SUCCESS)
-                       printf("FDT memrsv map %d: Failed to add to map\n", i);
+       /* process reserved-memory */
+       nodeoffset = fdt_subnode_offset(fdt, 0, "reserved-memory");
+       if (nodeoffset >= 0) {
+               subnode = fdt_first_subnode(fdt, nodeoffset);
+               while (subnode >= 0) {
+                       /* check if this subnode has a reg property */
+                       addr = fdtdec_get_addr_size(fdt, subnode, "reg",
+                                                   (fdt_size_t *)&size);
+                       /*
+                        * The /reserved-memory node may have children with
+                        * a size instead of a reg property.
+                        */
+                       if (addr != FDT_ADDR_T_NONE &&
+                           fdtdec_get_is_enabled(fdt, subnode))
+                               efi_reserve_memory(addr, size);
+                       subnode = fdt_next_subnode(fdt, subnode);
+               }
        }
 }
 
@@ -202,15 +225,15 @@ static void *get_config_table(const efi_guid_t *guid)
 /**
  * efi_install_fdt() - install device tree
  *
- * If fdt_addr is available, the device tree located at that memory address will
- * will be installed as configuration table, otherwise the device tree located
- * at the address indicated by environment variable fdt_addr or as fallback
- * fdtcontroladdr will be used.
+ * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
+ * address will will be installed as configuration table, otherwise the device
+ * tree located at the address indicated by environment variable fdt_addr or as
+ * fallback fdtcontroladdr will be used.
  *
  * On architectures using ACPI tables device trees shall not be installed as
  * configuration table.
  *
- * @fdt_addr:  address of device tree or EFI_FDT_USE_INTERNAL to use the
+ * @fdt:       address of device tree or EFI_FDT_USE_INTERNAL to use the
  *             the hardware device tree as indicated by environment variable
  *             fdt_addr or as fallback the internal device tree as indicated by
  *             the environment variable fdtcontroladdr
@@ -262,9 +285,6 @@ efi_status_t efi_install_fdt(void *fdt)
                return EFI_LOAD_ERROR;
        }
 
-       /* Create memory reservations as indicated by the device tree */
-       efi_carve_out_dt_rsv(fdt);
-
        /* Prepare device tree for payload */
        ret = copy_fdt(&fdt);
        if (ret) {
@@ -277,6 +297,9 @@ efi_status_t efi_install_fdt(void *fdt)
                return EFI_LOAD_ERROR;
        }
 
+       /* Create memory reservations as indicated by the device tree */
+       efi_carve_out_dt_rsv(fdt);
+
        /* Install device tree as UEFI table */
        ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
        if (ret != EFI_SUCCESS) {
@@ -454,10 +477,8 @@ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
        ret = do_bootefi_exec(handle);
 
 out:
-       if (mem_handle)
-               efi_delete_handle(mem_handle);
-       if (file_path)
-               efi_free_pool(file_path);
+       efi_delete_handle(mem_handle);
+       efi_free_pool(file_path);
        return ret;
 }