git: 6f051f0e56fe - main - bhyve: Treat BAR registration failures as non-fatal
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 20 Oct 2026 22:07:00 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=6f051f0e56feba19731adfa6f6bd2a098b5091de
commit 6f051f0e56feba19731adfa6f6bd2a098b5091de
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-10-20 15:41:21 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-10-20 22:04:55 +0000
bhyve: Treat BAR registration failures as non-fatal
Some guest operating systems (at least 9front) will leave device I/O
space decoding enabled while probing BAR sizes. In this case, a
sufficiently large 32-bit BAR can overlap with the HPET MMIO region
fixed at 0xfed00000. This results in an assertion failure in
modify_bar_registration(), even though the collision is transient, i.e.,
the guest will promptly map the BAR elsewhere.
Tolerate such overlaps. Keep track of a BAR's registration state and
make sure that modify_bar_registration() doesn't try to unregister an
I/O space if registration failed.
This fixes a problem where a 32MB framebuffer ends up overlapping with
the HPET MMIO region, causing some guests to crash with an assertion
failure when probing BARs during boot.
PR: 290098
Reviewed by: bnovkov
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D60748
---
usr.sbin/bhyve/pci_emul.c | 46 +++++++++++++++++++++++++++++++---------------
usr.sbin/bhyve/pci_emul.h | 2 ++
2 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 9170e0b6b93c..60128a735de1 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -639,12 +639,16 @@ static void
modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
{
struct pci_devemu *pe;
+ struct pcibar *bar;
int error;
- enum pcibar_type type;
pe = pi->pi_d;
- type = pi->pi_bar[idx].type;
- switch (type) {
+ bar = &pi->pi_bar[idx];
+
+ if (!registration && !bar->registered)
+ return;
+
+ switch (bar->type) {
case PCIBAR_IO:
{
#ifdef __amd64__
@@ -652,30 +656,34 @@ modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
bzero(&iop, sizeof(struct inout_port));
iop.name = pi->pi_name;
- iop.port = pi->pi_bar[idx].addr;
- iop.size = pi->pi_bar[idx].size;
+ iop.port = bar->addr;
+ iop.size = bar->size;
if (registration) {
iop.flags = IOPORT_F_INOUT;
iop.handler = pci_emul_io_handler;
iop.arg = pi;
error = register_inout(&iop);
- } else
+ } else {
error = unregister_inout(&iop);
+ assert(error == 0);
+ }
#else
struct mem_range mr;
bzero(&mr, sizeof(struct mem_range));
mr.name = pi->pi_name;
- mr.base = pi->pi_bar[idx].addr;
- mr.size = pi->pi_bar[idx].size;
+ mr.base = bar->addr;
+ mr.size = bar->size;
if (registration) {
mr.flags = MEM_F_RW;
mr.handler = pci_emul_iomem_handler;
mr.arg1 = pi;
mr.arg2 = idx;
error = register_mem(&mr);
- } else
+ } else {
error = unregister_mem(&mr);
+ assert(error == 0);
+ }
#endif
break;
}
@@ -686,16 +694,18 @@ modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
bzero(&mr, sizeof(struct mem_range));
mr.name = pi->pi_name;
- mr.base = pi->pi_bar[idx].addr;
- mr.size = pi->pi_bar[idx].size;
+ mr.base = bar->addr;
+ mr.size = bar->size;
if (registration) {
mr.flags = MEM_F_RW;
mr.handler = pci_emul_mem_handler;
mr.arg1 = pi;
mr.arg2 = idx;
error = register_mem(&mr);
- } else
+ } else {
error = unregister_mem(&mr);
+ assert(error == 0);
+ }
break;
}
case PCIBAR_ROM:
@@ -705,10 +715,16 @@ modify_bar_registration(struct pci_devinst *pi, int idx, int registration)
error = EINVAL;
break;
}
- assert(error == 0);
- if (pe->pe_baraddr != NULL)
- (*pe->pe_baraddr)(pi, idx, registration, pi->pi_bar[idx].addr);
+ /*
+ * An error may legitimately occur if the guest is probing BARs and
+ * leaves decoding enabled. Keep track of this if it happens so that we
+ * can skip unregistration.
+ */
+ bar->registered = (registration && error == 0);
+
+ if (error == 0 && pe->pe_baraddr != NULL)
+ (*pe->pe_baraddr)(pi, idx, registration, bar->addr);
}
static void
diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h
index 9aeb11496943..b7ddfd73bda1 100644
--- a/usr.sbin/bhyve/pci_emul.h
+++ b/usr.sbin/bhyve/pci_emul.h
@@ -39,6 +39,7 @@
#include <dev/pci/pcireg.h>
#include <assert.h>
+#include <stdbool.h>
#include "pci_irq.h"
@@ -99,6 +100,7 @@ struct pcibar {
uint64_t size;
uint64_t addr;
uint8_t lobits;
+ bool registered; /* io region is registered */
};
#define PI_NAMESZ 40