Skip to content

Instantly share code, notes, and snippets.

@ktemkin
Created January 10, 2016 21:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ktemkin/0e81b93654ae800a5609 to your computer and use it in GitHub Desktop.
Save ktemkin/0e81b93654ae800a5609 to your computer and use it in GitHub Desktop.
--------------------------------------------------------------------------------
SHORT DESCRIPTION:
--------------------------------------------------------------------------------
Workaround fixing VT-d breakage on Clarkdale integrated graphics.
--------------------------------------------------------------------------------
LONG DESCRIPTION:
--------------------------------------------------------------------------------
Unfortunately, quirks specific to the Clarkdale/Nehalem integrated
graphics device (IGD) do not function correctly with Xen's VT-d
implementation; causing mapping issues which break display and can corrupt
memory throughout dom0.
This workaround disables VT-d address translation for the affected IGD
/when used for display in dom0/, granting 1:1 access to the host's memory. VT-d
for passthrough and other dom0 devices is not affected. With this patch in
place, the affected systems function properly and have working displays.
--------------------------------------------------------------------------------
SECURITY CONCERNS:
--------------------------------------------------------------------------------
While it is true that, in general, disabling VT-d for a device opens several
security risks (e.g. that of a DMA attack), this patch itself is not believed to
present any significant security risk, as the affected device is a trusted
component of the processor, controlled by trusted software (surfman) in a
trusted, priveleged hardware domain (dom0).
It is worth noting that access to the card's DMA controller is gated by SELinux
policy-- and that the only software capable of interfacing with the card
(surfman) already has the permission to map arbitrary physical pages.
--------------------------------------------------------------------------------
DEPENDENCIES
--------------------------------------------------------------------------------
This patch has no intra-patch or external dependencies.
--------------------------------------------------------------------------------
CHANGELOG
--------------------------------------------------------------------------------
Implementation: Kyle J. Temkin <temkink@ainfosec.com> 7/9/2015
--------------------------------------------------------------------------------
REMOVAL
--------------------------------------------------------------------------------
This patch is a work-around for Nehalem/Clarkdale workstations. It
should be removed if:
-Support is dropped for Nehalem/Clarkdale workstations; or
-A fix for the Xen VT-d driver or i915 graphics driver is developed
that does not suffer from these quirks.
--------------------------------------------------------------------------------
UPSTREAM PLAN
--------------------------------------------------------------------------------
This is a work-around for OpenXT; it should not be upstreamed.
---
xen/drivers/passthrough/vtd/extern.h | 1 +
xen/drivers/passthrough/vtd/iommu.c | 31 +++++++++++++++++++++++++++++++
xen/drivers/passthrough/vtd/quirks.c | 23 +++++++++++++++++++++++
3 files changed, 55 insertions(+)
diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h
index afe7faf..c9cd464 100644
--- a/xen/drivers/passthrough/vtd/extern.h
+++ b/xen/drivers/passthrough/vtd/extern.h
@@ -95,6 +95,7 @@ int msi_msg_write_remap_rte(struct msi_desc *, struct msi_msg *);
int intel_setup_hpet_msi(struct msi_desc *);
int is_igd_vt_enabled_quirk(void);
+int is_oxt_nehalem_igd_quirk(void);
void platform_quirks_init(void);
void vtd_ops_preamble_quirk(struct iommu* iommu);
void vtd_ops_postamble_quirk(struct iommu* iommu);
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 142d79e..9cfa848 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -711,6 +711,27 @@ static int iommu_set_root_entry(struct iommu *iommu)
return 0;
}
+static int is_hardware_domain_mapping(struct iommu * iommu)
+{
+ unsigned long nr_dom, i;
+
+ //Determine the total number of domids that can be associated with the
+ nr_dom = cap_ndoms(iommu->cap);
+
+ //Iterate over each of the _valid_ domids associated with the MMU.
+ for( i = find_first_bit(iommu->domid_bitmap, nr_dom); i < nr_dom;
+ i = find_next_bit(iommu->domid_bitmap, nr_dom, i+1))
+ {
+ //If we have a mapping to something other than dom0, this isn't
+ //a trusted mapping-- we shouldn't apply certain quirks.
+ if ( iommu->domid_map[i] != 0 )
+ return 0;
+ }
+
+ //Otherwise, this must be a safe mapping to tweak.
+ return 1;
+}
+
static void iommu_enable_translation(struct acpi_drhd_unit *drhd)
{
u32 sts;
@@ -729,6 +750,16 @@ static void iommu_enable_translation(struct acpi_drhd_unit *drhd)
}
}
+ //If this is a Nehalem IGD known to suffer VT-d issues, and we haven't force use of the iommu,
+ //disable VT-d /just for this dom0 device/. This should have no security impact on most systems.
+ if(is_igd_drhd(drhd) && is_oxt_nehalem_igd_quirk() && is_hardware_domain_mapping(iommu) && !force_iommu) {
+ dprintk(XENLOG_WARNING VTDPREFIX, "This integrated graphics device has known issues with VT-d.\n");
+ dprintk(XENLOG_WARNING VTDPREFIX, "Disabling VT-d translation for this dom0 device.\n");
+ disable_pmr(iommu);
+ return;
+ }
+
+
/* apply platform specific errata workarounds */
vtd_ops_preamble_quirk(iommu);
diff --git a/xen/drivers/passthrough/vtd/quirks.c b/xen/drivers/passthrough/vtd/quirks.c
index 2fac35d..76433f7 100644
--- a/xen/drivers/passthrough/vtd/quirks.c
+++ b/xen/drivers/passthrough/vtd/quirks.c
@@ -75,6 +75,29 @@ int is_igd_vt_enabled_quirk(void)
return ( ggc & GGC_MEMORY_VT_ENABLED ? 1 : 0 );
}
+/**
+ * Determine if this devices has a known-problematic Integrated Graphics
+ * Device (IGD). At least one older IGD device doesn't work with our VT-d
+ * implementation.
+ */
+int is_oxt_nehalem_igd_quirk(void)
+{
+ u16 vid, pid;
+
+ //Check the vendor ID of the IGD device.
+ //(Note that device is on bus zero, and this an integrated component of
+ //the CPU for platforms supporting VTD. As a result, this makes it
+ //reasonable to trust its vendor ID.)
+ vid = pci_conf_read16(0, 0, IGD_DEV, 0, 0);
+ if(vid != 0x8086)
+ return 0;
+
+ //And check the product ID of the device.
+ pid = pci_conf_read16(0, 0, IGD_DEV, 0, 2);
+ return (pid == 0x0042);
+}
+
+
/*
* QUIRK to workaround cantiga VT-d buffer flush issue.
* The workaround is to force write buffer flush even if
--
2.4.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment