mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
VT-d: prepare for per-device quarantine page tables (part I)
Arrange for domain ID and page table root to be passed around, the latter in particular to domain_pgd_maddr() such that taking it from the per-domain fields can be overridden. No functional change intended. Signed-off-by: Jan Beulich <jbeulich@suse.com> Reviewed-by: Paul Durrant <paul@xen.org> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
This commit is contained in:
1 parent
1fa6e9aa36
commit
eb19326a32
3 files changed
+62
-35
No files matched your search
@@ -82,9 +82,10 @@ void *map_vtd_domain_page(u64 maddr);
|
||||
void unmap_vtd_domain_page(const void *va);
|
||||
int domain_context_mapping_one(struct domain *domain, struct vtd_iommu *iommu,
|
||||
uint8_t bus, uint8_t devfn,
|
||||
const struct pci_dev *pdev, unsigned int mode);
|
||||
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,
|
||||
u8 bus, u8 devfn);
|
||||
uint8_t bus, uint8_t devfn, domid_t domid);
|
||||
int cf_check intel_iommu_get_reserved_device_memory(
|
||||
iommu_grdm_t *func, void *ctxt);
|
||||
|
||||
@@ -105,7 +106,8 @@ void platform_quirks_init(void);
|
||||
void vtd_ops_preamble_quirk(struct vtd_iommu *iommu);
|
||||
void vtd_ops_postamble_quirk(struct vtd_iommu *iommu);
|
||||
int __must_check me_wifi_quirk(struct domain *domain, uint8_t bus,
|
||||
uint8_t devfn, unsigned int mode);
|
||||
uint8_t devfn, domid_t domid, paddr_t pgd_maddr,
|
||||
unsigned int mode);
|
||||
void pci_vtd_quirk(const struct pci_dev *);
|
||||
void quirk_iommu_caps(struct vtd_iommu *iommu);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#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;
|
||||
@@ -346,15 +346,17 @@ static u64 addr_to_dma_page_maddr(struct domain *domain, u64 addr, int alloc)
|
||||
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));
|
||||
|
||||
@@ -1379,18 +1381,18 @@ int domain_context_mapping_one(
|
||||
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());
|
||||
@@ -1427,10 +1429,12 @@ int domain_context_mapping_one(
|
||||
}
|
||||
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);
|
||||
@@ -1440,7 +1444,7 @@ int domain_context_mapping_one(
|
||||
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
|
||||
@@ -1557,15 +1561,21 @@ int domain_context_mapping_one(
|
||||
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;
|
||||
|
||||
@@ -1587,6 +1597,7 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
{
|
||||
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;
|
||||
@@ -1649,7 +1660,8 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
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 )
|
||||
@@ -1666,7 +1678,8 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
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;
|
||||
@@ -1694,7 +1707,8 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
*/
|
||||
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
|
||||
@@ -1709,7 +1723,8 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
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 )
|
||||
{
|
||||
@@ -1737,14 +1752,14 @@ static int domain_context_mapping(struct domain *domain, u8 devfn,
|
||||
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());
|
||||
@@ -1798,7 +1813,7 @@ int domain_context_unmap_one(
|
||||
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 )
|
||||
{
|
||||
@@ -1845,7 +1860,8 @@ static int domain_context_unmap(struct domain *domain, u8 devfn,
|
||||
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);
|
||||
|
||||
@@ -1858,7 +1874,8 @@ static int domain_context_unmap(struct domain *domain, u8 devfn,
|
||||
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;
|
||||
|
||||
@@ -1884,12 +1901,15 @@ static int domain_context_unmap(struct domain *domain, u8 devfn,
|
||||
/* 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;
|
||||
|
||||
@@ -1899,7 +1919,8 @@ static int domain_context_unmap(struct domain *domain, u8 devfn,
|
||||
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;
|
||||
@@ -2501,7 +2522,7 @@ static int cf_check reassign_device_ownership(
|
||||
{
|
||||
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);
|
||||
@@ -2517,7 +2538,8 @@ static int cf_check reassign_device_ownership(
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -408,6 +408,8 @@ void __init platform_quirks_init(void)
|
||||
|
||||
static int __must_check map_me_phantom_function(struct domain *domain,
|
||||
unsigned int dev,
|
||||
domid_t domid,
|
||||
paddr_t pgd_maddr,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct acpi_drhd_unit *drhd;
|
||||
@@ -421,16 +423,17 @@ static int __must_check map_me_phantom_function(struct domain *domain,
|
||||
/* map or unmap ME phantom function */
|
||||
if ( !(mode & UNMAP_ME_PHANTOM_FUNC) )
|
||||
rc = domain_context_mapping_one(domain, drhd->iommu, 0,
|
||||
PCI_DEVFN(dev, 7), NULL, mode);
|
||||
PCI_DEVFN(dev, 7), NULL,
|
||||
domid, pgd_maddr, mode);
|
||||
else
|
||||
rc = domain_context_unmap_one(domain, drhd->iommu, 0,
|
||||
PCI_DEVFN(dev, 7));
|
||||
PCI_DEVFN(dev, 7), domid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int me_wifi_quirk(struct domain *domain, uint8_t bus, uint8_t devfn,
|
||||
unsigned int mode)
|
||||
domid_t domid, paddr_t pgd_maddr, unsigned int mode)
|
||||
{
|
||||
u32 id;
|
||||
int rc = 0;
|
||||
@@ -454,7 +457,7 @@ int me_wifi_quirk(struct domain *domain, uint8_t bus, uint8_t devfn,
|
||||
case 0x423b8086:
|
||||
case 0x423c8086:
|
||||
case 0x423d8086:
|
||||
rc = map_me_phantom_function(domain, 3, mode);
|
||||
rc = map_me_phantom_function(domain, 3, domid, pgd_maddr, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -480,7 +483,7 @@ int me_wifi_quirk(struct domain *domain, uint8_t bus, uint8_t devfn,
|
||||
case 0x42388086: /* Puma Peak */
|
||||
case 0x422b8086:
|
||||
case 0x422c8086:
|
||||
rc = map_me_phantom_function(domain, 22, mode);
|
||||
rc = map_me_phantom_function(domain, 22, domid, pgd_maddr, mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||