diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -227,6 +228,8 @@ int init_pci(struct vmctx *ctx); void pci_callback(void); +uint32_t pci_config_read_reg(const struct pcisel *host_sel, nvlist_t *nvl, + uint32_t reg, uint8_t size, uint32_t def); 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, diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -61,6 +61,7 @@ #include "pci_emul.h" #include "pci_irq.h" #include "pci_lpc.h" +#include "pci_passthru.h" #define CONF1_ADDR_PORT 0x0cf8 #define CONF1_DATA_PORT 0x0cfc @@ -332,6 +333,49 @@ } } +uint32_t +pci_config_read_reg(const struct pcisel *const host_sel, nvlist_t *nvl, + const uint32_t reg, const uint8_t size, const uint32_t def) +{ + const char *config; + const nvlist_t *pci_regs; + + assert(size == 1 || size == 2 || size == 4); + + pci_regs = find_relative_config_node(nvl, "pcireg"); + if (pci_regs == NULL) { + return def; + } + + switch (reg) { + case PCIR_DEVICE: + config = get_config_value_node(pci_regs, "device"); + break; + case PCIR_VENDOR: + config = get_config_value_node(pci_regs, "vendor"); + break; + case PCIR_REVID: + config = get_config_value_node(pci_regs, "revid"); + break; + case PCIR_SUBVEND_0: + config = get_config_value_node(pci_regs, "subvendor"); + break; + case PCIR_SUBDEV_0: + config = get_config_value_node(pci_regs, "subdevice"); + break; + default: + return (-1); + } + + if (config == NULL) { + return def; + } else if (host_sel != NULL && strcmp(config, "host") == 0) { + return read_config(host_sel, reg, size); + } else { + return strtol(config, NULL, 16); + } +} + static int pci_valid_pba_offset(struct pci_devinst *pi, uint64_t offset) {