OVMF is "UEFI boot firmware for virtual machines", hence a new use case
for efibootmgr. A virtual machine can have virtio-blk disks, and OVMF
supports them with the VirtioBlkDxe driver. Let's recognize such disks,
and produce correct boot options for them.

For now the user has to specify "-e 3" on the command line, to enable EDD
3.0 support under OVMF. (The autodetection code in get_edd_version() seems
to be EFI inheritance, it doesn't work under UEFI / edk2.)

With this patch, efibootmgr generates the following device path scheme for
virtio-blk disks, matching the ones installed by VirtioBlkDxe:

  ACPI(a0341d0,0)PCI(7,0)\
  HD(1,800,64000,87b09cbe-32b9-4737-8ecc-c1e65702cfb6)\
  File(\EFI\redhat\grub.efi)

Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=998611

Signed-off-by: Laszlo Ersek <ler...@redhat.com>
---
 src/include/disk.h |    3 +-
 src/lib/disk.c     |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/lib/efi.c      |   17 ++++++----
 3 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/src/include/disk.h b/src/include/disk.h
index 368a6e1..5e11c0f 100644
--- a/src/include/disk.h
+++ b/src/include/disk.h
@@ -63,7 +63,8 @@
 enum _bus_type {bus_type_unknown, isa, pci};
 enum _interface_type {interface_type_unknown,
                      ata, atapi, scsi, usb,
-                     i1394, fibre, i2o, md};
+                     i1394, fibre, i2o, md,
+                     virtblk};
 
 
 unsigned int lcm(unsigned int x, unsigned int y);
diff --git a/src/lib/disk.c b/src/lib/disk.c
index 3f1f2a1..8486414 100644
--- a/src/lib/disk.c
+++ b/src/lib/disk.c
@@ -26,6 +26,7 @@
 #include <sys/time.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
 #include "disk.h"
 #include "scsi_ioctls.h"
 #include "gpt.h"
@@ -33,6 +34,47 @@
 
 #define BLKSSZGET  _IO(0x12,104)       /* get block device sector size */
 
+/* The major device number for virtio-blk disks is decided on module load time.
+ */
+static int
+get_virtblk_major(void)
+{
+       static int cached;
+       FILE *f;
+       char line[256];
+
+       if (cached != 0) {
+               return cached;
+       }
+
+       cached = -1;
+       f = fopen("/proc/devices", "r");
+       if (f == NULL) {
+               fprintf(stderr, "%s: opening /proc/devices: %s\n", __func__,
+                       strerror(errno));
+               return cached;
+       }
+       while (fgets(line, sizeof line, f) != NULL) {
+               size_t len = strlen(line);
+               int major, scanned;
+
+               if (len == 0 || line[len - 1] != '\n') {
+                       break;
+               }
+               if (sscanf(line, "%d %n", &major, &scanned) == 1 &&
+                   strcmp(line + scanned, "virtblk\n") == 0) {
+                       cached = major;
+                       break;
+               }
+       }
+       fclose(f);
+       if (cached == -1) {
+               fprintf(stderr, "%s: virtio-blk driver unavailable\n",
+                       __func__);
+       }
+       return cached;
+}
+
 int
 disk_info_from_fd(int fd, 
                  int *interface_type,
@@ -126,12 +168,45 @@ disk_info_from_fd(int fd,
                *part    = (minor & 0xF);
                return 0;
        }
-           
+
+       if (get_virtblk_major() != -1 && get_virtblk_major() == major) {
+               *interface_type = virtblk;
+               *disknum = minor >> 4;
+               *part = minor & 0xF;
+               return 0;
+       }
+
        printf("Unknown interface type.\n");
        return 1;
 }
 
 static int
+disk_get_virt_pci(unsigned disknum, unsigned part, unsigned char *bus,
+                 unsigned char *device, unsigned char *function)
+{
+       char inbuf[32], outbuf[128];
+       ssize_t lnksz;
+
+       if (snprintf(inbuf, sizeof inbuf, "/sys/dev/block/%d:%u",
+                    get_virtblk_major(),
+                    disknum << 4 | part) >= sizeof inbuf) {
+               return 1;
+       }
+
+       lnksz = readlink(inbuf, outbuf, sizeof outbuf);
+       if (lnksz == -1 || lnksz == sizeof outbuf) {
+               return 1;
+       }
+
+       outbuf[lnksz] = '\0';
+       if (sscanf(outbuf, "../../devices/pci0000:00/0000:%hhx:%hhx.%hhx",
+                  bus, device, function) != 3) {
+               return 1;
+       }
+       return 0;
+}
+
+static int
 disk_get_scsi_pci(int fd, 
             unsigned char *bus,
             unsigned char *device,
@@ -267,6 +342,8 @@ disk_get_pci(int fd,
                break;
        case md:
                break;
+       case virtblk:
+               return disk_get_virt_pci(disknum, part, bus, device, function);
        default:
                break;
        }
diff --git a/src/lib/efi.c b/src/lib/efi.c
index 9465cab..9fc35e2 100644
--- a/src/lib/efi.c
+++ b/src/lib/efi.c
@@ -476,18 +476,21 @@ make_edd30_device_path(int fd, void *buffer)
        unsigned char host=0, channel=0, id=0, lun=0;
        char *p = buffer;
 
-
        rc = disk_get_pci(fd, &interface_type, &bus, &device, &function);
        if (rc) return 0;
-
-       memset(&idlun, 0, sizeof(idlun));
-       rc = get_scsi_idlun(fd, &idlun);
-       if (rc) return 0;
-       idlun_to_components(&idlun, &host, &channel, &id, &lun);
+       if (interface_type != virtblk) {
+               memset(&idlun, 0, sizeof(idlun));
+               rc = get_scsi_idlun(fd, &idlun);
+               if (rc) return 0;
+               idlun_to_components(&idlun, &host, &channel, &id, &lun);
+       }
 
        p += make_acpi_device_path      (p, EISAID_PNP0A03, bus);
        p += make_pci_device_path       (p, bus, device, function);
-       p += make_scsi_device_path      (p, id, lun);
+       if (interface_type != virtblk) {
+               p += make_scsi_device_path(p, id, lun);
+       }
+
        return ((void *)p - buffer);
 }
 
-- 
1.7.1



------------------------------------------------------------------------------
Introducing Performance Central, a new site from SourceForge and 
AppDynamics. Performance Central is your source for news, insights, 
analysis and resources for efficient Application Performance Management. 
Visit us today!
http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to