git: 6632a0a4e3ab - main - bhyve: add helper to create a bootorder

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

URL: https://cgit.FreeBSD.org/src/commit/?id=6632a0a4e3ab68b0e31b612e8aeca14de3fc8159

commit 6632a0a4e3ab68b0e31b612e8aeca14de3fc8159
Author:     Corvin Köhne <corvink@FreeBSD.org>
AuthorDate: 2021-08-16 07:47:53 +0000
Commit:     Corvin Köhne <corvink@FreeBSD.org>
CommitDate: 2023-06-20 08:51:54 +0000

    bhyve: add helper to create a bootorder
    
    Qemu's fwcfg allows to define a bootorder. Therefore, the hypervisor has
    to create a fwcfg item named bootorder, which has a newline seperated
    list of boot entries. Qemu's OVMF will pick up the bootorder and applies
    it.
    
    Add the moment, bhyve's OVMF doesn't support a custom bootorder by
    qemu's fwcfg. However, in the future bhyve will gain support for qemu's
    OVMF. Additonally, we can port relevant parts from qemu's to bhyve's
    OVMF implementation.
    
    Reviewed by:            jhb, markj
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D39284
---
 usr.sbin/bhyve/pci_emul.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++
 usr.sbin/bhyve/pci_emul.h |  2 ++
 2 files changed, 78 insertions(+)

diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index cb92ea9edb09..ad6180c79470 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$");
 #include "pci_irq.h"
 #include "pci_lpc.h"
 #include "pci_passthru.h"
+#include "qemu_fwcfg.h"
 
 #define CONF1_ADDR_PORT	   0x0cf8
 #define CONF1_DATA_PORT	   0x0cfc
@@ -121,6 +122,14 @@ struct pci_bar_allocation {
 static TAILQ_HEAD(pci_bar_list, pci_bar_allocation) pci_bars =
     TAILQ_HEAD_INITIALIZER(pci_bars);
 
+struct boot_device {
+	TAILQ_ENTRY(boot_device) boot_device_chain;
+	struct pci_devinst *pdi;
+	int bootindex;
+};
+static TAILQ_HEAD(boot_list, boot_device) boot_devices = TAILQ_HEAD_INITIALIZER(
+    boot_devices);
+
 #define	PCI_EMUL_IOBASE		0x2000
 #define	PCI_EMUL_IOLIMIT	0x10000
 
@@ -955,6 +964,45 @@ pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size,
 	return (0);
 }
 
+int
+pci_emul_add_boot_device(struct pci_devinst *pi, int bootindex)
+{
+	struct boot_device *new_device, *device;
+
+	/* don't permit a negative bootindex */
+	if (bootindex < 0) {
+		errx(4, "Invalid bootindex %d for %s", bootindex, pi->pi_name);
+	}
+
+	/* alloc new boot device */
+	new_device = calloc(1, sizeof(struct boot_device));
+	if (new_device == NULL) {
+		return (ENOMEM);
+	}
+	new_device->pdi = pi;
+	new_device->bootindex = bootindex;
+
+	/* search for boot device with higher boot index */
+	TAILQ_FOREACH(device, &boot_devices, boot_device_chain) {
+		if (device->bootindex == bootindex) {
+			errx(4,
+			    "Could not set bootindex %d for %s. Bootindex already occupied by %s",
+			    bootindex, pi->pi_name, device->pdi->pi_name);
+		} else if (device->bootindex > bootindex) {
+			break;
+		}
+	}
+
+	/* add boot device to queue */
+	if (device == NULL) {
+		TAILQ_INSERT_TAIL(&boot_devices, new_device, boot_device_chain);
+	} else {
+		TAILQ_INSERT_BEFORE(device, new_device, boot_device_chain);
+	}
+
+	return (0);
+}
+
 #define	CAP_START_OFFSET	0x40
 static int
 pci_emul_add_capability(struct pci_devinst *pi, u_char *capdata, int caplen)
@@ -1362,6 +1410,27 @@ pci_ecfg_base(void)
 	return (PCI_EMUL_ECFG_BASE);
 }
 
+static int
+init_bootorder(void)
+{
+	struct boot_device *device;
+	FILE *fp;
+	char *bootorder;
+	size_t bootorder_len;
+
+	if (TAILQ_EMPTY(&boot_devices))
+		return (0);
+
+	fp = open_memstream(&bootorder, &bootorder_len);
+	TAILQ_FOREACH(device, &boot_devices, boot_device_chain) {
+		fprintf(fp, "/pci@i0cf8/pci@%d,%d\n",
+		    device->pdi->pi_slot, device->pdi->pi_func);
+	}
+	fclose(fp);
+
+	return (qemu_fwcfg_add_file("bootorder", bootorder_len, bootorder));
+}
+
 #define	BUSIO_ROUNDUP		32
 #define	BUSMEM32_ROUNDUP	(1024 * 1024)
 #define	BUSMEM64_ROUNDUP	(512 * 1024 * 1024)
@@ -1391,6 +1460,8 @@ init_pci(struct vmctx *ctx)
 	pci_emul_membase64 = roundup2(pci_emul_membase64, PCI_EMUL_MEMSIZE64);
 	pci_emul_memlim64 = pci_emul_membase64 + PCI_EMUL_MEMSIZE64;
 
+	TAILQ_INIT(&boot_devices);
+
 	for (bus = 0; bus < MAXBUSES; bus++) {
 		snprintf(node_name, sizeof(node_name), "pci.%d", bus);
 		nvl = find_config_node(node_name);
@@ -1498,6 +1569,11 @@ init_pci(struct vmctx *ctx)
 	}
 	lpc_pirq_routed();
 
+	if ((error = init_bootorder()) != 0) {
+		warnx("%s: Unable to init bootorder", __func__);
+		return (error);
+	}
+
 	/*
 	 * The guest physical memory map looks like the following:
 	 * [0,		    lowmem)		guest system memory
diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h
index d68920524398..945d32d7bdcd 100644
--- a/usr.sbin/bhyve/pci_emul.h
+++ b/usr.sbin/bhyve/pci_emul.h
@@ -234,6 +234,8 @@ int	pci_emul_alloc_bar(struct pci_devinst *pdi, int idx,
 	    enum pcibar_type type, uint64_t size);
 int 	pci_emul_alloc_rom(struct pci_devinst *const pdi, const uint64_t size,
     	    void **const addr);
+int 	pci_emul_add_boot_device(struct pci_devinst *const pi,
+	    const int bootindex);
 int	pci_emul_add_msicap(struct pci_devinst *pi, int msgnum);
 int	pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type);
 void	pci_emul_capwrite(struct pci_devinst *pi, int offset, int bytes,