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