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

[Xen-changelog] [xen-unstable] amd iommu: Cleanup initialization functions and fix a fatal page fault



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1252309370 -3600
# Node ID 6a2a099c8ef420ae8aa24bcc52788008eb97a898
# Parent  2c2cdaffc3f94ab9b910be9e7c09c6e1d629a3ea
amd iommu: Cleanup initialization functions and fix a fatal page fault
caused by out-of-bounds access to irq_to_iommu array.

Signed-off-by: Wei Wang <wei.wang2@xxxxxxx>
---
 xen/drivers/passthrough/amd/iommu_init.c      |  104 ++++++++++++++++----------
 xen/drivers/passthrough/amd/pci_amd_iommu.c   |   28 -------
 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h |    3 
 3 files changed, 66 insertions(+), 69 deletions(-)

diff -r 2c2cdaffc3f9 -r 6a2a099c8ef4 xen/drivers/passthrough/amd/iommu_init.c
--- a/xen/drivers/passthrough/amd/iommu_init.c  Mon Sep 07 08:41:45 2009 +0100
+++ b/xen/drivers/passthrough/amd/iommu_init.c  Mon Sep 07 08:42:50 2009 +0100
@@ -514,10 +514,6 @@ void enable_iommu(struct amd_iommu *iomm
 
     spin_lock_irqsave(&iommu->lock, flags);
 
-    irq_to_iommu = xmalloc_array(struct amd_iommu *, nr_irqs);
-    BUG_ON(!irq_to_iommu);
-    memset(irq_to_iommu, 0, nr_irqs * sizeof(struct iommu*));
-
     if ( iommu->enabled )
     {
         spin_unlock_irqrestore(&iommu->lock, flags); 
@@ -551,12 +547,6 @@ static void __init deallocate_iommu_tabl
         __free_amd_iommu_tables(table->buffer, order);
         table->buffer = NULL;
     }
-}
-
-static void __init deallocate_iommu_tables(struct amd_iommu *iommu)
-{
-    deallocate_iommu_table_struct(&iommu->cmd_buffer);
-    deallocate_iommu_table_struct(&iommu->event_log);
 }
 
 static int __init allocate_iommu_table_struct(struct table_struct *table,
@@ -578,7 +568,7 @@ static int __init allocate_iommu_table_s
     return 0;
 }
 
