]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
efi_loader: device paths for special block devices
authorHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Thu, 20 Jul 2023 22:03:46 +0000 (00:03 +0200)
committerHeinrich Schuchardt <heinrich.schuchardt@canonical.com>
Fri, 28 Jul 2023 09:36:37 +0000 (11:36 +0200)
The UEFI specification does not provide node types matching UCLASS_BLKMAP,
UCLASS_HOST, UCLASS_VIRTIO block devices.

The current implementation uses VenHw() nodes with uclass specific GUIDs
and a single byte for the device number appended. This leads to unaligned
integers in succeeding device path nodes.

The current implementation fails to create unique device paths for block
devices based on other uclasses like UCLASS_PVBLOCK.

Let's use a VenHw() node with the U-Boot GUID with a length dividable by
four and encoding blkdesc->uclass_id as well as  blkdesc->devnum.

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
lib/efi_loader/efi_device_path.c

index 19e8861ef492a2aaf7223beb0dbddd1ff0b3cacb..5b050fa17c50345b13a0effad530d01a51acbc22 100644 (file)
 #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
-#ifdef CONFIG_VIRTIO_BLK
-const efi_guid_t efi_guid_virtio_dev = U_BOOT_VIRTIO_DEV_GUID;
-#endif
-
 /* template END node: */
 const struct efi_device_path END = {
        .type     = DEVICE_PATH_TYPE_END,
@@ -524,43 +514,15 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev)
                        return dp_size(dev->parent) +
                                sizeof(struct efi_device_path_nvme);
 #endif
-#ifdef CONFIG_SANDBOX
-               case UCLASS_HOST:
-                        /*
-                         * Sandbox's host device will be represented
-                         * as vendor device with extra one byte for
-                         * device number
-                         */
-                       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:
-                        /*
-                         * Virtio 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
-#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);
+                       /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
+                       return dp_size(dev->parent) +
+                               sizeof(struct efi_device_path_udevice);
                }
 #if defined(CONFIG_MMC)
        case UCLASS_MMC:
@@ -608,53 +570,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
        }
 #endif
        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 = dp_fill(buf, dev->parent);
-                       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_HOST: {
-                       /* stop traversing parents at this point: */
-                       struct efi_device_path_vendor *dp;
-                       struct blk_desc *desc = dev_get_uclass_plat(dev);
-
-                       dp = dp_fill(buf, dev->parent);
-                       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_host_dev,
-                              sizeof(efi_guid_t));
-                       dp->vendor_data[0] = desc->devnum;
-                       return &dp->vendor_data[1];
-                       }
-#endif
-#ifdef CONFIG_VIRTIO_BLK
-               case UCLASS_VIRTIO: {
-                       struct efi_device_path_vendor *dp;
-                       struct blk_desc *desc = dev_get_uclass_plat(dev);
-
-                       dp = dp_fill(buf, dev->parent);
-                       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_virtio_dev,
-                              sizeof(efi_guid_t));
-                       dp->vendor_data[0] = desc->devnum;
-                       return &dp->vendor_data[1];
-                       }
-#endif
+               switch (device_get_uclass_id(dev->parent)) {
 #ifdef CONFIG_IDE
                case UCLASS_IDE: {
                        struct efi_device_path_atapi *dp =
@@ -744,12 +660,24 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
                        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);
+               default: {
+                       /* UCLASS_BLKMAP, UCLASS_HOST, UCLASS_VIRTIO */
+                       struct efi_device_path_udevice *dp;
+                       struct blk_desc *desc = dev_get_uclass_plat(dev);
+
+                       dp = dp_fill(buf, dev->parent);
+                       dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+                       dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+                       dp->dp.length = sizeof(*dp);
+                       memcpy(&dp->guid, &efi_u_boot_guid,
+                              sizeof(efi_guid_t));
+                       dp->uclass_id = (UCLASS_BLK & 0xffff) |
+                                       (desc->uclass_id << 16);
+                       dp->dev_number = desc->devnum;
+
+                       return &dp[1];
                }
+       }
 #if defined(CONFIG_MMC)
        case UCLASS_MMC: {
                struct efi_device_path_sd_mmc_path *sddp =