efi_loader: device path for virtio block devices

The UEFI specification does not define a device sub-type for virtio.
Let's use a vendor hardware node here.

This avoids creation of two handles with the same device path indicating
our root node.

Reported-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 4b48f99..9533df2 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -45,6 +45,10 @@
 #define U_BOOT_HOST_DEV_GUID \
 	EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \
 		 0x9a, 0xab, 0x3a, 0x7d, 0xbf, 0x40, 0xc4, 0x82)
+/* GUID used as root for virtio devices */
+#define U_BOOT_VIRTIO_DEV_GUID \
+	EFI_GUID(0x63293792, 0xadf5, 0x9325, \
+		 0xb9, 0x9f, 0x4e, 0x0e, 0x45, 0x5c, 0x1b, 0x1e)
 
 /* Use internal device tree when starting UEFI application */
 #define EFI_FDT_USE_INTERNAL NULL
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 2b537c1..f049b9e 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -22,6 +22,9 @@
 #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: */
 static const struct efi_device_path END = {
@@ -470,6 +473,16 @@
 			return dp_size(dev->parent)
 				+ sizeof(struct efi_device_path_vendor) + 1;
 #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
 		default:
 			return dp_size(dev->parent);
 		}
@@ -547,6 +560,23 @@
 			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_platdata(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_virtio_dev,
+			       sizeof(efi_guid_t));
+			dp->vendor_data[0] = desc->devnum;
+			return &dp->vendor_data[1];
+			}
+#endif
 #ifdef CONFIG_IDE
 		case UCLASS_IDE: {
 			struct efi_device_path_atapi *dp =