diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h index 9ff38f3ded..39602d1f88 100644 --- a/xen/drivers/passthrough/vtd/extern.h +++ b/xen/drivers/passthrough/vtd/extern.h @@ -85,7 +85,7 @@ int domain_context_mapping_one(struct domain *domain, struct vtd_iommu *iommu, const struct pci_dev *pdev, domid_t domid, paddr_t pgd_maddr, unsigned int mode); int domain_context_unmap_one(struct domain *domain, struct vtd_iommu *iommu, - uint8_t bus, uint8_t devfn, domid_t domid); + uint8_t bus, uint8_t devfn); int cf_check intel_iommu_get_reserved_device_memory( iommu_grdm_t *func, void *ctxt); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 4c9de8fecf..76ff551dfe 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1533,7 +1533,7 @@ int domain_context_mapping_one( check_cleanup_domid_map(domain, pdev, iommu); printk(XENLOG_ERR "%pp: unexpected context entry %016lx_%016lx (expected %016lx_%016lx)\n", - &PCI_SBDF3(pdev->seg, pdev->bus, devfn), + &PCI_SBDF3(seg, bus, devfn), (uint64_t)(res >> 64), (uint64_t)res, (uint64_t)(old >> 64), (uint64_t)old); rc = -EILSEQ; @@ -1601,9 +1601,14 @@ int domain_context_mapping_one( if ( rc ) { - if ( !prev_dom ) - ret = domain_context_unmap_one(domain, iommu, bus, devfn, - DEVICE_DOMID(domain, pdev)); + if ( !prev_dom || + /* + * Unmapping here means DEV_TYPE_PCI devices with RMRRs (if such + * exist) would cause problems if such a region was actually + * accessed. + */ + (prev_dom == dom_io && !pdev) ) + ret = domain_context_unmap_one(domain, iommu, bus, devfn); else if ( prev_dom != domain ) /* Avoid infinite recursion. */ ret = domain_context_mapping_one(prev_dom, iommu, bus, devfn, pdev, DEVICE_DOMID(prev_dom, pdev), @@ -1744,7 +1749,9 @@ static int domain_context_mapping(struct domain *domain, u8 devfn, * Strictly speaking if the device is the only one behind this bridge * and the only one with this (secbus,0,0) tuple, it could be allowed * to be re-assigned regardless of RMRR presence. But let's deal with - * that case only if it is actually found in the wild. + * that case only if it is actually found in the wild. Note that + * dealing with this just here would still not render the operation + * secure. */ else if ( prev_present && (mode & MAP_WITH_RMRR) && domain != pdev->domain ) @@ -1809,7 +1816,7 @@ static int domain_context_mapping(struct domain *domain, u8 devfn, int domain_context_unmap_one( struct domain *domain, struct vtd_iommu *iommu, - uint8_t bus, uint8_t devfn, domid_t domid) + uint8_t bus, uint8_t devfn) { struct context_entry *context, *context_entries; u64 maddr; @@ -1861,7 +1868,8 @@ int domain_context_unmap_one( unmap_vtd_domain_page(context_entries); if ( !iommu->drhd->segment && !rc ) - rc = me_wifi_quirk(domain, bus, devfn, domid, 0, UNMAP_ME_PHANTOM_FUNC); + rc = me_wifi_quirk(domain, bus, devfn, DOMID_INVALID, 0, + UNMAP_ME_PHANTOM_FUNC); if ( rc && !is_hardware_domain(domain) && domain != dom_io ) { @@ -1910,8 +1918,7 @@ static const struct acpi_drhd_unit *domain_context_unmap( if ( iommu_debug ) printk(VTDPREFIX "%pd:PCIe: unmap %pp\n", domain, &PCI_SBDF3(seg, bus, devfn)); - ret = domain_context_unmap_one(domain, iommu, bus, devfn, - DEVICE_DOMID(domain, pdev)); + ret = domain_context_unmap_one(domain, iommu, bus, devfn); if ( !ret && devfn == pdev->devfn && ats_device(pdev, drhd) > 0 ) disable_ats_device(pdev); @@ -1924,8 +1931,7 @@ static const struct acpi_drhd_unit *domain_context_unmap( if ( iommu_debug ) printk(VTDPREFIX "%pd:PCI: unmap %pp\n", domain, &PCI_SBDF3(seg, bus, devfn)); - ret = domain_context_unmap_one(domain, iommu, bus, devfn, - DEVICE_DOMID(domain, pdev)); + ret = domain_context_unmap_one(domain, iommu, bus, devfn); if ( ret ) break; @@ -1948,12 +1954,10 @@ static const struct acpi_drhd_unit *domain_context_unmap( break; } - ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn, - DEVICE_DOMID(domain, pdev)); + ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn); /* PCIe to PCI/PCIx bridge */ if ( !ret && pdev_type(seg, tmp_bus, tmp_devfn) == DEV_TYPE_PCIe2PCI_BRIDGE ) - ret = domain_context_unmap_one(domain, iommu, secbus, 0, - DEVICE_DOMID(domain, pdev)); + ret = domain_context_unmap_one(domain, iommu, secbus, 0); break; diff --git a/xen/drivers/passthrough/vtd/quirks.c b/xen/drivers/passthrough/vtd/quirks.c index f6f74416d0..3ddbb20e48 100644 --- a/xen/drivers/passthrough/vtd/quirks.c +++ b/xen/drivers/passthrough/vtd/quirks.c @@ -427,7 +427,7 @@ static int __must_check map_me_phantom_function(struct domain *domain, domid, pgd_maddr, mode); else rc = domain_context_unmap_one(domain, drhd->iommu, 0, - PCI_DEVFN(dev, 7), domid); + PCI_DEVFN(dev, 7)); return rc; }