diff --git a/usr.sbin/bhyve/pci_passthru.h b/usr.sbin/bhyve/pci_passthru.h --- a/usr.sbin/bhyve/pci_passthru.h +++ b/usr.sbin/bhyve/pci_passthru.h @@ -35,6 +35,10 @@ 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, diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c --- a/usr.sbin/bhyve/pci_passthru.c +++ b/usr.sbin/bhyve/pci_passthru.c @@ -79,6 +79,14 @@ 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_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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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;