Merge branch 'for-2023.07' of https://source.denx.de/u-boot/custodians/u-boot-mpc8xx
[platform/kernel/u-boot.git] / lib / efi_loader / efi_device_path.c
index 398dbc6..e2e98a3 100644 (file)
@@ -5,6 +5,8 @@
  * (C) Copyright 2017 Rob Clark
  */
 
+#define LOG_CATEGORY LOGC_EFI
+
 #include <common.h>
 #include <blk.h>
 #include <dm.h>
 #include <nvme.h>
 #include <efi_loader.h>
 #include <part.h>
-#include <sandboxblockdev.h>
+#include <uuid.h>
 #include <asm-generic/unaligned.h>
 #include <linux/compat.h> /* U16_MAX */
 
+#ifdef CONFIG_BLKMAP
+const efi_guid_t efi_guid_blkmap_dev = U_BOOT_BLKMAP_DEV_GUID;
+#endif
 #ifdef CONFIG_SANDBOX
 const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
 #endif
@@ -27,7 +32,7 @@ const efi_guid_t efi_guid_virtio_dev = U_BOOT_VIRTIO_DEV_GUID;
 #endif
 
 /* template END node: */
-static const struct efi_device_path END = {
+const struct efi_device_path END = {
        .type     = DEVICE_PATH_TYPE_END,
        .sub_type = DEVICE_PATH_SUB_TYPE_END,
        .length   = sizeof(END),
@@ -43,12 +48,12 @@ static const struct efi_device_path_vendor ROOT = {
        .guid = U_BOOT_GUID,
 };
 
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+#if defined(CONFIG_MMC)
 /*
  * Determine if an MMC device is an SD card.
  *
  * @desc       block device descriptor
- * @return     true if the device is an SD card
+ * Return:     true if the device is an SD card
  */
 static bool is_sd(struct blk_desc *desc)
 {
@@ -61,20 +66,6 @@ static bool is_sd(struct blk_desc *desc)
 }
 #endif
 
-static void *dp_alloc(size_t sz)
-{
-       void *buf;
-
-       if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
-           EFI_SUCCESS) {
-               debug("EFI: ERROR: out of memory in %s\n", __func__);
-               return NULL;
-       }
-
-       memset(buf, 0, sz);
-       return buf;
-}
-
 /*
  * Iterate to next block in device-path, terminating (returning NULL)
  * at /End* node.
@@ -119,28 +110,24 @@ int efi_dp_match(const struct efi_device_path *a,
        }
 }
 
-/*
- * We can have device paths that start with a USB WWID or a USB Class node,
- * and a few other cases which don't encode the full device path with bus
- * hierarchy:
+/**
+ * efi_dp_shorten() - shorten device-path
+ *
+ * When creating a short boot option we want to use a device-path that is
+ * independent of the location where the block device is plugged in.
+ *
+ * UsbWwi() nodes contain a serial number, hard drive paths a partition
+ * UUID. Both should be unique.
  *
- *   - MESSAGING:USB_WWID
- *   - MESSAGING:USB_CLASS
- *   - MEDIA:FILE_PATH
- *   - MEDIA:HARD_DRIVE
- *   - MESSAGING:URI
+ * See UEFI spec, section 3.1.2 for "short-form device path".
  *
- * See UEFI spec (section 3.1.2, about short-form device-paths)
+ * @dp:                original device-path
+ * @Return:    shortened device-path or NULL
  */
-static struct efi_device_path *shorten_path(struct efi_device_path *dp)
+struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp)
 {
        while (dp) {
-               /*
-                * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
-                * in practice fallback.efi just uses MEDIA:HARD_DRIVE
-                * so not sure when we would see these other cases.
-                */
-               if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
+               if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_WWI) ||
                    EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
                    EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
                        return dp;
@@ -151,76 +138,97 @@ static struct efi_device_path *shorten_path(struct efi_device_path *dp)
        return dp;
 }
 
