Skip to content

Commit

Permalink
hv: vpci: pass through stolen memory and opregion memory for GVT-D
Browse files Browse the repository at this point in the history
In order to add GVT-D support, we need pass through stolen memory and opregion memroy
to the post-launched VM. To implement this, we first reserve the GPA for stolen memory
and opregion memory through post-launched VM e820 table. Then we would build EPT mapping
between the GPA and the stolen memory and opregion memory real HPA. The last, we need to
return the GPA to post-launched VM if it wants to read the stolen memory and opregion
memory address and prevent post-launched VM to write the stolen memory and opregion memory
address register for now.
We do the GPA reserve and GPA to HPA EPT mapping in ACRN-DM and the stolen memory and
opregion memory CFG space register access emulation in ACRN-HV.

Tracked-On: #4371
Signed-off-by: Li Fei1 <fei1.li@intel.com>
  • Loading branch information
lifeix authored and wenlingz committed Mar 11, 2020
1 parent 659e542 commit fa74bf4
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
33 changes: 33 additions & 0 deletions devicemodel/hw/pci/passthrough.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
*/
#define AUDIO_NHLT_HACK 1

#define PCI_BDF_GPU 0x00000010 /* 00:02.0 */

#define GPU_GSM_SIZE 0x4000000
/* set gsm gpa=0xDB000000, which is reserved in e820 table */
#define GPU_GSM_GPA 0xDB000000
Expand All @@ -75,6 +77,9 @@ extern uint64_t audio_nhlt_len;
static int pciaccess_ref_cnt;
static pthread_mutex_t ref_cnt_mtx = PTHREAD_MUTEX_INITIALIZER;

uint32_t gsm_start_hpa = 0;
uint32_t opregion_start_hpa = 0;

struct passthru_dev {
struct pci_vdev *dev;
struct pcibar bar[PCI_BARMAX + 1];
Expand Down Expand Up @@ -412,6 +417,11 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
return -EINVAL;
}

if (is_rtvm && (PCI_BDF(bus, slot, func) == PCI_BDF_GPU)) {
warnx("%s RTVM doesn't support GVT-D.", __func__);
return -EINVAL;
}

while ((opt = strsep(&opts, ",")) != NULL) {
if (!strncmp(opt, "keep_gsi", 8))
keep_gsi = true;
Expand Down Expand Up @@ -491,6 +501,24 @@ passthru_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
if (error < 0)
goto done;

if (ptdev->phys_bdf == PCI_BDF_GPU) {
uint32_t gsm_phys, opregion_phys;
/* get gsm hpa */
gsm_phys = read_config(ptdev->phys_dev, PCIR_BDSM, 4);
gsm_start_hpa = gsm_phys & PCIM_BDSM_GSM_MASK;
/* initialize the EPT mapping for passthrough GPU gsm region */
vm_map_ptdev_mmio(ctx, 0, 2, 0, GPU_GSM_GPA, GPU_GSM_SIZE, gsm_start_hpa);

/* get opregion hpa */
opregion_phys = read_config(ptdev->phys_dev, PCIR_ASLS_CTL, 4);
opregion_start_hpa = opregion_phys & PCIM_ASLS_OPREGION_MASK;
/* initialize the EPT mapping for passthrough GPU opregion */
vm_map_ptdev_mmio(ctx, 0, 2, 0, GPU_OPREGION_GPA, GPU_OPREGION_SIZE, opregion_start_hpa);

pcidev.rsvd2[0] = GPU_GSM_GPA | (gsm_phys & ~PCIM_BDSM_GSM_MASK) ;
pcidev.rsvd2[1] = GPU_OPREGION_GPA | (opregion_phys & ~PCIM_ASLS_OPREGION_MASK);
}

pcidev.virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
pcidev.phys_bdf = ptdev->phys_bdf;
for (idx = 0; idx <= PCI_BARMAX; idx++) {
Expand Down Expand Up @@ -555,6 +583,11 @@ passthru_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
vm_reset_ptdev_intx_info(ctx, virt_bdf, ptdev->phys_bdf, dev->lintr.ioapic_irq, false);
}

if (ptdev->phys_bdf == PCI_BDF_GPU) {
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, GPU_GSM_GPA, GPU_GSM_SIZE, gsm_start_hpa);
vm_unmap_ptdev_mmio(ctx, 0, 2, 0, GPU_OPREGION_GPA, GPU_OPREGION_SIZE, opregion_start_hpa);
}

