diff --git a/usr.sbin/bhyve/bhyve_config.5 b/usr.sbin/bhyve/bhyve_config.5 --- a/usr.sbin/bhyve/bhyve_config.5 +++ b/usr.sbin/bhyve/bhyve_config.5 @@ -531,6 +531,20 @@ Settings for the COM4 serial port device. .It Va pc-testdev Ta bool Ta false Ta Enable the PC debug/test device. +.It Va pcir.* Ta integer Ta Ta +The pci ids of the lpc bridge can be modified by this setting. +It also accepts the value +.Ar host +to use the pci id of the host system. +This value is required for the Intel GOP driver to work properly. +.Bl -column "subvendor" "Default" +.It Sy Name Ta Sy Default +.It Va vendor Ta 0x8086 +.It Va device Ta 0x7000 +.It Va revid Ta 0 +.It Va subvendor Ta 0 +.It Va subdevice Ta 0 +.El .El .Ss NVMe Controller Settings Each NVMe controller supports a single storage device. diff --git a/usr.sbin/bhyve/pci_lpc.c b/usr.sbin/bhyve/pci_lpc.c --- a/usr.sbin/bhyve/pci_lpc.c +++ b/usr.sbin/bhyve/pci_lpc.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include @@ -51,6 +52,7 @@ #include "pci_emul.h" #include "pci_irq.h" #include "pci_lpc.h" +#include "pci_passthru.h" #include "pctestdev.h" #include "uart_emul.h" @@ -432,10 +434,57 @@ #define LPC_DEV 0x7000 #define LPC_VENDOR 0x8086 +#define LPC_REVID 0x00 +#define LPC_SUBVEND_0 0x0000 +#define LPC_SUBDEV_0 0x0000 + +static int +pci_lpc_get_sel(struct pcisel *sel) +{ + assert(sel != NULL); + + memset(sel, 0, sizeof(*sel)); + + /* + * Search for the host lpc bridge in reverse order because on intel + * systems the lpc bridge is always connected to 0/31/0. + */ + for (uint8_t slot = PCI_SLOTMAX; slot > 0; --slot) { + sel.pc_dev = slot; + if ((read_config(&sel, PCIR_CLASS, 1) == PCIC_BRIDGE) && + (read_config(&sel, PCIR_SUBCLASS, 1) == PCIS_BRIDGE_ISA)) { + return (0); + } + } + + return (-1); +} + +static uint32_t +pci_lpc_read_reg(const struct pcisel sel, const char *const path, + const uint32_t reg, const uint8_t size, const uint32_t def) +{ + const char *config; + + assert(size == 1 || size == 2 || size == 4); + + config = get_config_value(path); + if (config == NULL) { + return def; + } else if (strcmp(config, "host") == 0) { + return read_config(sel, reg, size); + } else { + return strtol(config, NULL, 16); + } +} static int pci_lpc_init(struct pci_devinst *pi, nvlist_t *nvl __unused) { + struct pcisel *sel = { 0 }; + uint16_t device, subdevice, subvendor, vendor; + uint8_t revid; + /* * Do not allow more than one LPC bridge to be configured. */ @@ -457,11 +506,28 @@ if (lpc_init(pi->pi_vmctx) != 0) return (-1); + if (pci_lpc_get_sel(sel) != 0) + return (-1); + + vendor = pci_lpc_read_reg(sel, "lpc.pcir.vendor", PCIR_VENDOR, 2, + LPC_VENDOR); + device = pci_lpc_read_reg(sel, "lpc.pcir.device", PCIR_DEVICE, 2, + LPC_DEV); + revid = pci_lpc_read_reg(sel, "lpc.pcir.revid", PCIR_REVID, 1, + LPC_REVID); + subvendor = pci_lpc_read_reg(sel, "lpc.pcir.subvendor", + PCIR_SUBVEND_0, 2, LPC_SUBVEND_0); + subdevice = pci_lpc_read_reg(sel, "lpc.pcir.subdevice", + PCIR_SUBDEV_0, 2, LPC_SUBDEV_0); + /* initialize config space */ - pci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV); - pci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR); + pci_set_cfgdata16(pi, PCIR_VENDOR, vendor); + pci_set_cfgdata16(pi, PCIR_DEVICE, device); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); + pci_set_cfgdata8(pi, PCIR_REVID, revid); + pci_set_cfgdata16(pi, PCIR_SUBVEND_0, subvendor); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, subdevice); lpc_bridge = pi;