[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] kexec: disable iommu and x2apic before jumping into the kdump kernel



This is a massive hack but is better than the code currently in place.
Some functions have been duped into a crash_* version to separate them
from the regular shutdown path, where disabling these subsystems is
irrelevant.

Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>

diff -r 0c446850d85e -r efa733ebd00d xen/arch/x86/apic.c
--- a/xen/arch/x86/apic.c       Wed May 11 12:58:04 2011 +0100
+++ b/xen/arch/x86/apic.c       Fri May 13 13:45:05 2011 +0100
@@ -344,6 +344,42 @@
     }
 }
 
+/* Customised version of disable_local_APIC which is only called on the kexec 
crash path.
+ * It is a brutal hack and only here untill the APIC code is overhauled.  We 
NEED to swtich
+ * out of x2apic mode whatever the case as the kdump kernel cant cope due to 
the MMIO <-> MSR
+ * swap invovled with x2apic mode.
+ */
+void crash_disable_local_APIC(void)
+{
+    uint64_t msr_content;
+    clear_local_APIC();
+
+    apic_write_around(APIC_SPIV,
+        apic_read(APIC_SPIV) & ~APIC_SPIV_APIC_ENABLED);
+
+    rdmsrl(MSR_IA32_APICBASE, msr_content);
+
+    /* This is the only way to exit x2apic mode.  Trying to disable x2apic 
mode while staying
+     * xapic mode will result in a protection fault which leads to a general 
protection fault
+     * as this is on the fault handler codepath.
+     */
+    msr_content &= ~(MSR_IA32_APICBASE_ENABLE|MSR_IA32_APICBASE_EXTD);
+    wrmsrl(MSR_IA32_APICBASE, msr_content);
+
+    /* In most cases, we should leave the lapic in xapic mode as this is the 
default state on
+     * CPU reset.  However, some bioses specifically disable xapic mode for 
hilarity sake so
+     * we should follow suit so the kdump kernel does not get confused about 
mismatching ACPI
+     * tables.
+     */
+    if ( ! enabled_via_apicbase) {
+           /* If we did not manually enable xapic mode, I.E. the bios left it 
enabled,
+            * lets follow suit and leave it enabled for the kdump kernel.
+            */
+        wrmsrl(MSR_IA32_APICBASE, msr_content | MSR_IA32_APICBASE_ENABLE);
+    }
+}
+
+
 /*
  * This is to verify that we're looking at a real local APIC.
  * Check these against your board if the CPUs aren't getting
diff -r 0c446850d85e -r efa733ebd00d xen/arch/x86/crash.c
--- a/xen/arch/x86/crash.c      Wed May 11 12:58:04 2011 +0100
+++ b/xen/arch/x86/crash.c      Fri May 13 13:45:05 2011 +0100
@@ -27,6 +27,8 @@
 #include <asm/hvm/support.h>
 #include <asm/apic.h>
 #include <asm/io_apic.h>
+#include <xen/iommu.h>
+#include <asm/hvm/iommu.h>
 
 static atomic_t waiting_for_crash_ipi;
 static unsigned int crashing_cpu;
@@ -43,7 +45,12 @@
 
     kexec_crash_save_cpu();
 
-    __stop_this_cpu();
+    crash_disable_local_APIC();
+    hvm_cpu_down();
+    /* Clear FPU, zapping any pending exceptions. Needed for warm reset with
+     * some BIOSes.*/
+    clts();
+    asm volatile ( "fninit" );
 
     atomic_dec(&waiting_for_crash_ipi);
 
@@ -77,7 +84,15 @@
         msecs--;
     }
 
-    __stop_this_cpu();
+    crash_disable_local_APIC();
+    hvm_cpu_down();
+    /* Clear FPU, zapping any pending exceptions. Needed for warm reset with
+     * some BIOSes.*/
+    clts();
+    asm volatile ( "fninit" );
+
+    x2apic_enabled = 0;
+
     disable_IO_APIC();
 
     local_irq_enable();
