The branch main has been updated by corvink:

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

commit df6c805ca12527d87051136ee5cf32f28e32d8cb
Author:     Corvin Köhne <corv...@freebsd.org>
AuthorDate: 2024-01-08 13:55:49 +0000
Commit:     Corvin Köhne <corv...@freebsd.org>
CommitDate: 2025-08-05 14:02:08 +0000

    bhyve: add BAR handler list for passthru devices
    
    We have to emulate some specific register of a BAR for passthru devices. Our
    current use case are Intels integrated graphic devices. They mirror some of
    their PCI config space into the MMIO space. Unfortunately, the Windows 
driver
    reads from MMIO instead of PCI config space. For that reason, we have to 
trap
    and emulate those register. Instead of implementing a quirk for this special
    device, we're implementing a generic approach by using a list of trapped
    register. That's much cleaner and can be reused. E.g. Nvidia GPUs mirror 
their
    PCI config space in MMIO too and we can reuse it to trap the MSI-X table in 
the
    future.
    
    Note that the handling of this new list requires a larger patch. For that
    reason, we split it into multiple commits. This means that the list isn't 
used
    yet. This commit adds the callback on BAR reads and writes. Some subsequent
    commit will add the trap for BAR regions and an interface to easily add
    protected regions.
    
    Reviewed by:            jhb, markj
    MFC after:              1 week
    Sponsored by:           Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D45339
---
 usr.sbin/bhyve/pci_passthru.c | 59 ++++++++++++++++++++++++++++++++++++++++---
 usr.sbin/bhyve/pci_passthru.h |  4 +++
 2 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
index a82078f6e036..0cc5b777b842 100644
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -79,6 +79,14 @@ static int pcifd = -1;
 
 SET_DECLARE(passthru_dev_set, struct passthru_dev);
 
+struct passthru_bar_handler {
+       TAILQ_ENTRY(passthru_bar_handler) chain;
+       uint64_t off;
+       uint64_t size;
+       passthru_read_handler read;
+       passthru_write_handler write;
+};
+
 struct passthru_softc {
        struct pci_devinst *psc_pi;
        /* ROM is handled like a BAR */
@@ -96,6 +104,9 @@ struct passthru_softc {
        struct passthru_mmio_mapping psc_mmio_map[PASSTHRU_MMIO_MAX];
        cfgread_handler psc_pcir_rhandler[PCI_REGMAX + 1];
        cfgwrite_handler psc_pcir_whandler[PCI_REGMAX + 1];
+
+       TAILQ_HEAD(,
+           passthru_bar_handler) psc_bar_handler[PCI_BARMAX_WITH_ROM + 1];
 };
 
 static int
@@ -947,6 +958,9 @@ passthru_init(struct pci_devinst *pi, nvlist_t *nvl)
        pi->pi_arg = sc;
        sc->psc_pi = pi;
 
+       for (uint8_t i = 0; i < PCI_BARMAX_WITH_ROM + 1; ++i)
+               TAILQ_INIT(&sc->psc_bar_handler[i]);
+
        /* initialize config space */
        if ((error = cfginit(pi, bus, slot, func)) != 0)
                goto done;
@@ -1166,6 +1180,7 @@ passthru_write(struct pci_devinst *pi, int baridx, 
uint64_t offset, int size,
     uint64_t value)
 {
        struct passthru_softc *sc;
+       struct passthru_bar_handler *handler;
        struct pci_bar_ioreq pio;
 
        sc = pi->pi_arg;
@@ -1173,9 +1188,27 @@ passthru_write(struct pci_devinst *pi, int baridx, 
uint64_t offset, int size,
        if (baridx == pci_msix_table_bar(pi)) {
                msix_table_write(sc, offset, size, value);
        } else {
-               assert(pi->pi_bar[baridx].type == PCIBAR_IO);
                assert(size == 1 || size == 2 || size == 4);
-               assert(offset <= UINT32_MAX && offset + size <= UINT32_MAX);
+
+               TAILQ_FOREACH(handler, &sc->psc_bar_handler[baridx], chain) {
+                       if (offset >= handler->off + handler->size) {
+                               continue;
+                       } else if (offset < handler->off) {
+                               assert(offset + size < handler->off);
+                               /*
+                                * The list is sorted in ascending order, so all
+                                * remaining handlers will have an even larger
+                                * offset.
+                                */
+                               break;
+                       }
+
+                       assert(offset + size <= handler->off + handler->size);
+
+                       handler->write(pi, baridx,
+                           offset - handler->off, size, value);
+                       return;
+               }
 
                bzero(&pio, sizeof(pio));
                pio.pbi_sel = sc->psc_sel;
@@ -1193,6 +1226,7 @@ static uint64_t
 passthru_read(struct pci_devinst *pi, int baridx, uint64_t offset, int size)
 {
        struct passthru_softc *sc;
+       struct passthru_bar_handler *handler;
        struct pci_bar_ioreq pio;
        uint64_t val;
 
@@ -1201,9 +1235,26 @@ passthru_read(struct pci_devinst *pi, int baridx, 
uint64_t offset, int size)
        if (baridx == pci_msix_table_bar(pi)) {
                val = msix_table_read(sc, offset, size);
        } else {
-               assert(pi->pi_bar[baridx].type == PCIBAR_IO);
                assert(size == 1 || size == 2 || size == 4);
-               assert(offset <= UINT32_MAX && offset + size <= UINT32_MAX);
+
+               TAILQ_FOREACH(handler, &sc->psc_bar_handler[baridx], chain) {
+                       if (offset >= handler->off + handler->size) {
+                               continue;
+                       } else if (offset < handler->off) {
+                               assert(offset + size < handler->off);
+                               /*
+                                * The list is sorted in ascending order, so all
+                                * remaining handlers will have an even larger
+                                * offset.
+                                */
+                               break;
+                       }
+
+                       assert(offset + size <= handler->off + handler->size);
+
+                       return (handler->read(pi, baridx,
+                           offset - handler->off, size));
+               }
 
                bzero(&pio, sizeof(pio));
                pio.pbi_sel = sc->psc_sel;
diff --git a/usr.sbin/bhyve/pci_passthru.h b/usr.sbin/bhyve/pci_passthru.h
index a89ad287cbc5..fc3fdbc1719f 100644
--- a/usr.sbin/bhyve/pci_passthru.h
+++ b/usr.sbin/bhyve/pci_passthru.h
@@ -35,6 +35,10 @@ typedef int (*cfgread_handler)(struct passthru_softc *sc,
     struct pci_devinst *pi, int coff, int bytes, uint32_t *rv);
 typedef int (*cfgwrite_handler)(struct passthru_softc *sc,
     struct pci_devinst *pi, int coff, int bytes, uint32_t val);
+typedef uint64_t (*passthru_read_handler)(struct pci_devinst *pi, int baridx,
+    uint64_t offset, int size);
+typedef void (*passthru_write_handler)(struct pci_devinst *pi, int baridx, 
uint64_t offset,
+    int size, uint64_t val);
 
 uint32_t pci_host_read_config(const struct pcisel *sel, long reg, int width);
 void pci_host_write_config(const struct pcisel *sel, long reg, int width,

Reply via email to