[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-4.1-testing] AMD, IOMMU: Clean up old entries in remapping tables when creating new one
# HG changeset patch # User Jan Beulich <jbeulich@xxxxxxxx> # Date 1360074944 -3600 # Node ID cac6ae5e5dc68e9ca4e80bcfff04a19dcb3e3113 # Parent dd6694df1a31608cffc1ff0f89b1f76adab87b68 AMD,IOMMU: Clean up old entries in remapping tables when creating new one When changing the affinity of an IRQ associated with a passed through PCI device, clear previous mapping. This is XSA-36 / CVE-2013-0153. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> In addition, because some BIOSes may incorrectly program IVRS entries for IOAPIC try to check for entry's consistency. Specifically, if conflicting entries are found disable IOMMU if per-device remapping table is used. If entries refer to bogus IOAPIC IDs disable IOMMU unconditionally Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxx> xen-unstable changeset: 26517:601139e2b0db xen-unstable date: Tue Feb 5 14:20:47 UTC 2013 --- diff -r dd6694df1a31 -r cac6ae5e5dc6 xen/drivers/passthrough/amd/iommu_acpi.c --- a/xen/drivers/passthrough/amd/iommu_acpi.c Tue Feb 05 15:34:55 2013 +0100 +++ b/xen/drivers/passthrough/amd/iommu_acpi.c Tue Feb 05 15:35:44 2013 +0100 @@ -21,6 +21,7 @@ #include <xen/config.h> #include <xen/errno.h> #include <asm/apicdef.h> +#include <asm/io_apic.h> #include <asm/amd-iommu.h> #include <asm/hvm/svm/amd-iommu-proto.h> #include <asm/hvm/svm/amd-iommu-acpi.h> @@ -29,7 +30,6 @@ extern unsigned long amd_iommu_page_entr extern unsigned short ivrs_bdf_entries; extern struct ivrs_mappings *ivrs_mappings; extern unsigned short last_bdf; -extern int ioapic_bdf[MAX_IO_APICS]; extern void *shared_intremap_table; static void add_ivrs_mapping_entry( @@ -636,6 +636,7 @@ static u16 __init parse_ivhd_device_spec u16 header_length, u16 block_length, struct amd_iommu *iommu) { u16 dev_length, bdf; + int apic; dev_length = sizeof(struct acpi_ivhd_device_special); if ( header_length < (block_length + dev_length) ) @@ -652,9 +653,58 @@ static u16 __init parse_ivhd_device_spec } add_ivrs_mapping_entry(bdf, bdf, ivhd_device->header.flags, iommu); - /* set device id of ioapic */ - ioapic_bdf[ivhd_device->special.handle] = bdf; - return dev_length; + + if ( ivhd_device->special.variety != 1 /* ACPI_IVHD_IOAPIC */ ) + { + if ( ivhd_device->special.variety != 2 /* ACPI_IVHD_HPET */ ) + printk(XENLOG_ERR "Unrecognized IVHD special variety %#x\n", + ivhd_device->special.variety); + return dev_length; + } + + /* + * Some BIOSes have IOAPIC broken entries so we check for IVRS + * consistency here --- whether entry's IOAPIC ID is valid and + * whether there are conflicting/duplicated entries. + */ + for ( apic = 0; apic < nr_ioapics; apic++ ) + { + if ( IO_APIC_ID(apic) != ivhd_device->special.handle ) + continue; + + if ( ioapic_bdf[ivhd_device->special.handle].pin_setup ) + { + if ( ioapic_bdf[ivhd_device->special.handle].bdf == bdf ) + AMD_IOMMU_DEBUG("IVHD Warning: Duplicate IO-APIC %#x entries\n", + ivhd_device->special.handle); + else + { + printk(XENLOG_ERR "IVHD Error: Conflicting IO-APIC %#x entries\n", + ivhd_device->special.handle); + if ( amd_iommu_perdev_intremap ) + return 0; + } + } + else + { + /* set device id of ioapic */ + ioapic_bdf[ivhd_device->special.handle].bdf = bdf; + + ioapic_bdf[ivhd_device->special.handle].pin_setup = xzalloc_array( + unsigned long, BITS_TO_LONGS(nr_ioapic_registers[apic])); + if ( nr_ioapic_registers[apic] && + !ioapic_bdf[IO_APIC_ID(apic)].pin_setup ) + { + printk(XENLOG_ERR "IVHD Error: Out of memory\n"); + return 0; + } + } + return dev_length; + } + + printk(XENLOG_ERR "IVHD Error: Invalid IO-APIC %#x\n", + ivhd_device->special.handle); + return 0; } static int __init parse_ivhd_block(struct acpi_ivhd_block_header *ivhd_block) diff -r dd6694df1a31 -r cac6ae5e5dc6 xen/drivers/passthrough/amd/iommu_intr.c --- a/xen/drivers/passthrough/amd/iommu_intr.c Tue Feb 05 15:34:55 2013 +0100 +++ b/xen/drivers/passthrough/amd/iommu_intr.c Tue Feb 05 15:35:44 2013 +0100 @@ -27,7 +27,7 @@ #define INTREMAP_LENGTH 0xB #define INTREMAP_ENTRIES (1 << INTREMAP_LENGTH) -int ioapic_bdf[MAX_IO_APICS]; +struct ioapic_bdf ioapic_bdf[MAX_IO_APICS]; extern struct ivrs_mappings *ivrs_mappings; extern unsigned short ivrs_bdf_entries; void *shared_intremap_table; @@ -117,12 +117,12 @@ void invalidate_interrupt_table(struct a static void update_intremap_entry_from_ioapic( int bdf, struct amd_iommu *iommu, - struct IO_APIC_route_entry *ioapic_rte) + const struct IO_APIC_route_entry *rte, + const struct IO_APIC_route_entry *old_rte) { unsigned long flags; u32* entry; u8 delivery_mode, dest, vector, dest_mode; - struct IO_APIC_route_entry *rte = ioapic_rte; int req_id; spinlock_t *lock; int offset; @@ -138,6 +138,14 @@ static void update_intremap_entry_from_i spin_lock_irqsave(lock, flags); offset = get_intremap_offset(vector, delivery_mode); + if ( old_rte ) + { + int old_offset = get_intremap_offset(old_rte->vector, + old_rte->delivery_mode); + + if ( offset != old_offset ) + free_intremap_entry(bdf, old_offset); + } entry = (u32*)get_intremap_entry(req_id, offset); update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest); @@ -176,7 +184,7 @@ int __init amd_iommu_setup_ioapic_remapp continue; /* get device id of ioapic devices */ - bdf = ioapic_bdf[IO_APIC_ID(apic)]; + bdf = ioapic_bdf[IO_APIC_ID(apic)].bdf; iommu = find_iommu_for_device(bdf); if ( !iommu ) { @@ -207,6 +215,7 @@ int __init amd_iommu_setup_ioapic_remapp flush_command_buffer(iommu); spin_unlock_irqrestore(&iommu->lock, flags); } + set_bit(pin, ioapic_bdf[IO_APIC_ID(apic)].pin_setup); } } return 0; @@ -218,6 +227,7 @@ void amd_iommu_ioapic_update_ire( struct IO_APIC_route_entry old_rte = { 0 }; struct IO_APIC_route_entry new_rte = { 0 }; unsigned int rte_lo = (reg & 1) ? reg - 1 : reg; + unsigned int pin = (reg - 0x10) / 2; int saved_mask, bdf; struct amd_iommu *iommu; @@ -228,7 +238,7 @@ void amd_iommu_ioapic_update_ire( } /* get device id of ioapic devices */ - bdf = ioapic_bdf[IO_APIC_ID(apic)]; + bdf = ioapic_bdf[IO_APIC_ID(apic)].bdf; iommu = find_iommu_for_device(bdf); if ( !iommu ) { @@ -254,6 +264,14 @@ void amd_iommu_ioapic_update_ire( *(((u32 *)&new_rte) + 1) = value; } + if ( new_rte.mask && + !test_bit(pin, ioapic_bdf[IO_APIC_ID(apic)].pin_setup) ) + { + ASSERT(saved_mask); + __io_apic_write(apic, reg, value); + return; + } + /* mask the interrupt while we change the intremap table */ if ( !saved_mask ) { @@ -262,7 +280,11 @@ void amd_iommu_ioapic_update_ire( } /* Update interrupt remapping entry */ - update_intremap_entry_from_ioapic(bdf, iommu, &new_rte); + update_intremap_entry_from_ioapic( + bdf, iommu, &new_rte, + test_and_set_bit(pin, + ioapic_bdf[IO_APIC_ID(apic)].pin_setup) ? &old_rte + : NULL); /* Forward write access to IO-APIC RTE */ __io_apic_write(apic, reg, value); @@ -373,6 +395,12 @@ void amd_iommu_msi_msg_update_ire( return; } + if ( msi_desc->remap_index >= 0 ) + update_intremap_entry_from_msi_msg(iommu, pdev, msi_desc, NULL); + + if ( !msg ) + return; + update_intremap_entry_from_msi_msg(iommu, pdev, msi_desc, msg); } diff -r dd6694df1a31 -r cac6ae5e5dc6 xen/include/asm-x86/hvm/svm/amd-iommu-proto.h --- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Tue Feb 05 15:34:55 2013 +0100 +++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h Tue Feb 05 15:35:44 2013 +0100 @@ -88,6 +88,11 @@ void amd_iommu_read_msi_from_ire( unsigned int amd_iommu_read_ioapic_from_ire( unsigned int apic, unsigned int reg); +extern struct ioapic_bdf { + u16 bdf; + unsigned long *pin_setup; +} ioapic_bdf[]; + /* power management support */ void amd_iommu_resume(void); void amd_iommu_suspend(void); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |