]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
blkmap: pass information on ISO image to the OS
authorSughosh Ganu <sughosh.ganu@linaro.org>
Mon, 17 Mar 2025 08:34:02 +0000 (14:04 +0530)
committerIlias Apalodimas <ilias.apalodimas@linaro.org>
Wed, 26 Mar 2025 11:28:08 +0000 (13:28 +0200)
The EFI HTTP boot puts the ISO installer image at some location in
memory. Information about this image has to be passed on to the OS
kernel, which is done by adding a persistent memory(pmem) node to the
devicetree(DT) that is passed to the OS. The OS kernel then gets
information about the presence of this ISO image and proceeds with the
installation.

In U-Boot, this ISO image gets mounted as a memory mapped blkmap
device slice, with the 'preserve' attribute. Add a helper function
which iterates through all such slices, and invokes a callback. The
callback adds the pmem node to the DT and removes the corresponding
memory region from the EFI memory map. Invoke this helper function as
part of the DT fixup which happens before booting the OS.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Tobias Waldekranz <tobias@waldekranz.com>
Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
boot/image-fdt.c
drivers/block/blkmap.c
include/blkmap.h
include/efi.h
lib/efi_loader/efi_helper.c

index 9d1598b1a93cc96d41aae9f36d8369a737bb4e13..8f718ad29f6b7af9cb1d0cedc8e4c038eb3020fc 100644 (file)
@@ -11,6 +11,7 @@
 #include <command.h>
 #include <fdt_support.h>
 #include <fdtdec.h>
+#include <efi.h>
 #include <env.h>
 #include <errno.h>
 #include <image.h>
@@ -649,6 +650,12 @@ int image_setup_libfdt(struct bootm_headers *images, void *blob, bool lmb)
        if (!ft_verify_fdt(blob))
                goto err;
 
+       if (CONFIG_IS_ENABLED(BLKMAP) && CONFIG_IS_ENABLED(EFI_LOADER)) {
+               fdt_ret = fdt_efi_pmem_setup(blob);
+               if (fdt_ret)
+                       goto err;
+       }
+
        /* after here we are using a livetree */
        if (!of_live_active() && CONFIG_IS_ENABLED(EVENT)) {
                struct event_ft_fixup fixup;
index 1b161bd90bee3d2c5319a7a82cdbc9b1664ea20a..473c65b59114e334ec0ab368ec29d25a82eeac92 100644 (file)
@@ -517,6 +517,49 @@ err:
        return err;
 }
 
