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

[Xen-devel] [PATCH 2/2] iommu: add rmrr Xen command line option for misc rmrrs



From: Elena Ufimtseva <elena.ufimtseva@xxxxxxxxxx>

On some platforms RMRR regions may be not specified
in ACPI and thus will not be mapped 1:1 in dom0. This
causes IO Page Faults and prevents dom0 from booting
in PVH mode.
New Xen command line option rmrr allows to specify
such devices and memory regions. These regions are added
to the list of RMRR defined in ACPI if the device
is present in system. As a result, additional RMRRs will
be mapped 1:1 in dom0 with correct permissions.

Mentioned above problems were discovered during PVH work with
ThinkCentre M and Dell 5600T. No official documentation
was found so far in regards to what devices and why cause this.
Experiments show that ThinkCentre M USB devices with enabled
debug port generate DMA read transactions to the regions of
memory marked reserved in host e820 map.
For Dell 5600T the device and faulting addresses are not found yet.

For detailed history of the discussion please check following threads:
http://lists.Xen.org/archives/html/xen-devel/2015-02/msg01724.html
http://lists.Xen.org/archives/html/xen-devel/2015-01/msg02513.html

Format for rmrr Xen command line option:
rmrr=[sbdf]start<:end>,[sbdf]start:<end>

Signed-off-by: Elena Ufimtseva <elena.ufimtseva@xxxxxxxxxx>
---
 docs/misc/xen-command-line.markdown |    7 +++
 xen/drivers/passthrough/iommu.c     |   86 +++++++++++++++++++++++++++++++++++
 xen/drivers/passthrough/vtd/iommu.c |   33 ++++++++++++++
 xen/drivers/passthrough/vtd/iommu.h |    1 +
 xen/include/xen/iommu.h             |    9 ++++
 5 files changed, 136 insertions(+)

diff --git a/docs/misc/xen-command-line.markdown 
b/docs/misc/xen-command-line.markdown
index bc316be..2e1210f 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1392,3 +1392,10 @@ mode.
 > Default: `true`
 
 Permit use of the `xsave/xrstor` instructions.
+
+### rmrr
+> '= [sbdf]start<:end>,[sbdf]start<:end>
+
+Define RMRRs units that are missing from ACPI table along with device
+they belong to and use them for 1:1 mapping. End addresses can be omitted
+and one page will be mapped.
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index cc12735..b64916e 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -55,6 +55,9 @@ bool_t __read_mostly iommu_hap_pt_share = 1;
 bool_t __read_mostly iommu_debug;
 bool_t __read_mostly amd_iommu_perdev_intremap = 1;
 
+static char __initdata misc_rmrr[100];
+string_param("rmrr", misc_rmrr);
+
 DEFINE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
 
 DEFINE_SPINLOCK(iommu_pt_cleanup_lock);
@@ -67,6 +70,87 @@ static struct keyhandler iommu_p2m_table = {
     .desc = "dump iommu p2m table"
 };
 
