git: 480bef9481f0 - main - bhyve: add bootindex option for several devices

From: Corvin Köhne <corvink_at_FreeBSD.org>
Date: Tue, 20 Jun 2023 08:52:17 UTC
The branch main has been updated by corvink:

URL: https://cgit.FreeBSD.org/src/commit/?id=480bef9481f0c44b19ac4b2adb09f6c3191acd41

commit 480bef9481f0c44b19ac4b2adb09f6c3191acd41
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2021-08-16 07:50:15 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2023-06-20 08:51:58 +0000

    bhyve: add bootindex option for several devices
    
    The bootindex option creates an entry in the "bootorder" fwcfg file.
    This file can be picked up by the guest firmware to determine the
    bootorder. Nevertheless, it's not guaranteed that the guest firmware
    uses the bootorder. At the moment, our OVMF ignores the bootorder. This
    will change in the future.
    
    If guest firmware supports the "bootorder" fwcfg file and no device uses
    the bootindex option, the boot order is determined by the firmware
    itself. If one or more devices specify a bootindex, the first bootable
    device with the lowest bootindex will be booted. It's not garanteed that
    devices without a bootindex will be recognized as bootable from the
    firmware in that case.
    
    Reviewed by:            jhb
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D39285
---
 usr.sbin/bhyve/bhyve.8            | 18 ++++++++++++++++++
 usr.sbin/bhyve/block_if.c         | 21 ++++++++++++++++++++-
 usr.sbin/bhyve/block_if.h         |  2 ++
 usr.sbin/bhyve/pci_ahci.c         |  7 +++++++
 usr.sbin/bhyve/pci_nvme.c         |  8 ++++++++
 usr.sbin/bhyve/pci_virtio_block.c |  5 +++++
 usr.sbin/bhyve/pci_virtio_scsi.c  |  9 +++++++++
 7 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 479ab75be60f..4f6d771cb93d 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -494,6 +494,12 @@ if not explicitly specified.
 Disable emulation of guest trim requests via
 .Dv DIOCGDELETE
 requests.
+.It Li bootindex= Ns Ar index
+Add the device to the bootorder at
+.Ar index .
+A fwcfg file is used to specify the bootorder.
+The guest firmware may ignore or doesn't support this fwcfg file.
+In that case, this feature doesn't work as expected.
 .El
 .Pp
 SCSI device backends:
@@ -511,6 +517,12 @@ are:
 .It Cm iid= Ns Ar IID
 Initiator ID to use when sending requests to specified CTL port.
 The default value is 0.
+.It Li bootindex= Ns Ar index
+Add the device to the bootorder at
+.Ar index .
+A fwcfg file is used to specify the bootorder.
+The guest firmware may ignore or doesn't support this fwcfg file.
+In that case, this feature doesn't work as expected.
 .El
 .Pp
 9P device backends:
@@ -608,6 +620,12 @@ Add
 .Ar romfile
 as option ROM to the PCI device.
 The ROM will be loaded by firmware and should be capable of initializing the device.
+.It Li bootindex= Ns Ar index
+Add the device to the bootorder at
+.Ar index .
+A fwcfg file is used to specify the bootorder.
+The guest firmware may ignore or doesn't support this fwcfg file.
+In that case, this feature doesn't work as expected.
 .El
 .Pp
 Guest memory must be wired using the
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c
index 42c1b5c27293..62f8a9f21661 100644
--- a/usr.sbin/bhyve/block_if.c
+++ b/usr.sbin/bhyve/block_if.c
@@ -122,6 +122,7 @@ struct blockif_ctxt {
 	TAILQ_HEAD(, blockif_elem) bc_pendq;
 	TAILQ_HEAD(, blockif_elem) bc_busyq;
 	struct blockif_elem	bc_reqs[BLOCKIF_MAXREQ];
+	int			bc_bootindex;
 };
 
 static pthread_once_t blockif_once = PTHREAD_ONCE_INIT;
@@ -466,12 +467,22 @@ blockif_legacy_config(nvlist_t *nvl, const char *opts)
 	return (pci_parse_legacy_config(nvl, cp + 1));
 }
 
+int
+blockif_add_boot_device(struct pci_devinst *const pi,
+    struct blockif_ctxt *const bc)
+{
+	if (bc->bc_bootindex < 0)
+		return (0);
+
+	return (pci_emul_add_boot_device(pi, bc->bc_bootindex));
+}
+
 struct blockif_ctxt *
 blockif_open(nvlist_t *nvl, const char *ident)
 {
 	char tname[MAXCOMLEN + 1];
 	char name[MAXPATHLEN];
-	const char *path, *pssval, *ssval;
+	const char *path, *pssval, *ssval, *bootindex_val;
 	char *cp;
 	struct blockif_ctxt *bc;
 	struct stat sbuf;
@@ -480,6 +491,7 @@ blockif_open(nvlist_t *nvl, const char *ident)
 	int extra, fd, i, sectsz;
 	int ro, candelete, geom, ssopt, pssopt;
 	int nodelete;
+	int bootindex;
 
 #ifndef WITHOUT_CAPSICUM
 	cap_rights_t rights;
@@ -493,6 +505,7 @@ blockif_open(nvlist_t *nvl, const char *ident)
 	ssopt = 0;
 	ro = 0;
 	nodelete = 0;
+	bootindex = -1;
 
 	if (get_config_bool_node_default(nvl, "nocache", false))
 		extra |= O_DIRECT;
@@ -525,6 +538,11 @@ blockif_open(nvlist_t *nvl, const char *ident)
 		}
 	}
 
