linux,uefi-mmap-desc-ver    32-bit   Version of the mmap descriptor format.
 
-linux,initrd-start          64-bit   Physical start address of an initrd
-
-linux,initrd-end            64-bit   Physical end address of an initrd
-
 kaslr-seed                  64-bit   Entropy used to randomize the kernel image
                                      base address location.
 ==========================  ======   ===========================================
 
 #include <linux/device.h>
 #include <linux/efi.h>
 #include <linux/of.h>
+#include <linux/initrd.h>
 #include <linux/io.h>
 #include <linux/kexec.h>
 #include <linux/platform_device.h>
 unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
 static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata initrd = EFI_INVALID_TABLE_ADDR;
 
 struct mm_struct efi_mm = {
        .mm_rb                  = RB_ROOT,
        {LINUX_EFI_TPM_EVENT_LOG_GUID,          &efi.tpm_log,           "TPMEventLog"   },
        {LINUX_EFI_TPM_FINAL_LOG_GUID,          &efi.tpm_final_log,     "TPMFinalLog"   },
        {LINUX_EFI_MEMRESERVE_TABLE_GUID,       &mem_reserve,           "MEMRESERVE"    },
+       {LINUX_EFI_INITRD_MEDIA_GUID,           &initrd,                "INITRD"        },
        {EFI_RT_PROPERTIES_TABLE_GUID,          &rt_prop,               "RTPROP"        },
 #ifdef CONFIG_EFI_RCI2_TABLE
        {DELLEMC_EFI_RCI2_TABLE_GUID,           &rci2_table_phys                        },
                }
        }
 
+       if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) &&
+           initrd != EFI_INVALID_TABLE_ADDR && phys_initrd_size == 0) {
+               struct linux_efi_initrd *tbl;
+
+               tbl = early_memremap(initrd, sizeof(*tbl));
+               if (tbl) {
+                       phys_initrd_start = tbl->base;
+                       phys_initrd_size = tbl->size;
+                       early_memunmap(tbl, sizeof(*tbl));
+               }
+       }
+
        return 0;
 }
 
 
  * * %EFI_SUCCESS if the initrd was loaded successfully, in which
  *   case @load_addr and @load_size are assigned accordingly
  * * %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd device path
- * * %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
  * * %EFI_OUT_OF_RESOURCES if memory allocation failed
  * * %EFI_LOAD_ERROR in all other cases
  */
 static
-efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
-                                     unsigned long *load_size,
+efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd,
                                      unsigned long max)
 {
        efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
        efi_device_path_protocol_t *dp;
        efi_load_file2_protocol_t *lf2;
-       unsigned long initrd_addr;
-       unsigned long initrd_size;
        efi_handle_t handle;
        efi_status_t status;
 
        if (status != EFI_SUCCESS)
                return status;
 
-       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
+       initrd->size = 0;
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, NULL);
        if (status != EFI_BUFFER_TOO_SMALL)
                return EFI_LOAD_ERROR;
 
-       status = efi_allocate_pages(initrd_size, &initrd_addr, max);
+       status = efi_allocate_pages(initrd->size, &initrd->base, max);
        if (status != EFI_SUCCESS)
                return status;
 
-       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
-                               (void *)initrd_addr);
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd->size,
+                               (void *)initrd->base);
        if (status != EFI_SUCCESS) {
-               efi_free(initrd_size, initrd_addr);
+               efi_free(initrd->size, initrd->base);
                return EFI_LOAD_ERROR;
        }
-
-       *load_addr = initrd_addr;
-       *load_size = initrd_size;
        return EFI_SUCCESS;
 }
 
 static
 efi_status_t efi_load_initrd_cmdline(efi_loaded_image_t *image,
-                                    unsigned long *load_addr,
-                                    unsigned long *load_size,
+                                    struct linux_efi_initrd *initrd,
                                     unsigned long soft_limit,
                                     unsigned long hard_limit)
 {
        if (!IS_ENABLED(CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER) ||
-           (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL))) {
-               *load_addr = *load_size = 0;
-               return EFI_SUCCESS;
-       }
+           (IS_ENABLED(CONFIG_X86) && (!efi_is_native() || image == NULL)))
+               return EFI_UNSUPPORTED;
 
        return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
                                    soft_limit, hard_limit,
