[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 4/4] x86/iommu: add PVH support to the inclusive options



Several people have reported hardware issues (malfunctioning USB
controllers) due to iommu page faults. Those faults are caused by
missing RMRR (VTd) or IRVS (AMD-Vi) entries in the ACPI tables. Those
can be worked around on VTd hardware by manually adding RMRR entries
on the command line, this is however limited to Intel hardware and
quite cumbersome to do.

In order to solve those issues add PVH support to the inclusive option
that identity maps all regions marked as reserved in the memory map.
Note that regions used by devices emulated by Xen (LAPIC, IO-APIC or
PCIe MCFG regions) are specifically avoided. Note that this option
currently relies on no MSIX MMIO areas residing in a reserved region,
or else Xen won't be able to trap those accesses.

Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
---
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx>
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Tim Deegan <tim@xxxxxxx>
Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
---
 docs/misc/xen-command-line.markdown | 16 ++++--
 xen/drivers/passthrough/x86/iommu.c | 82 +++++++++++++++++++++++------
 2 files changed, 77 insertions(+), 21 deletions(-)

diff --git a/docs/misc/xen-command-line.markdown 
b/docs/misc/xen-command-line.markdown
index 91a8bfc9a6..c7c9a38c19 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1203,11 +1203,17 @@ detection of systems known to misbehave upon accesses 
to that port.
 > Default: `true`
 
 >> Use this to work around firmware issues providing incorrect RMRR or IVMD
->> entries. Rather than only mapping RAM pages for IOMMU accesses for Dom0,
->> with this option all pages up to 4GB, not marked as unusable in the E820
->> table, will get a mapping established. Note that this option is only
->> applicable to a PV dom0. Also note that if `dom0-strict` mode is enabled
->> then conventional RAM pages not assigned to dom0 will not be mapped.
+>> entries. The behaviour of this option is slightly different between a PV and
+>> a PVH Dom0:
+>>
+>> * For a PV Dom0 all pages up to 4GB not marked as unusable in the memory
+>>   map will get a mapping established. Note that if `dom0-strict` mode is
+>>   enabled then conventional RAM pages not assigned to dom0 will not be
+>>   mapped.
+>>
+>> * For a PVH Dom0 all memory regions marked as reserved in the memory map
+>>   that don't overlap with any MMIO region from emulated devices will be
+>>   identity mapped.
 
 ### iommu\_dev\_iotlb\_timeout
 > `= <integer>`
diff --git a/xen/drivers/passthrough/x86/iommu.c 
b/xen/drivers/passthrough/x86/iommu.c
index 24cc591aa5..cfafe1b572 100644
--- a/xen/drivers/passthrough/x86/iommu.c
+++ b/xen/drivers/passthrough/x86/iommu.c
@@ -20,6 +20,8 @@
 #include <xen/softirq.h>
 #include <xsm/xsm.h>
 
+#include <asm/apicdef.h>
+#include <asm/io_apic.h>
 #include <asm/setup.h>
 
 void iommu_update_ire_from_apic(
@@ -134,11 +136,62 @@ void arch_iommu_domain_destroy(struct domain *d)
 {
 }
 
+static bool __hwdom_init pv_inclusive_map(unsigned long pfn,
+                                          unsigned long max_pfn)
+{
+    /*
+     * If dom0-strict mode is enabled then exclude conventional RAM
+     * and let the common code map dom0's pages.
+     */
+    if ( iommu_dom0_strict && page_is_ram_type(pfn, RAM_TYPE_CONVENTIONAL) )
+        return false;
+    if ( iommu_inclusive && pfn <= max_pfn )
+        return !page_is_ram_type(pfn, RAM_TYPE_UNUSABLE);
+
+    return page_is_ram_type(pfn, RAM_TYPE_CONVENTIONAL);
+}
+
+static bool __hwdom_init pvh_inclusive_map(const struct domain *d,
+                                           unsigned long pfn)
+{
+    unsigned int i;
+
+    /*
+     * Ignore any address below 1MB, that's already identity mapped by the
+     * domain builder.
+     */
+    if ( pfn < PFN_DOWN(MB(1)) )
+        return false;
+
+    /* Only add reserved regions. */
+    if ( !page_is_ram_type(pfn, RAM_TYPE_RESERVED) )
+        return false;
+
+    /* Check that it doesn't overlap with the LAPIC */
+    if ( pfn == PFN_DOWN(APIC_DEFAULT_PHYS_BASE) )
+        return false;
+    /* ... or the IO-APIC */
+    for ( i = 0; i < nr_ioapics; i++ )
+        if ( pfn == PFN_DOWN(domain_vioapic(d, i)->base_address) )
+            return false;
+    /* ... or the PCIe MCFG regions. */
+    for ( i = 0; i < pci_mmcfg_config_num; i++ )
+    {
+        unsigned long addr = PFN_DOWN(pci_mmcfg_config[i].address);
+
+        if ( pfn >= addr + (pci_mmcfg_config[i].start_bus_number << 8) &&
+             pfn < addr + (pci_mmcfg_config[i].end_bus_number << 8) )
+            return false;
+    }
+
+    return true;
+}
+
 void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
 {
     unsigned long i, j, tmp, top, max_pfn;
 
-    if ( iommu_passthrough || !is_pv_domain(d) )
+    if ( iommu_passthrough )
         return;
 
     BUG_ON(!is_hardware_domain(d));
@@ -149,7 +202,6 @@ void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
     for ( i = 0; i < top; i++ )
     {
         unsigned long pfn = pdx_to_pfn(i);
-        bool map;
         int rc = 0;
 
         /*
@@ -163,25 +215,23 @@ void __hwdom_init arch_iommu_hwdom_init(struct domain *d)
              xen_in_range(pfn) )
             continue;
 
-        /*
-         * If dom0-strict mode is enabled then exclude conventional RAM
-         * and let the common code map dom0's pages.
-         */
-        if ( iommu_dom0_strict &&
-             page_is_ram_type(pfn, RAM_TYPE_CONVENTIONAL) )
-            map = false;
-        else if ( iommu_inclusive && pfn <= max_pfn )
-            map = !page_is_ram_type(pfn, RAM_TYPE_UNUSABLE);
-        else
-            map = page_is_ram_type(pfn, RAM_TYPE_CONVENTIONAL);
-
-        if ( !map )
+        if ( is_pv_domain(d) ? !pv_inclusive_map(pfn, max_pfn)
+                             : !pvh_inclusive_map(d, pfn) )
             continue;
 
         tmp = 1 << (PAGE_SHIFT - PAGE_SHIFT_4K);
         for ( j = 0; j < tmp; j++ )
         {
-            int ret = iommu_map_page(d, pfn * tmp + j, pfn * tmp + j,
+            int ret;
+
+            if ( iommu_use_hap_pt(d) )
+            {
+                ASSERT(is_hvm_domain(d));
+                ret = set_identity_p2m_entry(d, pfn * tmp + j, p2m_access_rw,
+                                             0);
+            }
+            else
+                ret = iommu_map_page(d, pfn * tmp + j, pfn * tmp + j,
                                      IOMMUF_readable|IOMMUF_writable);
 
             if ( !rc )
-- 
2.18.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.