+	bootindex_val = get_config_value_node(nvl, "bootindex");
+	if (bootindex_val != NULL) {
+		bootindex = atoi(bootindex_val);
+	}
+
 	path = get_config_value_node(nvl, "path");
 	if (path == NULL) {
 		EPRINTLN("Missing \"path\" for block device.");
@@ -644,6 +662,7 @@ blockif_open(nvlist_t *nvl, const char *ident)
 	TAILQ_INIT(&bc->bc_freeq);
 	TAILQ_INIT(&bc->bc_pendq);
 	TAILQ_INIT(&bc->bc_busyq);
+	bc->bc_bootindex = bootindex;
 	for (i = 0; i < BLOCKIF_MAXREQ; i++) {
 		bc->bc_reqs[i].be_status = BST_FREE;
 		TAILQ_INSERT_HEAD(&bc->bc_freeq, &bc->bc_reqs[i], be_link);
diff --git a/usr.sbin/bhyve/block_if.h b/usr.sbin/bhyve/block_if.h
index b36d0c367890..52ebd8634b8e 100644
--- a/usr.sbin/bhyve/block_if.h
+++ b/usr.sbin/bhyve/block_if.h
@@ -62,11 +62,13 @@ struct blockif_req {
 	struct iovec	br_iov[BLOCKIF_IOV_MAX];
 };
 
+struct pci_devinst;
 struct blockif_ctxt;
 
 typedef void blockif_resize_cb(struct blockif_ctxt *, void *, size_t);
 
 int	blockif_legacy_config(nvlist_t *nvl, const char *opts);
+int 	blockif_add_boot_device(struct pci_devinst *const pi, struct blockif_ctxt *const bc);
 struct blockif_ctxt *blockif_open(nvlist_t *nvl, const char *ident);
 int	blockif_register_resize_callback(struct blockif_ctxt *bc,
     blockif_resize_cb *cb, void *cb_arg);
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index 2c36e1d5cbb9..a2731876bbea 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -2477,6 +2477,13 @@ pci_ahci_init(struct pci_devinst *pi, nvlist_t *nvl)
 			ret = 1;
 			goto open_fail;
 		}
+
+		ret = blockif_add_boot_device(pi, bctxt);
+		if (ret) {
+			sc->ports = p;
+			goto open_fail;
+		}
+
 		sc->port[p].bctx = bctxt;
 		sc->port[p].pr_sc = sc;
 		sc->port[p].port = p;
diff --git a/usr.sbin/bhyve/pci_nvme.c b/usr.sbin/bhyve/pci_nvme.c
index de5865220155..a18413a50367 100644
--- a/usr.sbin/bhyve/pci_nvme.c
+++ b/usr.sbin/bhyve/pci_nvme.c
@@ -3159,6 +3159,14 @@ pci_nvme_parse_config(struct pci_nvme_softc *sc, nvlist_t *nvl)
 			sc->dataset_management = NVME_DATASET_MANAGEMENT_DISABLE;
 	}
 
+	value = get_config_value_node(nvl, "bootindex");
+	if (value != NULL) {
+		if (pci_emul_add_boot_device(sc->nsc_pi, atoi(value))) {
+			EPRINTLN("Invalid bootindex %d", atoi(value));
+			return (-1);
+		}
+	}
+
 	value = get_config_value_node(nvl, "ram");
 	if (value != NULL) {
 		uint64_t sz = strtoull(value, NULL, 10);
diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c
index 9fd6db41dba8..c8ec62a66793 100644
--- a/usr.sbin/bhyve/pci_virtio_block.c
+++ b/usr.sbin/bhyve/pci_virtio_block.c
@@ -471,6 +471,11 @@ pci_vtblk_init(struct pci_devinst *pi, nvlist_t *nvl)
 		return (1);
 	}
 
+	if (blockif_add_boot_device(pi, bctxt)) {
+		perror("Invalid boot device");
+		return (1);
+	}
+
 	size = blockif_size(bctxt);
 	sectsz = blockif_sectsz(bctxt);
 	blockif_psectsz(bctxt, &sts, &sto);
diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c
index 7d5409cff6a1..fa6cb3a48787 100644
--- a/usr.sbin/bhyve/pci_virtio_scsi.c
+++ b/usr.sbin/bhyve/pci_virtio_scsi.c
@@ -709,6 +709,15 @@ pci_vtscsi_init(struct pci_devinst *pi, nvlist_t *nvl)
 	if (value != NULL)
 		sc->vss_iid = strtoul(value, NULL, 10);
 
+	value = get_config_value_node(nvl, "bootindex");
+	if (value != NULL) {
+		if (pci_emul_add_boot_device(pi, atoi(value))) {
+			EPRINTLN("Invalid bootindex %d", atoi(value));
+			free(sc);
+			return (-1);
+		}
+	}
+
 	devname = get_config_value_node(nvl, "dev");
 	if (devname == NULL)
 		devname = "/dev/cam/ctl";