debuggers.hg

changeset 20696:b543acc1aaad

iommu: Actually clear IO-APIC pins on boot and shutdown when used with an IOMMU

When booted with iommu=on, io_apic_read/write functions call into the
interrupt remapping code to update the IRTEs. Unfortunately, on boot
and shutdown, we really want clear_IO_APIC() to sanitize the actual
IOAPIC RTE, and not just the bits that are active when interrupt
remapping is enabled. This is particularly a problem on older
versions of Xen which used the IOAPIC RTE as the canonical source for
the IRTE index. In that case, clear_IO_APIC() actually causes
whatever happens to be stored in the RTEs to be used as an IRTE index,
which can come back and bite us in ioapic_guest_write() if we attempt
to remove an interrupt that didn't actually exist. Current upstream
appears less susceptible to errors since the IRTE index is stored in
an array, but it's still a good idea to sanitize the IOAPIC state.

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 16 12:32:35 2009 +0000 (2009-12-16)
parents 976d679b04fb
children cbcb3d564b2f
files xen/arch/x86/io_apic.c xen/include/asm-x86/io_apic.h
line diff
     1.1 --- a/xen/arch/x86/io_apic.c	Wed Dec 16 12:23:21 2009 +0000
     1.2 +++ b/xen/arch/x86/io_apic.c	Wed Dec 16 12:32:35 2009 +0000
     1.3 @@ -221,15 +221,21 @@ static void eoi_IO_APIC_irq(unsigned int
     1.4      spin_unlock_irqrestore(&ioapic_lock, flags);
     1.5  }
     1.6  
     1.7 -static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
     1.8 +#define clear_IO_APIC_pin(a,p)     __clear_IO_APIC_pin(a,p,0)
     1.9 +#define clear_IO_APIC_pin_raw(a,p) __clear_IO_APIC_pin(a,p,1)
    1.10 +static void __clear_IO_APIC_pin(unsigned int apic, unsigned int pin, int raw)
    1.11  {
    1.12 +    unsigned int (*read)(unsigned int, unsigned int)
    1.13 +        = raw ? __io_apic_read : io_apic_read;
    1.14 +    void (*write)(unsigned int, unsigned int, unsigned int)
    1.15 +        = raw ? __io_apic_write : io_apic_write;
    1.16      struct IO_APIC_route_entry entry;
    1.17      unsigned long flags;
    1.18      
    1.19      /* Check delivery_mode to be sure we're not clearing an SMI pin */
    1.20      spin_lock_irqsave(&ioapic_lock, flags);
    1.21 -    *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
    1.22 -    *(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
    1.23 +    *(((int*)&entry) + 0) = (*read)(apic, 0x10 + 2 * pin);
    1.24 +    *(((int*)&entry) + 1) = (*read)(apic, 0x11 + 2 * pin);
    1.25      spin_unlock_irqrestore(&ioapic_lock, flags);
    1.26      if (entry.delivery_mode == dest_SMI)
    1.27          return;
    1.28 @@ -240,8 +246,8 @@ static void clear_IO_APIC_pin(unsigned i
    1.29      memset(&entry, 0, sizeof(entry));
    1.30      entry.mask = 1;
    1.31      spin_lock_irqsave(&ioapic_lock, flags);
    1.32 -    io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
    1.33 -    io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
    1.34 +    (*write)(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
    1.35 +    (*write)(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
    1.36      spin_unlock_irqrestore(&ioapic_lock, flags);
    1.37  }
    1.38  
    1.39 @@ -249,9 +255,12 @@ static void clear_IO_APIC (void)
    1.40  {
    1.41      int apic, pin;
    1.42  
    1.43 -    for (apic = 0; apic < nr_ioapics; apic++)
    1.44 -        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
    1.45 +    for (apic = 0; apic < nr_ioapics; apic++) {
    1.46 +        for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
    1.47              clear_IO_APIC_pin(apic, pin);
    1.48 +            clear_IO_APIC_pin_raw(apic, pin);
    1.49 +        }
    1.50 +    }
    1.51  }
    1.52  
    1.53  #ifdef CONFIG_SMP
     2.1 --- a/xen/include/asm-x86/io_apic.h	Wed Dec 16 12:23:21 2009 +0000
     2.2 +++ b/xen/include/asm-x86/io_apic.h	Wed Dec 16 12:32:35 2009 +0000
     2.3 @@ -131,20 +131,30 @@ extern struct mpc_config_ioapic mp_ioapi
     2.4  /* Only need to remap ioapic RTE (reg: 10~3Fh) */
     2.5  #define ioapic_reg_remapped(reg) (iommu_enabled && ((reg) >= 0x10))
     2.6  
     2.7 +static inline unsigned int __io_apic_read(unsigned int apic, unsigned int reg)
     2.8 +{
     2.9 +	*IO_APIC_BASE(apic) = reg;
    2.10 +	return *(IO_APIC_BASE(apic)+4);
    2.11 +}
    2.12 +
    2.13  static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
    2.14  {
    2.15  	if (ioapic_reg_remapped(reg))
    2.16  		return iommu_read_apic_from_ire(apic, reg);
    2.17 +	return __io_apic_read(apic, reg);
    2.18 +}
    2.19 +
    2.20 +static inline void __io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
    2.21 +{
    2.22  	*IO_APIC_BASE(apic) = reg;
    2.23 -	return *(IO_APIC_BASE(apic)+4);
    2.24 +	*(IO_APIC_BASE(apic)+4) = value;
    2.25  }
    2.26  
    2.27  static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
    2.28  {
    2.29  	if (ioapic_reg_remapped(reg))
    2.30  		return iommu_update_ire_from_apic(apic, reg, value);
    2.31 -	*IO_APIC_BASE(apic) = reg;
    2.32 -	*(IO_APIC_BASE(apic)+4) = value;
    2.33 +	__io_apic_write(apic, reg, value);
    2.34  }
    2.35  
    2.36  static inline void io_apic_eoi(unsigned int apic, unsigned int vector)