-                                   load_addr, load_size);
+                                   &initrd->base, &initrd->size);
 }
 
 static const struct {
 /**
  * efi_load_initrd() - Load initial RAM disk
  * @image:     EFI loaded image protocol
- * @load_addr: pointer to loaded initrd
- * @load_size: size of loaded initrd
  * @soft_limit:        preferred address for loading the initrd
  * @hard_limit:        upper limit address for loading the initrd
  *
  * Return:     status code
  */
 efi_status_t efi_load_initrd(efi_loaded_image_t *image,
-                            unsigned long *load_addr,
-                            unsigned long *load_size,
                             unsigned long soft_limit,
-                            unsigned long hard_limit)
+                            unsigned long hard_limit,
+                            const struct linux_efi_initrd **out)
 {
-       efi_status_t status;
+       efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+       efi_status_t status = EFI_SUCCESS;
+       struct linux_efi_initrd initrd, *tbl;
 
-       if (efi_noinitrd) {
-               *load_addr = *load_size = 0;
-               status = EFI_SUCCESS;
-       } else {
-               status = efi_load_initrd_dev_path(load_addr, load_size, hard_limit);
-               if (status == EFI_SUCCESS) {
-                       efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
-                       if (*load_size > 0)
-                               efi_measure_initrd(*load_addr, *load_size);
-               } else if (status == EFI_NOT_FOUND) {
-                       status = efi_load_initrd_cmdline(image, load_addr, load_size,
-                                                        soft_limit, hard_limit);
-                       if (status == EFI_SUCCESS && *load_size > 0)
-                               efi_info("Loaded initrd from command line option\n");
-               }
-               if (status != EFI_SUCCESS) {
-                       efi_err("Failed to load initrd: 0x%lx\n", status);
-                       *load_addr = *load_size = 0;
-               }
+       if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd)
+               return EFI_SUCCESS;
+
+       status = efi_load_initrd_dev_path(&initrd, hard_limit);
+       if (status == EFI_SUCCESS) {
+               efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
+               if (initrd.size > 0)
+                       efi_measure_initrd(initrd.base, initrd.size);
+       } else if (status == EFI_NOT_FOUND) {
+               status = efi_load_initrd_cmdline(image, &initrd, soft_limit,
+                                                hard_limit);
+               /* command line loader disabled or no initrd= passed? */
+               if (status == EFI_UNSUPPORTED || status == EFI_NOT_READY)
+                       return EFI_SUCCESS;
+               if (status == EFI_SUCCESS)
+                       efi_info("Loaded initrd from command line option\n");
        }
+       if (status != EFI_SUCCESS)
+               goto failed;
+
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(initrd),
+                            (void **)&tbl);
+       if (status != EFI_SUCCESS)
+               goto free_initrd;
+
+       *tbl = initrd;
+       status = efi_bs_call(install_configuration_table, &tbl_guid, tbl);
+       if (status != EFI_SUCCESS)
+               goto free_tbl;
+
+       if (out)
+               *out = tbl;
+       return EFI_SUCCESS;
 
+free_tbl:
+       efi_bs_call(free_pool, tbl);
+free_initrd:
+       efi_free(initrd.size, initrd.base);
+failed:
+       efi_err("Failed to load initrd: 0x%lx\n", status);
        return status;
 }
 
 
        unsigned long image_addr;
        unsigned long image_size = 0;
        /* addr/point and size pairs for memory management*/
-       unsigned long initrd_addr = 0;
-       unsigned long initrd_size = 0;
        unsigned long fdt_addr = 0;  /* Original DTB */
        unsigned long fdt_size = 0;
        char *cmdline_ptr = NULL;
        } else {
                status = efi_load_dtb(image, &fdt_addr, &fdt_size);
 
-               if (status != EFI_SUCCESS) {
+               if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
                        efi_err("Failed to load device tree!\n");
                        goto fail_free_image;
                }
        if (!fdt_addr)
                efi_info("Generating empty DTB\n");
 
-       efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX,
-                       efi_get_max_initrd_addr(image_addr));
+       efi_load_initrd(image, ULONG_MAX, efi_get_max_initrd_addr(image_addr),
+                       NULL);
 
        efi_random_get_seed();
 
 
        install_memreserve_table();
 
-       status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
-                                               initrd_addr, initrd_size,
-                                               cmdline_ptr, fdt_addr, fdt_size);
+       status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr, cmdline_ptr,
+                                               fdt_addr, fdt_size);
        if (status != EFI_SUCCESS)
-               goto fail_free_initrd;
+               goto fail_free_fdt;
 
        if (IS_ENABLED(CONFIG_ARM))
                efi_handle_post_ebs_state();
        efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
        /* not reached */
 
-fail_free_initrd:
+fail_free_fdt:
        efi_err("Failed to update FDT and exit boot services\n");
 
