From 1e8eabf241e21419e8224b908988556a471c5d03 Mon Sep 17 00:00:00 2001 From: dv Date: Mon, 6 Feb 2023 20:33:34 +0000 Subject: [PATCH] vmd(8): scan pci bus to determine bootorder strings. 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 | 22 ++++++++++++++++------ usr.sbin/vmd/pci.c | 20 +++++++++++++++++++- usr.sbin/vmd/pci.h | 3 ++- usr.sbin/vmd/vm.c | 20 ++++++++++++-------- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/usr.sbin/vmd/fw_cfg.c b/usr.sbin/vmd/fw_cfg.c index ed4386b7c9c..b875082b6fe 100644 --- a/usr.sbin/vmd/fw_cfg.c +++ b/usr.sbin/vmd/fw_cfg.c @@ -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 * @@ -18,12 +18,14 @@ #include #include /* bios_memmap_t */ #include +#include #include #include #include #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 diff --git a/usr.sbin/vmd/pci.c b/usr.sbin/vmd/pci.c index c1cd8154663..5309449b339 100644 --- a/usr.sbin/vmd/pci.c +++ b/usr.sbin/vmd/pci.c @@ -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 @@ -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); +} diff --git a/usr.sbin/vmd/pci.h b/usr.sbin/vmd/pci.h index ed6ba534536..73b54437bed 100644 --- a/usr.sbin/vmd/pci.h +++ b/usr.sbin/vmd/pci.h @@ -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 @@ -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 *); diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index bf8b0b958f5..5b9a1831f5b 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -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 @@ -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 * -- 2.20.1