@@ -86,9 +101,24 @@
 void machine_crash_shutdown(void)
 {
     crash_xen_info_t *info;
+    const struct iommu_ops * ops;
 
     nmi_shootdown_cpus();
 
+    local_irq_disable();
+
+    /* Yes i know this is hacky but it is the easiest solution.  I should add 
an iommu_ops
+     * function called crash() or so which just disables the iommu 'fun' 
without saving state
+     */
+    ops = iommu_get_ops();
+    ops->suspend();
+
+    /* Yes i know this is from driver/passthrough/vtd/ but it appears to be 
architecture
+     * independant, and also bears little/no relation to x2apic.  Needs 
cleaning up
+     */
+    iommu_disable_x2apic_IR();
+    local_irq_enable();
+
     info = kexec_crash_save_info();
     info->xen_phys_start = xen_phys_start;
     info->dom0_pfn_to_mfn_frame_list_list =
diff -r 0c446850d85e -r efa733ebd00d xen/arch/x86/hpet.c
--- a/xen/arch/x86/hpet.c       Wed May 11 12:58:04 2011 +0100
+++ b/xen/arch/x86/hpet.c       Fri May 13 13:45:05 2011 +0100
@@ -670,6 +670,34 @@
     smp_send_event_check_mask(&cpu_online_map);
 }
 
+void crash_hpet_disable_legacy_broadcast(void)
+{
+    u32 cfg;
+
+    if ( !hpet_events || !(hpet_events->flags & HPET_EVT_LEGACY) )
+        return;
+
+    /* By this point in the crash handler, we are the only CPU still going,
+     * so the lock is irrelevant
+     */
+    /* spin_lock_irqsave(&hpet_events->lock, flags); */
+
+    hpet_events->flags |= HPET_EVT_DISABLE;
+
+    /* disable HPET T0 */
+    cfg = hpet_read32(HPET_Tn_CFG(0));
+    cfg &= ~HPET_TN_ENABLE;
+    hpet_write32(cfg, HPET_Tn_CFG(0));
+
+    /* Stop HPET legacy interrupts */
+    cfg = hpet_read32(HPET_CFG);
+    cfg &= ~HPET_CFG_LEGACY;
+    hpet_write32(cfg, HPET_CFG);
+
+    /* spin_unlock_irqrestore(&hpet_events->lock, flags); */
+}
+
+
 void hpet_broadcast_enter(void)
 {
     unsigned int cpu = smp_processor_id();
diff -r 0c446850d85e -r efa733ebd00d xen/arch/x86/machine_kexec.c
--- a/xen/arch/x86/machine_kexec.c      Wed May 11 12:58:04 2011 +0100
+++ b/xen/arch/x86/machine_kexec.c      Fri May 13 13:45:05 2011 +0100
@@ -97,7 +97,7 @@
     };
 
     if ( hpet_broadcast_is_available() )
-        hpet_disable_legacy_broadcast();
+        crash_hpet_disable_legacy_broadcast();
 
     /*
      * compat_machine_kexec() returns to idle pagetables, which requires us
diff -r 0c446850d85e -r efa733ebd00d xen/include/asm-x86/apic.h
--- a/xen/include/asm-x86/apic.h        Wed May 11 12:58:04 2011 +0100
+++ b/xen/include/asm-x86/apic.h        Fri May 13 13:45:05 2011 +0100
@@ -182,6 +182,7 @@
 extern void connect_bsp_APIC (void);
 extern void disconnect_bsp_APIC (int virt_wire_setup);
 extern void disable_local_APIC (void);
+extern void crash_disable_local_APIC (void);
 extern int verify_local_APIC (void);
 extern void cache_APIC_registers (void);
 extern void sync_Arb_IDs (void);
diff -r 0c446850d85e -r efa733ebd00d xen/include/asm-x86/hpet.h
--- a/xen/include/asm-x86/hpet.h        Wed May 11 12:58:04 2011 +0100
+++ b/xen/include/asm-x86/hpet.h        Fri May 13 13:45:05 2011 +0100
@@ -73,5 +73,6 @@
 void hpet_broadcast_exit(void);
 int hpet_broadcast_is_available(void);
 void hpet_disable_legacy_broadcast(void);
+void crash_hpet_disable_legacy_broadcast(void);
 
 #endif /* __X86_HPET_H__ */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.