diff --git a/hypervisor/dm/vpci/vhostbridge.c b/hypervisor/dm/vpci/vhostbridge.c index 9b30abff8..9ead392f0 100644 --- a/hypervisor/dm/vpci/vhostbridge.c +++ b/hypervisor/dm/vpci/vhostbridge.c @@ -37,14 +37,57 @@ #include #include #include "vpci_priv.h" - +#include /** * @pre vdev != NULL * @pre vdev->vpci != NULL */ +/* The chart below shows the hostbridge DID high-byte of the platform later than broadwell, whose PCIEXBAR are always + located in the PCI hostbridge config space at the offset 0x60. This chart may need further extension in the future + -------------------------------------------------------------------------------------- + platform | hostbridge DID high-byte + -------------------------------------------------------------------------------------- + SKL(6-gen) | 0x19 + APL(6-gen Atom) | 0x5a + KBL(7/8-gen) | 0x59 + CFL/CFL-R(8/9-gen) | 0x3e + ICL(10-gen) | 0x9b + EHL/TGL(11-gen) | 0x9a + -------------------------------------------------------------------------------------- +*/ +static const uint32_t hostbridge_did_highbytes[] = {0x19U, 0x5aU, 0x59U, 0x3eU, 0x9aU, 0x9bU}; + +/* + The vhostbridge we currently emulated is "Celeron N3350/Pentium N4200/Atom E3900 Series Host Bridge", + which belongs to Intel Appollo Lake processors family, and the device id is 5af0 + + TODO: + 1. In the future, we may add one or more virtual hostbridges for CPUs that are incompatible in layout with the current one + 2. Besides PCIEXBAR(0x60), there are also some registers needs to be emulated more precisely rather than be treated as read-only and hard-coded, listed below: + + ---------------------------------------------------------------------------------------------------------------- + reg | offset | length | current status | remark + ---------------------------------------------------------------------------------------------------------------- + STATUS_COMMAND | 0x8 | dword | unemulated | pci status and command + SVID_SID | 0x2C | dword | unemulated | subsys id and subsys vendor id + MCHBAR | 0x48 | qword | hard-coded | BAR of memory controller hub + GGC | 0x50 | dword | hard-coded | graphics & mem controller hub graphics CR + DEVEN | 0x54 | dword | hard-coded | device enable register + PAVPC | 0x58 | dword | hard-coded | protected audio video path control + TOUUD | 0xA8 | qword | hard-coded | top of upper usable DRAM + BDSM | 0xB0 | dword | hard-coded | base of data stolen memory + BGSM | 0xB4 | dword | hard-coded | base of graphics stolen memory + TSEGMB | 0xB8 | dword | hard-coded | top segmentmemory base + TOLUD | 0xBC | dword | hard-coded | top of lower usable dram + SKPD | 0xDC | dword | unemulated | scratchpad + CAPID0_CAPCTRL0 | 0xe0 | dword | hard-coded | capability 0 control + ---------------------------------------------------------------------------------------------------------------- +*/ static void init_vhostbridge(struct pci_vdev *vdev) { + union pci_bdf hostbridge_bdf = {.value = 0x0U}; + uint32_t pciexbar_low = 0x0U, pciexbar_high = 0x0U, phys_did, i; /* PCI config space */ pci_vdev_write_vcfg(vdev, PCIR_VENDOR, 2U, 0x8086U); pci_vdev_write_vcfg(vdev, PCIR_DEVICE, 2U, 0x5af0U); @@ -59,7 +102,6 @@ static void init_vhostbridge(struct pci_vdev *vdev) pci_vdev_write_vcfg(vdev, 0x50U, 4U, 0x000002c1U); pci_vdev_write_vcfg(vdev, 0x54U, 4U, 0x00000033U); pci_vdev_write_vcfg(vdev, 0x58U, 4U, 0x7ff00007U); - pci_vdev_write_vcfg(vdev, 0x60U, 4U, 0xe0000001U); pci_vdev_write_vcfg(vdev, 0xa8U, 4U, 0x80000000U); pci_vdev_write_vcfg(vdev, 0xacU, 4U, 0x00000002U); pci_vdev_write_vcfg(vdev, 0xb0U, 4U, 0x7c000001U); @@ -69,6 +111,25 @@ static void init_vhostbridge(struct pci_vdev *vdev) pci_vdev_write_vcfg(vdev, 0xe0U, 4U, 0x010c0009U); pci_vdev_write_vcfg(vdev, 0xf4U, 4U, 0x011c0f00U); + if (is_prelaunched_vm(container_of(vdev->vpci, struct acrn_vm, vpci))) { + /* For pre-launched VMs, we only need to write an GPA that's reserved in guest ve820, and VIRT_PCI_MMCFG_BASE(0xE0000000) is fine. The trailing 1 is a ECAM enable-bit */ + pciexbar_low = VIRT_PCI_MMCFG_BASE | 0x1U; + } + else { + /*Inject physical ECAM value to SOS vhostbridge since SOS may check PCIe-MMIO Base Address with it */ + phys_did = pci_pdev_read_cfg(hostbridge_bdf, PCIR_DEVICE, 2); + for (i = 0U; i < (sizeof(hostbridge_did_highbytes) / sizeof(uint32_t)); i++){ + if (((phys_did & 0xff00U) >> 8) == hostbridge_did_highbytes[i]) { + /* The offset of PCIEXBAR register is 0x60 on Intel platforms, and no counter-case is encountered yet */ + pciexbar_low = pci_pdev_read_cfg(hostbridge_bdf, 0x60U, 4); + pciexbar_high = pci_pdev_read_cfg(hostbridge_bdf, 0x64U, 4); + break; + } + } + } + + pci_vdev_write_vcfg(vdev, 0x60U, 4, pciexbar_low); + pci_vdev_write_vcfg(vdev, 0x64U, 4, pciexbar_high); vdev->parent_user = NULL; vdev->user = vdev; }