pcidev.virt_bdf = PCI_BDF(dev->bus, dev->slot, dev->func);
pcidev.phys_bdf = ptdev->phys_bdf;
pciaccess_cleanup();
Expand Down
25 changes: 20 additions & 5 deletions hypervisor/dm/vpci/vpci.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,12 @@ static int32_t write_pt_dev_cfg(struct pci_vdev *vdev, uint32_t offset,
} else if (sriovcap_access(vdev, offset)) {
write_sriov_cap_reg(vdev, offset, bytes, val);
} else {
/* passthru to physical device */
pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val);
/* For GVT-D, prevent stolen memory and opregion memory write */
if (!(is_postlaunched_vm(vdev->vpci->vm) && is_gvtd(vdev->pdev->bdf) &&
((offset == PCIR_BDSM) || (offset == PCIR_ASLS_CTL)))) {
/* passthru to physical device */
pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val);
}
}

return 0;
Expand All @@ -501,8 +505,14 @@ static int32_t read_pt_dev_cfg(const struct pci_vdev *vdev, uint32_t offset,
} else if (sriovcap_access(vdev, offset)) {
read_sriov_cap_reg(vdev, offset, bytes, val);
} else {
/* passthru to physical device */
*val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes);
/* For GVT-D, just return GPA for stolen memory and opregion memory read. */
if (is_postlaunched_vm(vdev->vpci->vm) && is_gvtd(vdev->pdev->bdf) &&
((offset == PCIR_BDSM) || (offset == PCIR_ASLS_CTL))) {
*val = pci_vdev_read_vcfg(vdev, offset, bytes);
} else {
/* passthru to physical device */
*val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes);
}
}

return 0;
Expand Down Expand Up @@ -752,6 +762,12 @@ int32_t vpci_assign_pcidev(struct acrn_vm *tgt_vm, struct acrn_assign_pcidev *pc
pci_vdev_write_vbar(vdev, idx, pcidev->bar[idx]);
}

if (is_gvtd(bdf)) {
/* rsvd2[0U] for stolen memory GPA; rsvd2[1U] for opregion memory GPA */
pci_vdev_write_vcfg(vdev, PCIR_BDSM, 4U, pcidev->rsvd2[0U]);
pci_vdev_write_vcfg(vdev, PCIR_ASLS_CTL, 4U, pcidev->rsvd2[1U]);
}

vdev->bdf.value = pcidev->virt_bdf;
spinlock_release(&tgt_vm->vpci.lock);
vdev_in_sos->new_owner = vdev;
Expand Down Expand Up @@ -800,7 +816,6 @@ int32_t vpci_deassign_pcidev(struct acrn_vm *tgt_vm, struct acrn_assign_pcidev *
deinit_vmsi(vdev);

deinit_vmsix(vdev);

}
spinlock_release(&tgt_vm->vpci.lock);

Expand Down
9 changes: 9 additions & 0 deletions hypervisor/include/hw/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
#define HOST_BRIDGE_BDF 0U
#define PCI_STD_NUM_BARS 6U

/* Graphics definitions */
#define PCIR_BDSM 0x5CU /* BDSM graphics base data of stolen memory register */
#define PCIR_ASLS_CTL 0xFCU /* Opregion start addr register */

union pci_bdf {
uint16_t value;
struct {
Expand Down Expand Up @@ -251,6 +255,11 @@ struct pci_cfg_ops {
void (*pci_write_cfg)(union pci_bdf bdf, uint32_t offset, uint32_t bytes, uint32_t val);
};

static inline bool is_gvtd(union pci_bdf bdf)
{
return (bdf.value == CONFIG_GPU_SBDF);
}

static inline uint32_t pci_bar_offset(uint32_t idx)
{
return PCIR_BARS + (idx << 2U);
Expand Down

0 comments on commit fa74bf4

Please sign in to comment.