#include "../ats.h"
/* dom_io is used as a sentinel for quarantined devices */
-#define QUARANTINE_SKIP(d) ((d) == dom_io && !dom_iommu(d)->arch.vtd.pgd_maddr)
+#define QUARANTINE_SKIP(d, pgd_maddr) ((d) == dom_io && !(pgd_maddr))
/* Possible unfiltered LAPIC/MSI messages from untrusted sources? */
bool __read_mostly untrusted_msi;
return pte_maddr;
}
-static uint64_t domain_pgd_maddr(struct domain *d, unsigned int nr_pt_levels)
+static paddr_t domain_pgd_maddr(struct domain *d, paddr_t pgd_maddr,
+ unsigned int nr_pt_levels)
{
struct domain_iommu *hd = dom_iommu(d);
- uint64_t pgd_maddr;
unsigned int agaw;
ASSERT(spin_is_locked(&hd->arch.mapping_lock));
- if ( iommu_use_hap_pt(d) )
+ if ( pgd_maddr )
+ /* nothing */;
+ else if ( iommu_use_hap_pt(d) )
{
pagetable_t pgt = p2m_get_pagetable(p2m_get_hostp2m(d));
struct domain *domain,
struct vtd_iommu *iommu,
uint8_t bus, uint8_t devfn, const struct pci_dev *pdev,
- unsigned int mode)
+ domid_t domid, paddr_t pgd_maddr, unsigned int mode)
{
struct domain_iommu *hd = dom_iommu(domain);
struct context_entry *context, *context_entries, lctxt;
__uint128_t old;
- u64 maddr, pgd_maddr;
+ uint64_t maddr;
uint16_t seg = iommu->drhd->segment, prev_did = 0;
struct domain *prev_dom = NULL;
int rc, ret;
bool_t flush_dev_iotlb;
- if ( QUARANTINE_SKIP(domain) )
+ if ( QUARANTINE_SKIP(domain, pgd_maddr) )
return 0;
ASSERT(pcidevs_locked());
}
else
{
+ paddr_t root;
+
spin_lock(&hd->arch.mapping_lock);
- pgd_maddr = domain_pgd_maddr(domain, iommu->nr_pt_levels);
- if ( !pgd_maddr )
+ root = domain_pgd_maddr(domain, pgd_maddr, iommu->nr_pt_levels);
+ if ( !root )
{
spin_unlock(&hd->arch.mapping_lock);
spin_unlock(&iommu->lock);
return -ENOMEM;
}
- context_set_address_root(lctxt, pgd_maddr);
+ context_set_address_root(lctxt, root);
if ( ats_enabled && ecap_dev_iotlb(iommu->ecap) )
context_set_translation_type(lctxt, CONTEXT_TT_DEV_IOTLB);
else
unmap_vtd_domain_page(context_entries);
if ( !seg && !rc )
- rc = me_wifi_quirk(domain, bus, devfn, mode);
+ rc = me_wifi_quirk(domain, bus, devfn, domid, pgd_maddr, mode);
if ( rc )
{
if ( !prev_dom )
- ret = domain_context_unmap_one(domain, iommu, bus, devfn);
+ ret = domain_context_unmap_one(domain, iommu, bus, devfn,
+ domain->domain_id);
else if ( prev_dom != domain ) /* Avoid infinite recursion. */
+ {
+ hd = dom_iommu(prev_dom);
ret = domain_context_mapping_one(prev_dom, iommu, bus, devfn, pdev,
+ domain->domain_id,
+ hd->arch.vtd.pgd_maddr,
mode & MAP_WITH_RMRR) < 0;
+ }
else
ret = 1;
{
const struct acpi_drhd_unit *drhd = acpi_find_matched_drhd_unit(pdev);
const struct acpi_rmrr_unit *rmrr;
+ paddr_t pgd_maddr = dom_iommu(domain)->arch.vtd.pgd_maddr;
int ret = 0;
unsigned int i, mode = 0;
uint16_t seg = pdev->seg, bdf;
printk(VTDPREFIX "%pd:PCIe: map %pp\n",
domain, &PCI_SBDF3(seg, bus, devfn));
ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn,
- pdev, mode);
+ pdev, domain->domain_id, pgd_maddr,
+ mode);
if ( ret > 0 )
ret = 0;
if ( !ret && devfn == pdev->devfn && ats_device(pdev, drhd) > 0 )
domain, &PCI_SBDF3(seg, bus, devfn));
ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn,
- pdev, mode);
+ pdev, domain->domain_id, pgd_maddr,
+ mode);
if ( ret < 0 )
break;
prev_present = ret;
*/
if ( ret >= 0 )
ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn,
- NULL, mode);
+ NULL, domain->domain_id, pgd_maddr,
+ mode);
/*
* Devices behind PCIe-to-PCI/PCIx bridge may generate different
if ( !ret && pdev_type(seg, bus, devfn) == DEV_TYPE_PCIe2PCI_BRIDGE &&
(secbus != pdev->bus || pdev->devfn != 0) )
ret = domain_context_mapping_one(domain, drhd->iommu, secbus, 0,
- NULL, mode);
+ NULL, domain->domain_id, pgd_maddr,
+ mode);
if ( ret )
{
int domain_context_unmap_one(
struct domain *domain,
struct vtd_iommu *iommu,
- u8 bus, u8 devfn)
+ uint8_t bus, uint8_t devfn, domid_t domid)
{
struct context_entry *context, *context_entries;
u64 maddr;
int iommu_domid, rc, ret;
bool_t flush_dev_iotlb;
- if ( QUARANTINE_SKIP(domain) )
+ if ( QUARANTINE_SKIP(domain, dom_iommu(domain)->arch.vtd.pgd_maddr) )
return 0;
ASSERT(pcidevs_locked());
unmap_vtd_domain_page(context_entries);
if ( !iommu->drhd->segment && !rc )
- rc = me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC);
+ rc = me_wifi_quirk(domain, bus, devfn, domid, 0, UNMAP_ME_PHANTOM_FUNC);
if ( rc && !is_hardware_domain(domain) && domain != dom_io )
{
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);
+ ret = domain_context_unmap_one(domain, iommu, bus, devfn,
+ domain->domain_id);
if ( !ret && devfn == pdev->devfn && ats_device(pdev, drhd) > 0 )
disable_ats_device(pdev);
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);
+ ret = domain_context_unmap_one(domain, iommu, bus, devfn,
+ domain->domain_id);
if ( ret )
break;
/* PCIe to PCI/PCIx bridge */
if ( pdev_type(seg, tmp_bus, tmp_devfn) == DEV_TYPE_PCIe2PCI_BRIDGE )
{
- ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn);
+ ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn,
+ domain->domain_id);
if ( !ret )
- ret = domain_context_unmap_one(domain, iommu, secbus, 0);
+ ret = domain_context_unmap_one(domain, iommu, secbus, 0,
+ domain->domain_id);
}
else /* Legacy PCI bridge */
- ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn);
+ ret = domain_context_unmap_one(domain, iommu, tmp_bus, tmp_devfn,
+ domain->domain_id);
break;
return -EINVAL;
}
- if ( !ret && !QUARANTINE_SKIP(domain) && pdev->devfn == devfn )
+ if ( !ret && pdev->devfn == devfn &&
+ !QUARANTINE_SKIP(domain, dom_iommu(domain)->arch.vtd.pgd_maddr) )
check_cleanup_domid_map(domain, pdev, iommu);
return ret;
{
int ret;
- if ( !QUARANTINE_SKIP(target) )
+ if ( !QUARANTINE_SKIP(target, dom_iommu(target)->arch.vtd.pgd_maddr) )
{
if ( !has_arch_pdevs(target) )
vmx_pi_hooks_assign(target);
ret = domain_context_mapping(target, devfn, pdev);
- if ( !ret && !QUARANTINE_SKIP(source) && pdev->devfn == devfn )
+ if ( !ret && pdev->devfn == devfn &&
+ !QUARANTINE_SKIP(source, dom_iommu(source)->arch.vtd.pgd_maddr) )
{
const struct acpi_drhd_unit *drhd = acpi_find_matched_drhd_unit(pdev);