-static int __init allocate_iommu_tables(struct amd_iommu *iommu)
+static int __init allocate_cmd_buffer(struct amd_iommu *iommu)
 {
     /* allocate 'command buffer' in power of 2 increments of 4K */
     iommu->cmd_buffer_tail = 0;
@@ -589,10 +579,12 @@ static int __init allocate_iommu_tables(
     iommu->cmd_buffer.entries = iommu->cmd_buffer.alloc_size /
                                 IOMMU_CMD_BUFFER_ENTRY_SIZE;
 
-    if ( allocate_iommu_table_struct(&iommu->cmd_buffer, "Command Buffer") != 
0 )
-        goto error_out;
-
-    /* allocate 'event log' in power of 2 increments of 4K */
+    return (allocate_iommu_table_struct(&iommu->cmd_buffer, "Command Buffer"));
+}
+
+static int __init allocate_event_log(struct amd_iommu *iommu)
+{
+   /* allocate 'event log' in power of 2 increments of 4K */
     iommu->event_log_head = 0;
     iommu->event_log.alloc_size = PAGE_SIZE <<
                                   get_order_from_bytes(
@@ -601,19 +593,15 @@ static int __init allocate_iommu_tables(
     iommu->event_log.entries = iommu->event_log.alloc_size /
                                IOMMU_EVENT_LOG_ENTRY_SIZE;
 
-    if ( allocate_iommu_table_struct(&iommu->event_log, "Event Log") != 0 )
-        goto error_out;
-
-    return 0;
-
- error_out:
-    deallocate_iommu_tables(iommu);
-    return -ENOMEM;
+    return (allocate_iommu_table_struct(&iommu->event_log, "Event Log"));
 }
 
 int __init amd_iommu_init_one(struct amd_iommu *iommu)
 {
-    if ( allocate_iommu_tables(iommu) != 0 )
+    if ( allocate_cmd_buffer(iommu) != 0 )
+        goto error_out;
+
+    if ( allocate_event_log(iommu) != 0 )
         goto error_out;
 
     if ( map_iommu_mmio_region(iommu) != 0 )
@@ -640,20 +628,46 @@ error_out:
     return -ENODEV;
 }
 
-void __init amd_iommu_init_cleanup(void)
+static void __init amd_iommu_init_cleanup(void)
 {
     struct amd_iommu *iommu, *next;
 
+    /* free amd iommu list */
     list_for_each_entry_safe ( iommu, next, &amd_iommu_head, list )
     {
         list_del(&iommu->list);
         if ( iommu->enabled )
         {
-            deallocate_iommu_tables(iommu);
+            deallocate_iommu_table_struct(&iommu->cmd_buffer);
+            deallocate_iommu_table_struct(&iommu->event_log);
             unmap_iommu_mmio_region(iommu);
         }
         xfree(iommu);
     }
+
+    /* free interrupt remapping table */
+    deallocate_intremap_table();
+
+    /* free device table */
+    deallocate_iommu_table_struct(&device_table);
+
+    /* free ivrs_mappings[] */
+    if ( ivrs_mappings )
+    {
+        xfree(ivrs_mappings);
+        ivrs_mappings = NULL;
+    }
+
+    /* free irq_to_iommu[] */
+    if ( irq_to_iommu )
+    {
+        xfree(irq_to_iommu);
+        irq_to_iommu = NULL;
+    }
+
+    iommu_enabled = 0;
+    iommu_passthrough = 0;
+    iommu_intremap = 0;
 }
 
 static int __init init_ivrs_mapping(void)
@@ -696,31 +710,45 @@ static int __init amd_iommu_setup_device
     return ( allocate_iommu_table_struct(&device_table, "Device Table") );
 }
 
-int __init amd_iommu_setup_shared_tables(void)
-{
-    BUG_ON( !ivrs_bdf_entries );
+int __init amd_iommu_init(void)
+{
+    struct amd_iommu *iommu;
+
+    BUG_ON( !iommu_found() );
+
+    irq_to_iommu = xmalloc_array(struct amd_iommu *, nr_irqs);
+    BUG_ON(!irq_to_iommu);
+    memset(irq_to_iommu, 0, nr_irqs * sizeof(struct iommu*));
+
+    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
+
+    if ( !ivrs_bdf_entries )
+        goto error_out;
 
     if ( init_ivrs_mapping() != 0 )
         goto error_out;
 
+    if ( amd_iommu_update_ivrs_mapping_acpi() != 0 )
+        goto error_out;
+
+    /* allocate and initialize a global device table shared by all iommus */
     if ( amd_iommu_setup_device_table() != 0 )
         goto error_out;
 
+    /* initialize io-apic interrupt remapping entries */
     if ( amd_iommu_setup_intremap_table() != 0 )
         goto error_out;
 
+    /* per iommu initialization  */
+    for_each_amd_iommu ( iommu )
+        if ( amd_iommu_init_one(iommu) != 0 )
+            goto error_out;
+
     return 0;
 
 error_out:
-    deallocate_intremap_table();
-    deallocate_iommu_table_struct(&device_table);
-
-    if ( ivrs_mappings )
-    {
-        xfree(ivrs_mappings);
-        ivrs_mappings = NULL;
-    }
-    return -ENOMEM;
+    amd_iommu_init_cleanup();
+    return -ENODEV;
 }
 
 static void disable_iommu(struct amd_iommu *iommu)
diff -r 2c2cdaffc3f9 -r 6a2a099c8ef4 xen/drivers/passthrough/amd/pci_amd_iommu.c
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c       Mon Sep 07 08:41:45 
2009 +0100
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c       Mon Sep 07 08:42:50 
2009 +0100
@@ -28,34 +28,6 @@ extern struct ivrs_mappings *ivrs_mappin
 extern struct ivrs_mappings *ivrs_mappings;
 extern void *int_remap_table;
 
-int __init amd_iommu_init(void)
-{
-    struct amd_iommu *iommu;
-
-    BUG_ON( !iommu_found() );
-
-    ivrs_bdf_entries = amd_iommu_get_ivrs_dev_entries();
-
-    if ( !ivrs_bdf_entries )
-        goto error_out;
-
-    if ( amd_iommu_setup_shared_tables() != 0 )
-        goto error_out;
-
-    if ( amd_iommu_update_ivrs_mapping_acpi() != 0 )
-        goto error_out;
-
-    for_each_amd_iommu ( iommu )
-        if ( amd_iommu_init_one(iommu) != 0 )
-            goto error_out;
-
-    return 0;
-
-error_out:
-    amd_iommu_init_cleanup();
-    return -ENODEV;
-}
-
 struct amd_iommu *find_iommu_for_device(int bus, int devfn)
 {
     u16 bdf = (bus << 8) | devfn;
diff -r 2c2cdaffc3f9 -r 6a2a099c8ef4 
xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h     Mon Sep 07 08:41:45 
2009 +0100
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h     Mon Sep 07 08:42:50 
2009 +0100
@@ -52,10 +52,7 @@ int __init amd_iommu_detect_acpi(void);
 
 /* amd-iommu-init functions */
 int __init amd_iommu_init(void);
-int __init amd_iommu_init_one(struct amd_iommu *iommu);
 int __init amd_iommu_update_ivrs_mapping_acpi(void);
-void __init amd_iommu_init_cleanup(void);
-int __init amd_iommu_setup_shared_tables(void);
 
 /* mapping functions */
 int amd_iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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