-static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
-                                  struct efi_device_path **rem)
+/**
+ * find_handle() - find handle by device path and installed protocol
+ *
+ * If @rem is provided, the handle with the longest partial match is returned.
+ *
+ * @dp:                device path to search
+ * @guid:      GUID of protocol that must be installed on path or NULL
+ * @short_path:        use short form device path for matching
+ * @rem:       pointer to receive remaining device path
+ * Return:     matching handle
+ */
+static efi_handle_t find_handle(struct efi_device_path *dp,
+                               const efi_guid_t *guid, bool short_path,
+                               struct efi_device_path **rem)
 {
-       struct efi_object *efiobj;
-       efi_uintn_t dp_size = efi_dp_instance_size(dp);
+       efi_handle_t handle, best_handle = NULL;
+       efi_uintn_t len, best_len = 0;
+
+       len = efi_dp_instance_size(dp);
 
-       list_for_each_entry(efiobj, &efi_obj_list, link) {
+       list_for_each_entry(handle, &efi_obj_list, link) {
                struct efi_handler *handler;
-               struct efi_device_path *obj_dp;
+               struct efi_device_path *dp_current;
+               efi_uintn_t len_current;
                efi_status_t ret;
 
-               ret = efi_search_protocol(efiobj,
-                                         &efi_guid_device_path, &handler);
+               if (guid) {
+                       ret = efi_search_protocol(handle, guid, &handler);
+                       if (ret != EFI_SUCCESS)
+                               continue;
+               }
+               ret = efi_search_protocol(handle, &efi_guid_device_path,
+                                         &handler);
                if (ret != EFI_SUCCESS)
                        continue;
-               obj_dp = handler->protocol_interface;
-
-               do {
-                       if (efi_dp_match(dp, obj_dp) == 0) {
-                               if (rem) {
-                                       /*
-                                        * Allow partial matches, but inform
-                                        * the caller.
-                                        */
-                                       *rem = ((void *)dp) +
-                                               efi_dp_instance_size(obj_dp);
-                                       return efiobj;
-                               } else {
-                                       /* Only return on exact matches */
-                                       if (efi_dp_instance_size(obj_dp) ==
-                                           dp_size)
-                                               return efiobj;
-                               }
-                       }
-
-                       obj_dp = shorten_path(efi_dp_next(obj_dp));
-               } while (short_path && obj_dp);
+               dp_current = handler->protocol_interface;
+               if (short_path) {
+                       dp_current = efi_dp_shorten(dp_current);
+                       if (!dp_current)
+                               continue;
+               }
+               len_current = efi_dp_instance_size(dp_current);
+               if (rem) {
+                       if (len_current > len)
+                               continue;
+               } else {
+                       if (len_current != len)
+                               continue;
+               }
+               if (memcmp(dp_current, dp, len_current))
+                       continue;
+               if (!rem)
+                       return handle;
+               if (len_current > best_len) {
+                       best_len = len_current;
+                       best_handle = handle;
+                       *rem = (void*)((u8 *)dp + len_current);
+               }
        }
-
-       return NULL;
+       return best_handle;
 }
 
-/*
- * Find an efiobj from device-path, if 'rem' is not NULL, returns the
- * remaining part of the device path after the matched object.
+/**
+ * efi_dp_find_obj() - find handle by device path
+ *
+ * If @rem is provided, the handle with the longest partial match is returned.
+ *
+ * @dp:                device path to search
+ * @guid:      GUID of protocol that must be installed on path or NULL
+ * @rem:       pointer to receive remaining device path
+ * Return:     matching handle
  */
-struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
-                                  struct efi_device_path **rem)
+efi_handle_t efi_dp_find_obj(struct efi_device_path *dp,
+                            const efi_guid_t *guid,
+                            struct efi_device_path **rem)
 {
-       struct efi_object *efiobj;
-
-       /* Search for an exact match first */
-       efiobj = find_obj(dp, false, NULL);
-
-       /* Then for a fuzzy match */
-       if (!efiobj)
-               efiobj = find_obj(dp, false, rem);
+       efi_handle_t handle;
 
-       /* And now for a fuzzy short match */
-       if (!efiobj)
-               efiobj = find_obj(dp, true, rem);
+       handle = find_handle(dp, guid, false, rem);
+       if (!handle)
+               /* Match short form device path */
+               handle = find_handle(dp, guid, true, rem);
 
-       return efiobj;
+       return handle;
 }
 
 /*
  * Determine the last device path node that is not the end node.
  *
  * @dp         device path
- * @return     last node before the end node if it exists
+ * Return:     last node before the end node if it exists
  *             otherwise NULL
  */
 const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
@@ -274,7 +282,7 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
        if (!dp)
                return NULL;
 
-       ndp = dp_alloc(sz);
+       ndp = efi_alloc(sz);
        if (!ndp)
                return NULL;
        memcpy(ndp, dp, sz);
@@ -282,11 +290,31 @@ struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
        return ndp;
 }
 
-struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
-                                     const struct efi_device_path *dp2)
+/**
+ * efi_dp_append_or_concatenate() - Append or concatenate two device paths.
+ *                                 Concatenated device path will be separated
+ *                                 by a sub-type 0xff end node
+ *
+ * @dp1:       First device path
+ * @dp2:       Second device path
+ * @concat:    If true the two device paths will be concatenated and separated
+ *             by an end of entrire device path sub-type 0xff end node.
+ *             If true the second device path will be appended to the first and
+ *             terminated by an end node
+ *
+ * Return:
+ * concatenated device path or NULL. Caller must free the returned value
+ */
+static struct
+efi_device_path *efi_dp_append_or_concatenate(const struct efi_device_path *dp1,
+                                             const struct efi_device_path *dp2,
+                                             bool concat)
 {
        struct efi_device_path *ret;
+       size_t end_size = sizeof(END);
 
+       if (concat)
+               end_size = 2 * sizeof(END);
        if (!dp1 && !dp2) {
                /* return an end node */
                ret = efi_dp_dup(&END);
@@ -298,18 +326,58 @@ struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
                /* both dp1 and dp2 are non-null */
                unsigned sz1 = efi_dp_size(dp1);
                unsigned sz2 = efi_dp_size(dp2);
-               void *p = dp_alloc(sz1 + sz2 + sizeof(END));
+               void *p = efi_alloc(sz1 + sz2 + end_size);
                if (!p)
                        return NULL;
+               ret = p;
                memcpy(p, dp1, sz1);
+               p += sz1;
+
+               if (concat) {
+                       memcpy(p, &END, sizeof(END));
+                       p += sizeof(END);
+               }
+
                /* the end node of the second device path has to be retained */
-               memcpy(p + sz1, dp2, sz2 + sizeof(END));
-               ret = p;
+               memcpy(p, dp2, sz2);
+               p += sz2;
+               memcpy(p, &END, sizeof(END));
        }
 
        return ret;
 }
 
