diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1098,3 +1098,8 @@ #define PCIM_OSC_CTL_PCIE_PME 0x04 /* PCIe Native Power Mgt Events */ #define PCIM_OSC_CTL_PCIE_AER 0x08 /* PCIe Advanced Error Reporting */ #define PCIM_OSC_CTL_PCIE_CAP_STRUCT 0x10 /* Various Capability Structures */ + +/* + * PCI Vendors + */ +#define PCI_VENDOR_INTEL 0x8086 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 @@ -139,6 +139,26 @@ This value only works when loaded with UEFI mode for VNC, and used a VNC client that don't support QEMU Extended Key Event Message (e.g. TightVNC). +.It Va lpc.pcir.vendor Ta integer Ta 0x8086 Ta +Vendor id of the LPC bridge as hex number. +On Intel systems the LPC bridge uses the physical vendor id +as default value. +.It Va lpc.pcir.device Ta integer Ta 0x7000 Ta +Device id of the LPC bridge as hex number. +On Intel systems the LPC bridge uses the physical device id +as default value. +.It Va lpc.pcir.revid Ta integer Ta 0 Ta +Revision id of the LPC bridge as hex number. +On Intel systems the LPC bridge uses the physical revision id +as default value. +.It Va lpc.pcir.subvendor Ta integer Ta 0 Ta +Subvendor id of the LPC bridge as hex number. +On Intel systems the LPC bridge uses the physical subvendor id +as default value. +.It Va lpc.pcir.subdevice Ta integer Ta 0 Ta +Subdevice id of the LPC bridge as hex number. +On Intel systems the LPC bridge uses the physical subdevice id +as default value. .It Va rtc.use_localtime Ta bool Ta true Ta The real time clock uses the local time of the host. If this is set to false, the real time clock uses UTC. 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" @@ -459,11 +461,61 @@ if (lpc_init(ctx) != 0) return (-1); + char value[16]; + + /* on Intel systems lpc is always connected to 0:1f.0 */ + const struct pcisel sel = { .pc_dev = 0x1f }; + if ((read_config(&sel, PCIR_VENDOR, 2) == PCI_VENDOR_INTEL) && + (read_config(&sel, PCIR_CLASS, 1) == PCIC_BRIDGE) && + (read_config(&sel, PCIR_SUBCLASS, 1) == PCIS_BRIDGE_ISA)) { + /* + * The VID, DID, REVID, SUBVID and SUBDID of lpc need to be + * aligned with the physical ones. Without these physical + * values, GPU passthrough of Intel integrated graphics devices + * won't work properly. The Intel GOP driver checks these values + * to proof that it runs on the correct platform. + */ + snprintf(value, sizeof(value), "0x%04x", + read_config(&sel, PCIR_VENDOR, 2)); + set_config_value_if_unset("lpc.pcir.vendor", value); + snprintf(value, sizeof(value), "0x%04x", + read_config(&sel, PCIR_DEVICE, 2)); + set_config_value_if_unset("lpc.pcir.device", value); + snprintf(value, sizeof(value), "0x%02x", + read_config(&sel, PCIR_REVID, 1)); + set_config_value_if_unset("lpc.pcir.revid", value); + snprintf(value, sizeof(value), "0x%04x", + read_config(&sel, PCIR_SUBVEND_0, 2)); + set_config_value_if_unset("lpc.pcir.subvendor", value); + snprintf(value, sizeof(value), "0x%04x", + read_config(&sel, PCIR_SUBDEV_0, 2)); + set_config_value_if_unset("lpc.pcir.subdevice", value); + } + + snprintf(value, sizeof(value), "0x%04x", LPC_VENDOR); + set_config_value_if_unset("lpc.pcir.vendor", value); + snprintf(value, sizeof(value), "0x%04x", LPC_DEV); + set_config_value_if_unset("lpc.pcir.device", value); + snprintf(value, sizeof(value), "0x%02x", 0); + set_config_value_if_unset("lpc.pcir.revid", 0); + snprintf(value, sizeof(value), "0x%04x", 0); + set_config_value_if_unset("lpc.pcir.subvendor", 0); + snprintf(value, sizeof(value), "0x%04x", 0); + set_config_value_if_unset("lpc.pcir.subdevice", 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, + strtol(get_config_value("lpc.pcir.vendor"), NULL, 16)); + pci_set_cfgdata16(pi, PCIR_DEVICE, + strtol(get_config_value("lpc.pcir.device"), NULL, 16)); pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); + pci_set_cfgdata8(pi, PCIR_REVID, + strtol(get_config_value("lpc.pcir.revid"), NULL, 16)); + pci_set_cfgdata16(pi, PCIR_SUBVEND_0, + strtol(get_config_value("lpc.pcir.subvendor"), NULL, 16)); + pci_set_cfgdata16(pi, PCIR_SUBDEV_0, + strtol(get_config_value("lpc.pcir.subdevice"), NULL, 16)); lpc_bridge = pi;