26369-libxl-devid.patch - fate##313584: pass bios information to XEN HVM guest 26554-hvm-firmware-passthrough.patch 26555-hvm-firmware-passthrough.patch 26556-hvm-firmware-passthrough.patch - Upstream patches from Jan 26516-ACPI-parse-table-retval.patch (Replaces CVE-2013-0153-xsa36.patch) 26517-AMD-IOMMU-clear-irtes.patch (Replaces CVE-2013-0153-xsa36.patch) 26518-AMD-IOMMU-disable-if-SATA-combined-mode.patch (Replaces CVE-2013-0153-xsa36.patch) 26519-AMD-IOMMU-perdev-intremap-default.patch (Replaces CVE-2013-0153-xsa36.patch) 26526-pvdrv-no-devinit.patch 26529-gcc48-build-fix.patch 26531-AMD-IOMMU-IVHD-special-missing.patch (Replaces CVE-2013-0153-xsa36.patch) 26532-AMD-IOMMU-phantom-MSI.patch 26536-xenoprof-div-by-0.patch 26576-x86-APICV-migration.patch 26577-x86-APICV-x2APIC.patch 26578-AMD-IOMMU-replace-BUG_ON.patch - bnc#797014 - no way to control live migrations 26547-tools-xc_fix_logic_error_in_stdiostream_progress.patch 26548-tools-xc_handle_tty_output_differently_in_stdiostream_progress.patch 26549-tools-xc_turn_XCFLAGS_*_into_shifts.patch 26550-tools-xc_restore_logging_in_xc_save.patch 26551-tools-xc_log_pid_in_xc_save-xc_restore_output.patch - PVonHVM: __devinit was removed in linux-3.8 OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=229
206 lines
6.8 KiB
Diff
206 lines
6.8 KiB
Diff
References: CVE-2013-0153 XSA-36 bnc#800275
|
|
|
|
# HG changeset patch
|
|
# User Jan Beulich <jbeulich@suse.com>
|
|
# Date 1360074047 -3600
|
|
# Node ID 601139e2b0db7dc8a5bb69b9b7373fb87742741c
|
|
# Parent 32d4516a97f0b22ed06155f7b8e0bff075024991
|
|
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@suse.com>
|
|
|
|
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@amd.com>
|
|
|
|
--- a/xen/drivers/passthrough/amd/iommu_acpi.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_acpi.c
|
|
@@ -22,6 +22,7 @@
|
|
#include <xen/errno.h>
|
|
#include <xen/acpi.h>
|
|
#include <asm/apicdef.h>
|
|
+#include <asm/io_apic.h>
|
|
#include <asm/amd-iommu.h>
|
|
#include <asm/hvm/svm/amd-iommu-proto.h>
|
|
|
|
@@ -635,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(*special);
|
|
if ( header_length < (block_length + dev_length) )
|
|
@@ -651,10 +653,59 @@ static u16 __init parse_ivhd_device_spec
|
|
}
|
|
|
|
add_ivrs_mapping_entry(bdf, bdf, special->header.data_setting, iommu);
|
|
- /* set device id of ioapic */
|
|
- ioapic_sbdf[special->handle].bdf = bdf;
|
|
- ioapic_sbdf[special->handle].seg = seg;
|
|
- return dev_length;
|
|
+
|
|
+ if ( special->variety != ACPI_IVHD_IOAPIC )
|
|
+ {
|
|
+ if ( special->variety != ACPI_IVHD_HPET )
|
|
+ printk(XENLOG_ERR "Unrecognized IVHD special variety %#x\n",
|
|
+ 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) != special->handle )
|
|
+ continue;
|
|
+
|
|
+ if ( ioapic_sbdf[special->handle].pin_setup )
|
|
+ {
|
|
+ if ( ioapic_sbdf[special->handle].bdf == bdf &&
|
|
+ ioapic_sbdf[special->handle].seg == seg )
|
|
+ AMD_IOMMU_DEBUG("IVHD Warning: Duplicate IO-APIC %#x entries\n",
|
|
+ special->handle);
|
|
+ else
|
|
+ {
|
|
+ printk(XENLOG_ERR "IVHD Error: Conflicting IO-APIC %#x entries\n",
|
|
+ special->handle);
|
|
+ if ( amd_iommu_perdev_intremap )
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* set device id of ioapic */
|
|
+ ioapic_sbdf[special->handle].bdf = bdf;
|
|
+ ioapic_sbdf[special->handle].seg = seg;
|
|
+
|
|
+ ioapic_sbdf[special->handle].pin_setup = xzalloc_array(
|
|
+ unsigned long, BITS_TO_LONGS(nr_ioapic_entries[apic]));
|
|
+ if ( nr_ioapic_entries[apic] &&
|
|
+ !ioapic_sbdf[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", special->handle);
|
|
+ return 0;
|
|
}
|
|
|
|
static int __init parse_ivhd_block(const struct acpi_ivrs_hardware *ivhd_block)
|
|
--- a/xen/drivers/passthrough/amd/iommu_intr.c
|
|
+++ b/xen/drivers/passthrough/amd/iommu_intr.c
|
|
@@ -99,12 +99,12 @@ static void update_intremap_entry(u32* e
|
|
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;
|
|
@@ -120,6 +120,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(iommu->seg, bdf, old_offset);
|
|
+ }
|
|
entry = (u32*)get_intremap_entry(iommu->seg, req_id, offset);
|
|
update_intremap_entry(entry, vector, delivery_mode, dest_mode, dest);
|
|
|
|
@@ -188,6 +196,7 @@ int __init amd_iommu_setup_ioapic_remapp
|
|
amd_iommu_flush_intremap(iommu, req_id);
|
|
spin_unlock_irqrestore(&iommu->lock, flags);
|
|
}
|
|
+ set_bit(pin, ioapic_sbdf[IO_APIC_ID(apic)].pin_setup);
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -199,6 +208,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, seg, bdf;
|
|
struct amd_iommu *iommu;
|
|
|
|
@@ -236,6 +246,14 @@ void amd_iommu_ioapic_update_ire(
|
|
*(((u32 *)&new_rte) + 1) = value;
|
|
}
|
|
|
|
+ if ( new_rte.mask &&
|
|
+ !test_bit(pin, ioapic_sbdf[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 )
|
|
{
|
|
@@ -244,7 +262,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_sbdf[IO_APIC_ID(apic)].pin_setup) ? &old_rte
|
|
+ : NULL);
|
|
|
|
/* Forward write access to IO-APIC RTE */
|
|
__io_apic_write(apic, reg, value);
|
|
@@ -354,6 +376,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);
|
|
}
|
|
|
|
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
|
|
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
|
|
@@ -100,6 +100,7 @@ void amd_iommu_read_msi_from_ire(
|
|
|
|
extern struct ioapic_sbdf {
|
|
u16 bdf, seg;
|
|
+ unsigned long *pin_setup;
|
|
} ioapic_sbdf[MAX_IO_APICS];
|
|
extern void *shared_intremap_table;
|
|
|