+/**
+ * efi_dp_append() - Append a device to an existing device path.
+ *
+ * @dp1:       First device path
+ * @dp2:       Second device path
+ *
+ * Return:
+ * concatenated device path or NULL. Caller must free the returned value
+ */
+struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
+                                     const struct efi_device_path *dp2)
+{
+       return efi_dp_append_or_concatenate(dp1, dp2, false);
+}
+
+/**
+ * efi_dp_concat() - Concatenate 2 device paths. The final device path will
+ *                   contain two device paths separated by and end node (0xff).
+ *
+ * @dp1:       First device path
+ * @dp2:       Second device path
+ *
+ * Return:
+ * concatenated device path or NULL. Caller must free the returned value
+ */
+struct efi_device_path *efi_dp_concat(const struct efi_device_path *dp1,
+                                     const struct efi_device_path *dp2)
+{
+       return efi_dp_append_or_concatenate(dp1, dp2, true);
+}
+
 struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
                                           const struct efi_device_path *node)
 {
@@ -321,7 +389,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
                ret = efi_dp_dup(dp);
        } else if (!dp) {
                size_t sz = node->length;
-               void *p = dp_alloc(sz + sizeof(END));
+               void *p = efi_alloc(sz + sizeof(END));
                if (!p)
                        return NULL;
                memcpy(p, node, sz);
@@ -330,7 +398,7 @@ struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
        } else {
                /* both dp and node are non-null */
                size_t sz = efi_dp_size(dp);
-               void *p = dp_alloc(sz + node->length + sizeof(END));
+               void *p = efi_alloc(sz + node->length + sizeof(END));
                if (!p)
                        return NULL;
                memcpy(p, dp, sz);
@@ -351,7 +419,7 @@ struct efi_device_path *efi_dp_create_device_node(const u8 type,
        if (length < sizeof(struct efi_device_path))
                return NULL;
 
-       ret = dp_alloc(length);
+       ret = efi_alloc(length);
        if (!ret)
                return ret;
        ret->type = type;
@@ -373,7 +441,7 @@ struct efi_device_path *efi_dp_append_instance(
                return efi_dp_dup(dpi);
        sz = efi_dp_size(dp);
        szi = efi_dp_instance_size(dpi);
-       p = dp_alloc(sz + szi + 2 * sizeof(END));
+       p = efi_alloc(sz + szi + 2 * sizeof(END));
        if (!p)
                return NULL;
        ret = p;
@@ -398,7 +466,7 @@ struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
        if (!dp || !*dp)
                return NULL;
        sz = efi_dp_instance_size(*dp);
-       p = dp_alloc(sz + sizeof(END));
+       p = efi_alloc(sz + sizeof(END));
        if (!p)
                return NULL;
        memcpy(p, *dp, sz + sizeof(END));
@@ -423,7 +491,6 @@ bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
        return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
 }
 
-#ifdef CONFIG_DM
 /* size of device-path not including END node for device and all parents
  * up to the root device.
  */
@@ -432,7 +499,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
        if (!dev || !dev->driver)
                return sizeof(ROOT);
 
-       switch (dev->driver->id) {
+       switch (device_get_uclass_id(dev)) {
        case UCLASS_ROOT:
        case UCLASS_SIMPLE_BUS:
                /* stop traversing parents at this point: */
@@ -440,7 +507,6 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
        case UCLASS_ETH:
                return dp_size(dev->parent) +
                        sizeof(struct efi_device_path_mac_addr);
-#ifdef CONFIG_BLK
        case UCLASS_BLK:
                switch (dev->parent->uclass->uc_drv->id) {
 #ifdef CONFIG_IDE
@@ -448,12 +514,12 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
                        return dp_size(dev->parent) +
                                sizeof(struct efi_device_path_atapi);
 #endif
-#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
+#if defined(CONFIG_SCSI)
                case UCLASS_SCSI:
                        return dp_size(dev->parent) +
                                sizeof(struct efi_device_path_scsi);
 #endif
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+#if defined(CONFIG_MMC)
                case UCLASS_MMC:
                        return dp_size(dev->parent) +
                                sizeof(struct efi_device_path_sd_mmc_path);
@@ -469,7 +535,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
                                sizeof(struct efi_device_path_nvme);
 #endif
 #ifdef CONFIG_SANDBOX
-               case UCLASS_ROOT:
+               case UCLASS_HOST:
                         /*
                          * Sandbox's host device will be represented
                          * as vendor device with extra one byte for
@@ -478,6 +544,11 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
                        return dp_size(dev->parent)
                                + sizeof(struct efi_device_path_vendor) + 1;
 #endif
+#ifdef CONFIG_USB
+               case UCLASS_MASS_STORAGE:
+                       return dp_size(dev->parent)
+                               + sizeof(struct efi_device_path_controller);
+#endif
 #ifdef CONFIG_VIRTIO_BLK
                case UCLASS_VIRTIO:
                         /*
@@ -488,11 +559,20 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
                        return dp_size(dev->parent)
                                + sizeof(struct efi_device_path_vendor) + 1;
 #endif
+#ifdef CONFIG_BLKMAP
+               case UCLASS_BLKMAP:
+                        /*
+                         * blkmap devices will be represented as a vendor
+                         * device node with an extra byte for the device
+                         * number.
+                         */
+                       return dp_size(dev->parent)
+                               + sizeof(struct efi_device_path_vendor) + 1;
+#endif
                default:
                        return dp_size(dev->parent);
                }
-#endif
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+#if defined(CONFIG_MMC)
        case UCLASS_MMC:
                return dp_size(dev->parent) +
                        sizeof(struct efi_device_path_sd_mmc_path);
@@ -500,7 +580,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
        case UCLASS_MASS_STORAGE:
        case UCLASS_USB_HUB:
                return dp_size(dev->parent) +
-                       sizeof(struct efi_device_path_usb_class);
+                       sizeof(struct efi_device_path_usb);
        default:
                /* just skip over unknown classes: */
                return dp_size(dev->parent);
@@ -512,14 +592,14 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
  *
  * @buf                pointer to the end of the device path
  * @dev                device
- * @return     pointer to the end of the device path
+ * Return:     pointer to the end of the device path
  */
 __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
 {
        if (!dev || !dev->driver)
                return buf;
 
-       switch (dev->driver->id) {
+       switch (device_get_uclass_id(dev)) {
        case UCLASS_ROOT:
        case UCLASS_SIMPLE_BUS: {
                /* stop traversing parents at this point: */
@@ -527,7 +607,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                *vdp = ROOT;
                return &vdp[1];
        }
-#ifdef CONFIG_DM_ETH
+#ifdef CONFIG_NETDEVICES
        case UCLASS_ETH: {
                struct efi_device_path_mac_addr *dp =
                        dp_fill(buf, dev->parent);
@@ -544,11 +624,27 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                return &dp[1];
        }
 #endif
-#ifdef CONFIG_BLK
        case UCLASS_BLK:
                switch (dev->parent->uclass->uc_drv->id) {
+#ifdef CONFIG_BLKMAP
+               case UCLASS_BLKMAP: {
+                       struct efi_device_path_vendor *dp;
+                       struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+                       dp_fill(buf, dev->parent);
+                       dp = buf;
+                       ++dp;
+                       dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+                       dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+                       dp->dp.length = sizeof(*dp) + 1;
+                       memcpy(&dp->guid, &efi_guid_blkmap_dev,
+                              sizeof(efi_guid_t));
+                       dp->vendor_data[0] = desc->devnum;
+                       return &dp->vendor_data[1];
+                       }
+#endif
 #ifdef CONFIG_SANDBOX
-               case UCLASS_ROOT: {
+               case UCLASS_HOST: {
                        /* stop traversing parents at this point: */
                        struct efi_device_path_vendor *dp;
                        struct blk_desc *desc = dev_get_uclass_plat(dev);
@@ -599,7 +695,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                        return &dp[1];
                        }
 #endif
-#if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
+#if defined(CONFIG_SCSI)
                case UCLASS_SCSI: {
                        struct efi_device_path_scsi *dp =
                                dp_fill(buf, dev->parent);
@@ -613,7 +709,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                        return &dp[1];
                        }
 #endif
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+#if defined(CONFIG_MMC)
                case UCLASS_MMC: {
                        struct efi_device_path_sd_mmc_path *sddp =
                                dp_fill(buf, dev->parent);
@@ -658,14 +754,26 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                        return &dp[1];
                        }
 #endif
+#if defined(CONFIG_USB)
+               case UCLASS_MASS_STORAGE: {
+                       struct blk_desc *desc = dev_get_uclass_plat(dev);
+                       struct efi_device_path_controller *dp =
+                               dp_fill(buf, dev->parent);
+
+                       dp->dp.type     = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+                       dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CONTROLLER;
+                       dp->dp.length   = sizeof(*dp);
+                       dp->controller_number = desc->lun;
+                       return &dp[1];
+               }
+#endif
                default:
                        debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
                              __FILE__, __LINE__, __func__,
                              dev->name, dev->parent->uclass->uc_drv->id);
                        return dp_fill(buf, dev->parent);
                }
-#endif
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
+#if defined(CONFIG_MMC)
        case UCLASS_MMC: {
                struct efi_device_path_sd_mmc_path *sddp =
                        dp_fill(buf, dev->parent);
@@ -684,47 +792,39 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
 #endif
        case UCLASS_MASS_STORAGE:
        case UCLASS_USB_HUB: {
-               struct efi_device_path_usb_class *udp =
-                       dp_fill(buf, dev->parent);
-               struct usb_device *udev = dev_get_parent_priv(dev);
-               struct usb_device_descriptor *desc = &udev->descriptor;
+               struct efi_device_path_usb *udp = dp_fill(buf, dev->parent);
+
+               switch (device_get_uclass_id(dev->parent)) {
+               case UCLASS_USB_HUB: {
+                       struct usb_device *udev = dev_get_parent_priv(dev);
 
+                       udp->parent_port_number = udev->portnr;
+                       break;
+               }
+               default:
+                       udp->parent_port_number = 0;
+               }
                udp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
-               udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
+               udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
                udp->dp.length   = sizeof(*udp);
-               udp->vendor_id   = desc->idVendor;
-               udp->product_id  = desc->idProduct;
-               udp->device_class    = desc->bDeviceClass;
-               udp->device_subclass = desc->bDeviceSubClass;
-               udp->device_protocol = desc->bDeviceProtocol;
+               udp->usb_interface = 0;
 
                return &udp[1];
        }
        default:
-               debug("%s(%u) %s: unhandled device class: %s (%u)\n",
-                     __FILE__, __LINE__, __func__,
-                     dev->name, dev->driver->id);
+               /* If the uclass driver is missing, this will show NULL */
+               log_debug("unhandled device class: %s (%s)\n", dev->name,
+                         dev_get_uclass_name(dev));
                return dp_fill(buf, dev->parent);
        }
 }
-#endif
 
 static unsigned dp_part_size(struct blk_desc *desc, int part)
 {
        unsigned dpsize;
+       struct udevice *dev = desc->bdev;
 
-#ifdef CONFIG_BLK
-       {
-               struct udevice *dev;
-               int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
-
-               if (ret)
-                       dev = desc->bdev->parent;
-               dpsize = dp_size(dev);
-       }
-#else
-       dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
-#endif
+       dpsize = dp_size(dev);
 
        if (part == 0) /* the actual disk, not a partition */
                return dpsize;
@@ -791,8 +891,16 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
                        break;
                case SIG_TYPE_GUID:
                        hddp->signature_type = 2;
-                       memcpy(hddp->partition_signature, &desc->guid_sig,
-                              sizeof(hddp->partition_signature));
+#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
+                       /* info.uuid exists only with PARTITION_UUIDS */
+                       if (uuid_str_to_bin(info.uuid,
+                                           hddp->partition_signature,
+                                           UUID_STR_FORMAT_GUID)) {
+                               log_warning(
+                                       "Partition %d: invalid GUID %s\n",
+                                       part, info.uuid);
+                       }
+#endif
                        break;
                }
 
@@ -811,36 +919,9 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
  */
 static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
 {
-#ifdef CONFIG_BLK
-       {
-               struct udevice *dev;
-               int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
+       struct udevice *dev = desc->bdev;
 
-               if (ret)
-                       dev = desc->bdev->parent;
-               buf = dp_fill(buf, dev);
-       }
-#else
-       /*
-        * We *could* make a more accurate path, by looking at if_type
-        * and handling all the different cases like we do for non-
-        * legacy (i.e. CONFIG_BLK=y) case. But most important thing
-        * is just to have a unique device-path for if_type+devnum.
-        * So map things to a fictitious USB device.
-        */
-       struct efi_device_path_usb *udp;
-
-       memcpy(buf, &ROOT, sizeof(ROOT));
-       buf += sizeof(ROOT);
-
-       udp = buf;
-       udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
-       udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
-       udp->dp.length = sizeof(*udp);
-       udp->parent_port_number = desc->if_type;
-       udp->usb_interface = desc->devnum;
-       buf = &udp[1];
-#endif
+       buf = dp_fill(buf, dev);
 
        if (part == 0) /* the actual disk, not a partition */
                return buf;
@@ -853,7 +934,7 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
 {
        void *buf, *start;
 
-       start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
+       start = buf = efi_alloc(dp_part_size(desc, part) + sizeof(END));
        if (!buf)
                return NULL;
 
@@ -880,9 +961,10 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
                dpsize = sizeof(struct efi_device_path_cdrom_path);
        else
                dpsize = sizeof(struct efi_device_path_hard_drive_path);
-       buf = dp_alloc(dpsize);
+       buf = efi_alloc(dpsize);
 
-       dp_part_node(buf, desc, part);
+       if (buf)
+               dp_part_node(buf, desc, part);
 
        return buf;
 }
@@ -919,9 +1001,22 @@ static void path_to_uefi(void *uefi, const char *src)
        *pos = 0;
 }
 
-/*
- * If desc is NULL, this creates a path with only the file component,
- * otherwise it creates a full path with both device and file components
+/**
+ * efi_dp_from_file() - create device path for file
+ *
+ * The function creates a device path from the block descriptor @desc and the
+ * partition number @part and appends a device path node created describing the
+ * file path @path.
+ *
+ * If @desc is NULL, the device path will not contain nodes describing the
+ * partition.
+ * If @path is an empty string "", the device path will not contain a node
+ * for the file path.
+ *
+ * @desc:      block device descriptor or NULL
+ * @part:      partition number
+ * @path:      file path on partition or ""
+ * Return:     device path or NULL in case of an error
  */
 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
                const char *path)
@@ -940,7 +1035,7 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
 
        dpsize += fpsize;
 
-       start = buf = dp_alloc(dpsize + sizeof(END));
+       start = buf = efi_alloc(dpsize + sizeof(END));
        if (!buf)
                return NULL;
 
@@ -948,12 +1043,14 @@ struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
                buf = dp_part_fill(buf, desc, part);
 
        /* add file-path: */
-       fp = buf;
-       fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
-       fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
-       fp->dp.length = (u16)fpsize;
-       path_to_uefi(fp->str, path);
-       buf += fpsize;
+       if (*path) {
+               fp = buf;
+               fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
+               fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
+               fp->dp.length = (u16)fpsize;
+               path_to_uefi(fp->str, path);
+               buf += fpsize;
+       }
 
        *((struct efi_device_path *)buf) = END;
 
@@ -966,7 +1063,7 @@ struct efi_device_path *efi_dp_from_uart(void)
        struct efi_device_path_uart *uart;
        size_t dpsize = sizeof(ROOT) + sizeof(*uart) + sizeof(END);
 
-       buf = dp_alloc(dpsize);
+       buf = efi_alloc(dpsize);
        if (!buf)
                return NULL;
        pos = buf;
@@ -982,42 +1079,21 @@ struct efi_device_path *efi_dp_from_uart(void)
        return buf;
 }
 
-#ifdef CONFIG_NET
+#ifdef CONFIG_NETDEVICES
 struct efi_device_path *efi_dp_from_eth(void)
 {
-#ifndef CONFIG_DM_ETH
-       struct efi_device_path_mac_addr *ndp;
-#endif
        void *buf, *start;
        unsigned dpsize = 0;
 
        assert(eth_get_dev());
 
-#ifdef CONFIG_DM_ETH
        dpsize += dp_size(eth_get_dev());
-#else
-       dpsize += sizeof(ROOT);
-       dpsize += sizeof(*ndp);
-#endif
 
-       start = buf = dp_alloc(dpsize + sizeof(END));
+       start = buf = efi_alloc(dpsize + sizeof(END));
        if (!buf)
                return NULL;
 
-#ifdef CONFIG_DM_ETH
        buf = dp_fill(buf, eth_get_dev());
-#else
-       memcpy(buf, &ROOT, sizeof(ROOT));
-       buf += sizeof(ROOT);
-
-       ndp = buf;
-       ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
-       ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
-       ndp->dp.length = sizeof(*ndp);
-       ndp->if_type = 1; /* Ethernet */
-       memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
-       buf = &ndp[1];
-#endif
 
        *((struct efi_device_path *)buf) = END;
 
@@ -1033,7 +1109,7 @@ struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
        struct efi_device_path_memory *mdp;
        void *buf, *start;
 
-       start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
+       start = buf = efi_alloc(sizeof(*mdp) + sizeof(END));
        if (!buf)
                return NULL;
 
@@ -1110,21 +1186,30 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
 {
        struct blk_desc *desc = NULL;
        struct disk_partition fs_partition;
+       size_t image_size;
+       void *image_addr;
        int part = 0;
-       char filename[32] = { 0 }; /* dp->str is u16[32] long */
+       char *filename;
        char *s;
 
        if (path && !file)
                return EFI_INVALID_PARAMETER;
 
        if (!strcmp(dev, "Net")) {
-#ifdef CONFIG_NET
+#ifdef CONFIG_NETDEVICES
                if (device)
                        *device = efi_dp_from_eth();
 #endif
        } else if (!strcmp(dev, "Uart")) {
                if (device)
                        *device = efi_dp_from_uart();
+       } else if (!strcmp(dev, "Mem")) {
+               efi_get_image_parameters(&image_addr, &image_size);
+
+               if (device)
+                       *device = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
+                                                 (uintptr_t)image_addr,
+                                                 image_size);
        } else {
                part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
                                               1);
@@ -1138,12 +1223,17 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
        if (!path)
                return EFI_SUCCESS;
 
-       snprintf(filename, sizeof(filename), "%s", path);
+       filename = calloc(1, strlen(path) + 1);
+       if (!filename)
+               return EFI_OUT_OF_RESOURCES;
+
+       sprintf(filename, "%s", path);
        /* DOS style file path: */
        s = filename;
        while ((s = strchr(s, '/')))
                *s++ = '\\';
        *file = efi_dp_from_file(desc, part, filename);
+       free(filename);
 
        if (!*file)
                return EFI_INVALID_PARAMETER;
@@ -1183,3 +1273,69 @@ ssize_t efi_dp_check_length(const struct efi_device_path *dp,
                dp = (const struct efi_device_path *)((const u8 *)dp + len);
        }
 }
+
+/**
+ * efi_dp_from_lo() - Get the instance of a VenMedia node in a
+ *                    multi-instance device path that matches
+ *                    a specific GUID. This kind of device paths
+ *                    is found in Boot#### options describing an
+ *                    initrd location
+ *
+ * @lo:                EFI_LOAD_OPTION containing a valid device path
+ * @guid:      guid to search for
+ *
+ * Return:
+ * device path including the VenMedia node or NULL.
+ * Caller must free the returned value.
+ */
+struct
+efi_device_path *efi_dp_from_lo(struct efi_load_option *lo,
+                               const efi_guid_t *guid)
+{
+       struct efi_device_path *fp = lo->file_path;
+       struct efi_device_path_vendor *vendor;
+       int lo_len = lo->file_path_length;
+
+       for (; lo_len >=  sizeof(struct efi_device_path);
+            lo_len -= fp->length, fp = (void *)fp + fp->length) {
+               if (lo_len < 0 || efi_dp_check_length(fp, lo_len) < 0)
+                       break;
+               if (fp->type != DEVICE_PATH_TYPE_MEDIA_DEVICE ||
+                   fp->sub_type != DEVICE_PATH_SUB_TYPE_VENDOR_PATH)
+                       continue;
+
+               vendor = (struct efi_device_path_vendor *)fp;
+               if (!guidcmp(&vendor->guid, guid))
+                       return efi_dp_dup(efi_dp_next(fp));
+       }
+       log_debug("VenMedia(%pUl) not found in %ls\n", &guid, lo->label);
+
+       return NULL;
+}
+
+/**
+ * search_gpt_dp_node() - search gpt device path node
+ *
+ * @device_path:       device path
+ *
+ * Return:     pointer to the gpt device path node
+ */
+struct efi_device_path *search_gpt_dp_node(struct efi_device_path *device_path)
+{
+       struct efi_device_path *dp = device_path;
+
+       while (dp) {
+               if (dp->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
+                   dp->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
+                       struct efi_device_path_hard_drive_path *hd_dp =
+                               (struct efi_device_path_hard_drive_path *)dp;
+
+                       if (hd_dp->partmap_type == PART_FORMAT_GPT &&
+                           hd_dp->signature_type == SIG_TYPE_GUID)
+                               return dp;
+               }
+               dp = efi_dp_next(dp);
+       }
+
+       return NULL;
+}