-       efi_free(initrd_size, initrd_addr);
        efi_free(fdt_size, fdt_addr);
 
 fail_free_image:
 
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
-                                           u64 initrd_addr, u64 initrd_size,
                                            char *cmdline_ptr,
                                            unsigned long fdt_addr,
                                            unsigned long fdt_size);
 }
 
 efi_status_t efi_load_initrd(efi_loaded_image_t *image,
-                            unsigned long *load_addr,
-                            unsigned long *load_size,
                             unsigned long soft_limit,
-                            unsigned long hard_limit);
+                            unsigned long hard_limit,
+                            const struct linux_efi_initrd **out);
 /*
  * This function handles the architcture specific differences between arm and
  * arm64 regarding where the kernel image must be loaded and any memory that
 
 }
 
 static efi_status_t update_fdt(void *orig_fdt, unsigned long orig_fdt_size,
-                              void *fdt, int new_fdt_size, char *cmdline_ptr,
-                              u64 initrd_addr, u64 initrd_size)
+                              void *fdt, int new_fdt_size, char *cmdline_ptr)
 {
        int node, num_rsv;
        int status;
                        goto fdt_set_fail;
        }
 
-       /* Set initrd address/end in device tree, if present */
-       if (initrd_size != 0) {
-               u64 initrd_image_end;
-               u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
-
-               status = fdt_setprop_var(fdt, node, "linux,initrd-start", initrd_image_start);
-               if (status)
-                       goto fdt_set_fail;
-
-               initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
-               status = fdt_setprop_var(fdt, node, "linux,initrd-end", initrd_image_end);
-               if (status)
-                       goto fdt_set_fail;
-       }
-
        /* Add FDT entries for EFI runtime services in chosen node. */
        node = fdt_subnode_offset(fdt, 0, "chosen");
        fdt_val64 = cpu_to_fdt64((u64)(unsigned long)efi_system_table);
 #endif
 
 /*
- * Allocate memory for a new FDT, then add EFI, commandline, and
- * initrd related fields to the FDT.  This routine increases the
- * FDT allocation size until the allocated memory is large
- * enough.  EFI allocations are in EFI_PAGE_SIZE granules,
- * which are fixed at 4K bytes, so in most cases the first
- * allocation should succeed.
- * EFI boot services are exited at the end of this function.
- * There must be no allocations between the get_memory_map()
- * call and the exit_boot_services() call, so the exiting of
- * boot services is very tightly tied to the creation of the FDT
- * with the final memory map in it.
+ * Allocate memory for a new FDT, then add EFI and commandline related fields
+ * to the FDT.  This routine increases the FDT allocation size until the
+ * allocated memory is large enough.  EFI allocations are in EFI_PAGE_SIZE
+ * granules, which are fixed at 4K bytes, so in most cases the first allocation
+ * should succeed.  EFI boot services are exited at the end of this function.
+ * There must be no allocations between the get_memory_map() call and the
+ * exit_boot_services() call, so the exiting of boot services is very tightly
+ * tied to the creation of the FDT with the final memory map in it.
  */
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
-                                           u64 initrd_addr, u64 initrd_size,
                                            char *cmdline_ptr,
                                            unsigned long fdt_addr,
                                            unsigned long fdt_size)
        }
 
        status = update_fdt((void *)fdt_addr, fdt_size,
-                           (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr,
-                           initrd_addr, initrd_size);
+                           (void *)*new_fdt_addr, MAX_FDT_SIZE, cmdline_ptr);
 
        if (status != EFI_SUCCESS) {
                efi_err("Unable to construct new device tree.\n");
 
 
        if (volume)
                volume->close(volume);
+
+       if (*load_size == 0)
+               return EFI_NOT_READY;
        return EFI_SUCCESS;
 
 err_close_file:
 
        unsigned long bzimage_addr = (unsigned long)startup_32;
        unsigned long buffer_start, buffer_end;
        struct setup_header *hdr = &boot_params->hdr;
-       unsigned long addr, size;
+       const struct linux_efi_initrd *initrd = NULL;
        efi_status_t status;
 
        efi_system_table = sys_table_arg;
         * arguments will be processed only if image is not NULL, which will be
         * the case only if we were loaded via the PE entry point.
         */
-       status = efi_load_initrd(image, &addr, &size, hdr->initrd_addr_max,
-                                ULONG_MAX);
+       status = efi_load_initrd(image, hdr->initrd_addr_max, ULONG_MAX,
+                                &initrd);
        if (status != EFI_SUCCESS)
                goto fail;
-       if (size > 0) {
-               efi_set_u64_split(addr, &hdr->ramdisk_image,
+       if (initrd && initrd->size > 0) {
+               efi_set_u64_split(initrd->base, &hdr->ramdisk_image,
                                  &boot_params->ext_ramdisk_image);
-               efi_set_u64_split(size, &hdr->ramdisk_size,
+               efi_set_u64_split(initrd->size, &hdr->ramdisk_size,
                                  &boot_params->ext_ramdisk_size);
        }
 
+
        /*
         * If the boot loader gave us a value for secure_boot then we use that,
         * otherwise we ask the BIOS.
 
        u64     size;
 };
 
+struct linux_efi_initrd {
+       unsigned long   base;
+       unsigned long   size;
+};
+
 /* Header of a populated EFI secret area */
 #define EFI_SECRET_TABLE_HEADER_GUID   EFI_GUID(0x1e74f542, 0x71dd, 0x4d66,  0x96, 0x3e, 0xef, 0x42, 0x87, 0xff, 0x17, 0x3b)