+static bool blkmap_mem_preserve_slice(struct blkmap_slice *bms)
+{
+       return (bms->attr & (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE)) ==
+               (BLKMAP_SLICE_MEM | BLKMAP_SLICE_PRESERVE);
+}
+
+int blkmap_get_preserved_pmem_slices(int (*cb)(void *ctx, u64 addr,
+                                              u64 size), void *ctx)
+{
+       int ret;
+       u64 addr, size;
+       struct udevice *dev;
+       struct uclass *uc;
+       struct blkmap *bm;
+       struct blkmap_mem *bmm;
+       struct blkmap_slice *bms;
+       struct blk_desc *bd;
+
+       if (!cb) {
+               log_debug("%s: No callback passed to the function\n", __func__);
+               return 0;
+       }
+
+       uclass_id_foreach_dev(UCLASS_BLKMAP, dev, uc) {
+               bm = dev_get_plat(dev);
+               bd = dev_get_uclass_plat(bm->blk);
+
+               list_for_each_entry(bms, &bm->slices, node) {
+                       if (!blkmap_mem_preserve_slice(bms))
+                               continue;
+
+                       bmm = container_of(bms, struct blkmap_mem, slice);
+                       addr = (u64)(uintptr_t)bmm->addr;
+                       size = (u64)bms->blkcnt << bd->log2blksz;
+                       ret = cb(ctx, addr, size);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
 int blkmap_destroy(struct udevice *dev)
 {
        int err;
index 754d8671b010709c08340448375fc3003621ccae..57555fda4fb7b3826b56308c4e9f387fa7001f28 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef _BLKMAP_H
 #define _BLKMAP_H
 
+#include <blk.h>
 #include <dm/lists.h>
 
 /**
@@ -104,4 +105,32 @@ int blkmap_destroy(struct udevice *dev);
 int blkmap_create_ramdisk(const char *label, ulong image_addr, ulong image_size,
                          struct udevice **devp);
 
+/**
+ * blkmap_get_preserved_pmem_slices() - Look for memory mapped preserved slices
+ * @cb: Callback function to call for the blkmap slice
+ * @ctx: Argument to be passed to the callback function
+ *
+ * The function is used to iterate through all the blkmap slices, looking
+ * specifically for memory mapped blkmap mapping which has been
+ * created with the preserve attribute. The function looks for such slices
+ * with the relevant attributes and then calls the callback function which
+ * then does additional configuration as needed. The callback function is
+ * invoked for all the discovered slices, unless there is an error returned
+ * by the callback, in which case the function returns that error.
+ *
+ * The callback function has the following arguments
+ * @ctx:       Argument to be passed to the callback function
+ * @addr:      Start address of the memory mapped slice
+ * @size:      Size of the memory mapped slice
+ *
+ * Typically, the callback will perform some configuration needed for the
+ * information passed on to it. An example of this would be setting up the
+ * pmem node in a device-tree(passed through the ctx argument) with the
+ * parameters passed on to the callback.
+ *
+ * Return: 0 on success, negative error on failure
+ */
+int blkmap_get_preserved_pmem_slices(int (*cb)(void *ctx, u64 addr,
+                                              u64 size), void *ctx);
+
 #endif /* _BLKMAP_H */
index d005cb6181edb9a3730fcc7b13aae93ea816ce31..f9bbb175c3a94d1302ff74818fa5c071b7ed40c5 100644 (file)
@@ -705,4 +705,17 @@ static inline bool efi_use_host_arch(void)
  */
 int efi_get_pxe_arch(void);
 
+/**
+ * fdt_efi_pmem_setup() - Pmem setup in DT and EFI memory map
+ * @fdt: Devicetree to add the pmem nodes to
+ *
+ * Iterate through all the blkmap devices, look for BLKMAP_MEM devices,
+ * and add pmem nodes corresponding to the blkmap slice to the
+ * devicetree along with removing the corresponding region from the
+ * EFI memory map.
+ *
+ * Returns: 0 on success, negative error on failure
+ */
+int fdt_efi_pmem_setup(void *fdt);
+
 #endif /* _LINUX_EFI_H */
index f6fbcdffe8260451c329e9b92ec59f348e158edd..8c32059eddab866a74609b13b435a7cc5b9ba92b 100644 (file)
@@ -5,6 +5,7 @@
 
 #define LOG_CATEGORY LOGC_EFI
 
+#include <blkmap.h>
 #include <bootm.h>
 #include <env.h>
 #include <image.h>
@@ -687,3 +688,44 @@ out:
 
        return ret;
 }
+
+/**
+ * pmem_node_efi_memmap_setup() - Add pmem node and tweak EFI memmap
+ * @fdt: The devicetree to which pmem node is added
+ * @addr: start address of the pmem node
+ * @size: size of the memory of the pmem node
+ *
+ * The function adds the pmem node to the device-tree along with removing
+ * the corresponding region from the EFI memory map. Used primarily to
+ * pass the information of a RAM based ISO image to the OS.
+ *
+ * Return: 0 on success, -ve value on error
+ */
+static int pmem_node_efi_memmap_setup(void *fdt, u64 addr, u64 size)
+{
+       int ret;
+       u64 pages;
+       efi_status_t status;
+
+       ret = fdt_fixup_pmem_region(fdt, addr, size);
+       if (ret) {
+               log_err("Failed to setup pmem node for addr %#llx, size %#llx, err %d\n",
+                       addr, size, ret);
+               return ret;
+       }
+
+       /* Remove the pmem region from the EFI memory map */
+       pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
+       status = efi_update_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY,
+                                      false, true);
+       if (status != EFI_SUCCESS)
+               return -1;
+
+       return 0;
+}
+
+int fdt_efi_pmem_setup(void *fdt)
+{
+       return blkmap_get_preserved_pmem_slices(pmem_node_efi_memmap_setup,
+                                               fdt);
+}