# 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
|