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 @@ -11,5 +11,14 @@ #include "pci_emul.h" +struct passthru_softc; + +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); + uint32_t read_config(const struct pcisel *sel, long reg, int width); void write_config(const struct pcisel *sel, long reg, int width, uint32_t data); +int set_pcir_handler(struct passthru_softc *sc, int reg, int len, + cfgread_handler rhandler, cfgwrite_handler whandler); 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 @@ -93,6 +93,9 @@ int capoff; } psc_msix; struct pcisel psc_sel; + + cfgread_handler psc_pcir_rhandler[PCI_REGMAX + 1]; + cfgwrite_handler psc_pcir_whandler[PCI_REGMAX + 1]; }; static int @@ -643,6 +646,21 @@ return (error); } +int +set_pcir_handler(struct passthru_softc *sc, int reg, int len, + cfgread_handler rhandler, cfgwrite_handler whandler) +{ + if (reg > PCI_REGMAX || reg + len > PCI_REGMAX + 1) + return (-1); + + for (int i = reg; i < reg + len; ++i) { + sc->psc_pcir_rhandler[i] = rhandler; + sc->psc_pcir_whandler[i] = whandler; + } + + return (0); +} + static int passthru_legacy_config(nvlist_t *nvl, const char *opts) { @@ -856,6 +874,14 @@ get_config_value_node(nvl, "rom"))) != 0) goto done; + /* + * Default PCI config register to accessing the config register of the + * physical device. + */ + if ((error = set_pcir_handler(sc, 0, PCI_REGMAX + 1, + passthru_cfgread_default, passthru_cfgwrite_default)) != 0) + goto done; + error = 0; /* success */ done: if (error) { @@ -902,12 +928,9 @@ } static int -passthru_cfgread(struct pci_devinst *pi, int coff, int bytes, uint32_t *rv) +passthru_cfgread_default(struct passthru_softc *sc, + struct pci_devinst *pi __unused, int coff, int bytes, uint32_t *rv) { - struct passthru_softc *sc; - - sc = pi->pi_arg; - /* * PCI BARs and MSI capability is emulated. */ @@ -946,14 +969,25 @@ } static int -passthru_cfgwrite(struct pci_devinst *pi, int coff, int bytes, uint32_t val) +passthru_cfgread(struct pci_devinst *pi, int coff, int bytes, uint32_t *rv) { - int error, msix_table_entries, i; struct passthru_softc *sc; - uint16_t cmd_old; sc = pi->pi_arg; + if (sc->psc_pcir_rhandler[coff] != NULL) + return (sc->psc_pcir_rhandler[coff](sc, pi, coff, bytes, rv)); + + return (passthru_cfgread_default(sc, pi, coff, bytes, rv)); +} + +static int +passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi, + int coff, int bytes, uint32_t val) +{ + int error, msix_table_entries, i; + uint16_t cmd_old; + /* * PCI BARs are emulated */ @@ -1026,6 +1060,19 @@ return (0); } +static int +passthru_cfgwrite(struct pci_devinst *pi, int coff, int bytes, uint32_t val) +{ + struct passthru_softc *sc; + + sc = pi->pi_arg; + + if (sc->psc_pcir_whandler[coff] != NULL) + return (sc->psc_pcir_whandler[coff](sc, pi, coff, bytes, val)); + + return (passthru_cfgwrite_default(sc, pi, coff, bytes, val)); +} + static void passthru_write(struct pci_devinst *pi, int baridx, uint64_t offset, int size, uint64_t value)