xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] kexec: disable iommu and x2apic before jumping into the kdump kernel
@ 2011-05-13 12:47 Andrew Cooper
  2011-05-13 14:22 ` Jan Beulich
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cooper @ 2011-05-13 12:47 UTC (permalink / raw)
  To: xen-devel; +Cc: Andrew Cooper

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@citrix.com>

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__ */

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2011-05-13 14:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-13 12:47 [PATCH] kexec: disable iommu and x2apic before jumping into the kdump kernel Andrew Cooper
2011-05-13 14:22 ` Jan Beulich
2011-05-13 14:26   ` Ian Campbell
2011-05-13 14:32   ` Andrew Cooper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).