vmd(8): scan pci bus to determine bootorder strings.
authordv <dv@openbsd.org>
Mon, 6 Feb 2023 20:33:34 +0000 (20:33 +0000)
committerdv <dv@openbsd.org>
Mon, 6 Feb 2023 20:33:34 +0000 (20:33 +0000)
vmd's SeaBIOS bootorder strings had hardcoded pci device ids, so
if a user added a network interface the bootorder strings didn't
line up with reality. Using vmctl(8) to boot from a cdrom (-B cdrom)
would fail, for instance, if attaching both a nic and a disk as
well.

This change scans the pci devices and finds the first of each type
to construct viable bootorder strings.

ok jan@

usr.sbin/vmd/fw_cfg.c
usr.sbin/vmd/pci.c
usr.sbin/vmd/pci.h
usr.sbin/vmd/vm.c

index ed4386b..b875082 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fw_cfg.c,v 1.6 2022/12/26 23:50:20 dv Exp $   */
+/*     $OpenBSD: fw_cfg.c,v 1.7 2023/02/06 20:33:34 dv Exp $   */
 /*
  * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org>
  *
 #include <sys/uio.h>
 #include <machine/biosvar.h>   /* bios_memmap_t */
 #include <machine/vmmvar.h>
+#include <dev/pv/virtioreg.h>
 
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "atomicio.h"
+#include "pci.h"
 #include "vmd.h"
 #include "vmm.h"
 #include "fw_cfg.h"
@@ -72,9 +74,11 @@ static void  fw_cfg_file_dir(void);
 void
 fw_cfg_init(struct vmop_create_params *vmc)
 {
-       const char *bootorder = NULL;
        unsigned int sd = 0;
        size_t i, e820_len = 0;
+       char bootorder[64];
+       const char *bootfmt;
+       int bootidx = -1;
 
        /* Define e820 memory ranges. */
        memset(&e820, 0, sizeof(e820));
@@ -96,18 +100,24 @@ fw_cfg_init(struct vmop_create_params *vmc)
 
        switch (vmc->vmc_bootdevice) {
        case VMBOOTDEV_DISK:
-               bootorder = "/pci@i0cf8/*@3\nHALT";
+               bootidx = pci_find_first_device(PCI_PRODUCT_VIRTIO_BLOCK);
+               bootfmt = "/pci@i0cf8/*@%d\nHALT";
                break;
        case VMBOOTDEV_CDROM:
-               bootorder = "/pci@i0cf8/*@4/*@0/*@0,40000100\nHALT";
+               bootidx = pci_find_first_device(PCI_PRODUCT_VIRTIO_SCSI);
+               bootfmt = "/pci@i0cf8/*@%d/*@0/*@0,40000100\nHALT";
                break;
        case VMBOOTDEV_NET:
                /* XXX not yet */
-               bootorder = "HALT";
+               bootidx = pci_find_first_device(PCI_PRODUCT_VIRTIO_NETWORK);
+               bootfmt = "HALT";
                break;
        }
-       if (bootorder)
+       if (bootidx > -1) {
+               snprintf(bootorder, sizeof(bootorder), bootfmt, bootidx);
+               log_debug("%s: bootorder: %s", __func__, bootorder);
                fw_cfg_add_file("bootorder", bootorder, strlen(bootorder) + 1);
+       }
 }
 
 int
index c1cd815..5309449 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pci.c,v 1.30 2023/01/28 14:40:53 dv Exp $     */
+/*     $OpenBSD: pci.c,v 1.31 2023/02/06 20:33:34 dv Exp $     */
 
 /*
  * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -437,3 +437,21 @@ pci_restore(int fd)
        }
        return (0);
 }
+
+/*
+ * Find the first PCI device based on PCI Subsystem ID
+ * (e.g. PCI_PRODUCT_VIRTIO_BLOCK).
+ *
+ * Returns the PCI device id of the first matching device, if found.
+ * Otherwise, returns -1.
+ */
+int
+pci_find_first_device(uint16_t subsys_id)
+{
+       int i;
+
+       for (i = 0; i < pci.pci_dev_ct; i++)
+               if (pci.pci_devices[i].pd_subsys_id == subsys_id)
+                       return (i);
+       return (-1);
+}
index ed6ba53..73b5443 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pci.h,v 1.9 2021/06/16 16:55:02 dv Exp $      */
+/*     $OpenBSD: pci.h,v 1.10 2023/02/06 20:33:34 dv Exp $     */
 
 /*
  * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -92,6 +92,7 @@ struct pci {
        struct pci_dev pci_devices[PCI_CONFIG_MAX_DEV];
 };
 
+int pci_find_first_device(uint16_t);
 void pci_handle_address_reg(struct vm_run_params *);
 void pci_handle_data_reg(struct vm_run_params *);
 uint8_t pci_handle_io(struct vm_run_params *);
index bf8b0b9..5b9a183 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vm.c,v 1.82 2023/01/28 14:40:53 dv Exp $      */
+/*     $OpenBSD: vm.c,v 1.83 2023/02/06 20:33:34 dv Exp $      */
 
 /*
  * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -1106,13 +1106,6 @@ init_emulated_hw(struct vmop_create_params *vmc, int child_cdrom,
        for (i = COM1_DATA; i <= COM1_SCR; i++)
                ioports_map[i] = vcpu_exit_com;
 
-       /* Init QEMU fw_cfg interface */
-       fw_cfg_init(vmc);
-       ioports_map[FW_CFG_IO_SELECT] = vcpu_exit_fw_cfg;
-       ioports_map[FW_CFG_IO_DATA] = vcpu_exit_fw_cfg;
-       ioports_map[FW_CFG_IO_DMA_ADDR_HIGH] = vcpu_exit_fw_cfg_dma;
-       ioports_map[FW_CFG_IO_DMA_ADDR_LOW] = vcpu_exit_fw_cfg_dma;
-
        /* Initialize PCI */
        for (i = VM_PCI_IO_BAR_BASE; i <= VM_PCI_IO_BAR_END; i++)
                ioports_map[i] = vcpu_exit_pci;
@@ -1126,7 +1119,18 @@ init_emulated_hw(struct vmop_create_params *vmc, int child_cdrom,
 
        /* Initialize virtio devices */
        virtio_init(current_vm, child_cdrom, child_disks, child_taps);
+
+       /*
+        * Init QEMU fw_cfg interface. Must be done last for pci hardware
+        * detection.
+        */
+       fw_cfg_init(vmc);
+       ioports_map[FW_CFG_IO_SELECT] = vcpu_exit_fw_cfg;
+       ioports_map[FW_CFG_IO_DATA] = vcpu_exit_fw_cfg;
+       ioports_map[FW_CFG_IO_DMA_ADDR_HIGH] = vcpu_exit_fw_cfg_dma;
+       ioports_map[FW_CFG_IO_DMA_ADDR_LOW] = vcpu_exit_fw_cfg_dma;
 }
+
 /*
  * restore_emulated_hw
  *