79 lines
3.3 KiB
Diff
79 lines
3.3 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1226313701 0
|
|
# Node ID 40668908260c7667cc5a0b75862352016c52e38f
|
|
# Parent 832efb028a1dc72fb52edc11c958fd19f8542e48
|
|
vtd: fix interrupt remapping to handle SMI RTE's with uninitialized
|
|
reserved fields
|
|
|
|
Some BIOS does not zero out reserve fields in IOAPIC RTE's.
|
|
clear_IO_APIC() zeroes out all RTE's except for RTE with MSI delivery
|
|
type. This is a problem when the host OS converts SMI delivery type
|
|
to some other type but leaving the reserved field uninitialized. This
|
|
can cause interrupt remapping table out of bound error if "format"
|
|
field is 1 and the uninitialized "index" field has a value that that
|
|
is larger than the maximum index of interrupt remapping table.
|
|
|
|
Signed-off-by: Allen Kay <allen.m.kay@intel.com>=
|
|
|
|
Index: xen-3.3.1-testing/xen/drivers/passthrough/vtd/dmar.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/drivers/passthrough/vtd/dmar.c
|
|
+++ xen-3.3.1-testing/xen/drivers/passthrough/vtd/dmar.c
|
|
@@ -369,7 +369,9 @@ acpi_parse_one_rmrr(struct acpi_dmar_ent
|
|
|
|
if ( rmrr->base_address >= rmrr->end_address )
|
|
{
|
|
- dprintk(XENLOG_ERR VTDPREFIX, "RMRR is incorrect.\n");
|
|
+ dprintk(XENLOG_ERR VTDPREFIX,
|
|
+ "RMRR error: base_addr %"PRIx64" end_address %"PRIx64"\n",
|
|
+ rmrr->base_address, rmrr->end_address);
|
|
return -EFAULT;
|
|
}
|
|
|
|
Index: xen-3.3.1-testing/xen/drivers/passthrough/vtd/intremap.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/drivers/passthrough/vtd/intremap.c
|
|
+++ xen-3.3.1-testing/xen/drivers/passthrough/vtd/intremap.c
|
|
@@ -201,7 +201,7 @@ unsigned int io_apic_read_remap_rte(
|
|
|
|
remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
|
|
|
|
- if ( remap_rte->format == 0 )
|
|
+ if ( (remap_rte->format == 0) || (old_rte.delivery_mode == dest_SMI) )
|
|
{
|
|
*IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
|
|
return *(IO_APIC_BASE(apic)+4);
|
|
@@ -247,6 +247,31 @@ void io_apic_write_remap_rte(
|
|
|
|
remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
|
|
|
|
+ if ( old_rte.delivery_mode == dest_SMI )
|
|
+ {
|
|
+ /* Some BIOS does not zero out reserve fields in IOAPIC
|
|
+ * RTE's. clear_IO_APIC() zeroes out all RTE's except for RTE
|
|
+ * with MSI delivery type. This is a problem when the host
|
|
+ * OS converts SMI delivery type to some other type but leaving
|
|
+ * the reserved field uninitialized. This can cause interrupt
|
|
+ * remapping table out of bound error if "format" field is 1
|
|
+ * and the "index" field has a value that that is larger than
|
|
+ * the maximum index of interrupt remapping table.
|
|
+ */
|
|
+ if ( remap_rte->format == 1 )
|
|
+ {
|
|
+ remap_rte->format = 0;
|
|
+ *IO_APIC_BASE(apic) = reg;
|
|
+ *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
|
|
+ *IO_APIC_BASE(apic) = reg + 1;
|
|
+ *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
|
|
+ }
|
|
+
|
|
+ *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
|
|
+ *(IO_APIC_BASE(apic)+4) = value;
|
|
+ return;
|
|
+ }
|
|
+
|
|
/* mask the interrupt while we change the intremap table */
|
|
saved_mask = remap_rte->mask;
|
|
remap_rte->mask = 1;
|