+/*
+ * List of command line defined rmrr units.
+ */
+__initdata LIST_HEAD(misc_rmrr_units);
+
+/*
+ * Parse rmrr Xen command line options and add parsed
+ * device and region into apci_rmrr_unit list to mapped
+ * as RMRRs parsed from ACPI.
+ * Format: rmrr=[sbdf]start<:end>,[sbdf]start:<end>
+ * end address can be ommited and one page will be used
+ * for mapping with start pfn.
+ */
+static void __init parse_iommu_extra_rmrr(const char *s)
+{
+    unsigned int idx = 0, found = 0;
+    struct misc_rmrr_unit *rmrru;
+    unsigned int seg, bus, dev, func;
+    const char *str, *cur;
+    u64 start, end;
+
+    do {
+        if ( idx >= 10 )
+            break;
+
+        if ( *s != '[' )
+            break;
+
+        str = s;
+        seg = bus = dev = func = 0;
+        str = parse_pci(str + 1, &seg, &bus, &dev, &func);
+        if ( !str )
+        {
+            str = strchr(s, ']');
+            if ( !str )
+                return;
+        }
+        else
+            found = 1;
+
+        s = str;
+        if ( *s != ']' )
+            return;
+
+        start = simple_strtoull(cur = s + 1, &s, 0);
+        if ( cur == s )
+            break;
+
+        if ( *s == ':' )
+        {
+            end = simple_strtoull(cur = s + 1, &s, 0);
+            if ( cur == s )
+                break;
+        }
+        else
+            end = start;
+
+        if ( !found )
+            continue;
+
+        if ( end >= start )
+        {
+            rmrru = xzalloc(struct misc_rmrr_unit);
+            if ( !rmrru )
+                return;
+            rmrru->base_address = start << PAGE_SHIFT;
+            rmrru->end_address = (end << PAGE_SHIFT) + 1;
+            rmrru->segment = seg;
+            rmrru->device = PCI_BDF(bus, dev, func);
+            list_add(&rmrru->list, &misc_rmrr_units);
+        }
+        else
+        {
+            printk(XENLOG_WARNING "Bad rmrr: start > end, %"PRIx64" > 
%"PRIx64"\n",
+                   start, end);
+            break;
+        }
+        idx++;
+    } while ( *s++ == ',' );
+}
+
 static void __init parse_iommu_param(char *s)
 {
     char *ss;
@@ -153,6 +237,8 @@ void __hwdom_init iommu_hwdom_init(struct domain *d)
     if ( !iommu_enabled )
         return;
 
+    parse_iommu_extra_rmrr(misc_rmrr);
+
     register_keyhandler('o', &iommu_p2m_table);
     d->need_iommu = !!iommu_dom0_strict;
     if ( need_iommu(d) && !iommu_use_hap_pt(d) )
diff --git a/xen/drivers/passthrough/vtd/iommu.c 
b/xen/drivers/passthrough/vtd/iommu.c
index 2e113d7..9cb6e73 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1232,6 +1232,38 @@ static int intel_iommu_domain_init(struct domain *d)
     return 0;
 }
 
+static void add_misc_rmrr(void)
+{
+    struct acpi_rmrr_unit *rmrrn;
+    struct misc_rmrr_unit *rmrru, *r;
+
+    list_for_each_entry_safe( rmrru, r, &misc_rmrr_units, list )
+    {
+        rmrrn = xzalloc(struct acpi_rmrr_unit);
+        if ( !rmrrn )
+            goto free;
+
+        rmrrn->scope.devices = xzalloc(typeof(*rmrrn->scope.devices));
+        if ( !rmrrn->scope.devices )
+        {
+            xfree(rmrrn);
+            goto free;
+        }
+        rmrrn->scope.devices_cnt = 1;
+        rmrrn->segment = rmrru->segment;
+        rmrrn->scope.devices[0] = rmrru->device;
+
+        if ( register_one_rmrr(rmrrn) )
+        {
+            xfree(rmrrn->scope.devices);
+            xfree(rmrrn);
+        }
+ free:
+        list_del(&rmrru->list);
+        xfree(rmrru);
+    }
+}
+
 static void __hwdom_init intel_iommu_hwdom_init(struct domain *d)
 {
     struct acpi_drhd_unit *drhd;
@@ -1243,6 +1275,7 @@ static void __hwdom_init intel_iommu_hwdom_init(struct 
domain *d)
     }
 
     setup_hwdom_pci_devices(d, setup_hwdom_device);
+    add_misc_rmrr();
     setup_hwdom_rmrr(d);
 
     iommu_flush_all();
diff --git a/xen/drivers/passthrough/vtd/iommu.h 
b/xen/drivers/passthrough/vtd/iommu.h
index c3e5181..b3c1b59 100644
--- a/xen/drivers/passthrough/vtd/iommu.h
+++ b/xen/drivers/passthrough/vtd/iommu.h
@@ -484,6 +484,7 @@ struct qinval_entry {
 extern struct list_head acpi_drhd_units;
 extern struct list_head acpi_rmrr_units;
 extern struct list_head acpi_ioapic_units;
+extern struct list_head misc_rmrr_units;
 
 struct qi_ctrl {
     u64 qinval_maddr;  /* queue invalidation page machine address */
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 8eb764a..2c43956 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -191,4 +191,13 @@ DECLARE_PER_CPU(bool_t, iommu_dont_flush_iotlb);
 extern struct spinlock iommu_pt_cleanup_lock;
 extern struct page_list_head iommu_pt_cleanup_list;
 
+/*RMRR units derived from command line rmrr option */
+struct misc_rmrr_unit {
+    struct list_head list;
+    u64    base_address;
+    u64    end_address;
+    u16    segment;
+    u16    device;
+};
+
 #endif /* _IOMMU_H_ */
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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