diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h index 6b0b7af9e2..994d360e90 100644 --- a/xen/drivers/passthrough/vtd/extern.h +++ b/xen/drivers/passthrough/vtd/extern.h @@ -101,6 +101,8 @@ void vtd_ops_postamble_quirk(struct vtd_iommu *iommu); int __must_check me_wifi_quirk(struct domain *domain, u8 bus, u8 devfn, int map); void pci_vtd_quirk(const struct pci_dev *); +void quirk_iommu_caps(struct vtd_iommu *iommu); + bool_t platform_supports_intremap(void); bool_t platform_supports_x2apic(void); diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 68e7f5fb58..25ad649c34 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -1170,6 +1170,8 @@ int __init iommu_alloc(struct acpi_drhd_unit *drhd) if ( !(iommu->cap + 1) || !(iommu->ecap + 1) ) return -ENODEV; + quirk_iommu_caps(iommu); + if ( cap_fault_reg_offset(iommu->cap) + cap_num_fault_regs(iommu->cap) * PRIMARY_FAULT_REG_LEN >= PAGE_SIZE || ecap_iotlb_offset(iommu->ecap) >= PAGE_SIZE ) diff --git a/xen/drivers/passthrough/vtd/quirks.c b/xen/drivers/passthrough/vtd/quirks.c index e7e326fe8c..4dadd9523f 100644 --- a/xen/drivers/passthrough/vtd/quirks.c +++ b/xen/drivers/passthrough/vtd/quirks.c @@ -536,3 +536,28 @@ void pci_vtd_quirk(const struct pci_dev *pdev) break; } } + +void __init quirk_iommu_caps(struct vtd_iommu *iommu) +{ + /* + * IOMMU Quirks: + * + * SandyBridge IOMMUs claim support for 2M and 1G superpages, but don't + * implement superpages internally. + * + * There are issues changing the walk length under in-flight DMA, which + * has manifested as incompatibility between EPT/IOMMU sharing and the + * workaround for CVE-2018-12207 / XSA-304. Hide the superpages + * capabilities in the IOMMU, which will prevent Xen from sharing the EPT + * and IOMMU pagetables. + * + * Detection of SandyBridge unfortunately has to be done by processor + * model because the client parts don't expose their IOMMUs as PCI devices + * we could match with a Device ID. + */ + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + (boot_cpu_data.x86_model == 0x2a || + boot_cpu_data.x86_model == 0x2d) ) + iommu->cap &= ~(0xful << 34); +}