Re: [Xen-devel] [PATCH 3 of 3] kexec: disable iommu jumping into the kdu
On 18/05/11 19:49, Konrad Rzeszutek Wilk wrote:
purgatory is the bit of code which the a crashing kernel jumps into,
which pretends to do minimal bootloader things to book the kdump
kernel. It is part of the kexec-tools package.
On Wed, May 18, 2011 at 07:08:16PM +0100, Andrew Cooper wrote:
kdump kernels are unable to boot with IOMMU enabled,
this patch disabled IOMMU mode and removes some of the generic
code from the shutdown path which doesnt work after other
CPUs have been shot down.
Also, leave local interrupts disabled when jumping into pugatory
I was replacing __stop_this_cpu() with the safe subset of its contents -
it was a verbatim copy minus the SMP stuff which the regular
__stop_this_cpu() does. I suppose I could have split __stop_this_cpu()
to __crash_stop_this_cpu() but it didn't seem worth making such a
trivially small function.
as we have no idea whats in there and really dont want to be
servicing interrupts when our entire state is invalid.
Signed-off-by: Andrew Cooper<andrew.cooper3@xxxxxxxxxx>
diff -r e80b5280fe2f -r aaf44d1a903d xen/arch/x86/crash.c
--- a/xen/arch/x86/crash.c Wed May 18 19:00:13 2011 +0100
+++ b/xen/arch/x86/crash.c Wed May 18 19:00:13 2011 +0100
@@ -27,6 +27,8 @@
static atomic_t waiting_for_crash_ipi;
static unsigned int crashing_cpu;
@@ -43,7 +45,10 @@ static int crash_nmi_callback(struct cpu
+ asm volatile ( "fninit" );
Can you provide a comment why you are using fninit and clt?
Is this what the Linux kernel does too when it goes through the kexec path?
Because that local_irq_enable() results in the interrupt flag being set
when jumping into purgatory, which (at the moment) doesn't touch
interrupts at all. The result is that interrupts from PCI devices which
are unaware of the crash are (potentially) being serviced by the xen
handlers even though we have left the Xen context for good.
@@ -56,6 +61,7 @@ static int crash_nmi_callback(struct cpu
static void nmi_shootdown_cpus(void)
unsigned long msecs;
+ u64 msr_contents;
@@ -77,18 +83,43 @@ static void nmi_shootdown_cpus(void)
+ asm volatile ( "fninit" );
+ /* This is a bit of a hack but there is no other way to shutdown correctly
+ * without a significant refactoring of the APIC code */
+ rdmsrl(MSR_IA32_APICBASE, msr_contents);
+ if ( cpu_has(¤t_cpu_data, X86_FEATURE_X2APIC)
+&& (msr_contents& MSR_IA32_APICBASE_EXTD) )
+ x2apic_enabled = 1;
+ x2apic_enabled = 0;
True - at the moment both intel and amd iommu_ops are fully implemented
but I will add an extra condition to the if statement.
+ const struct iommu_ops * ops;
+ /* Yes i know this is hacky but it is the easiest solution. I should add
+ * function called crash() or so which just disables the iommu 'fun'
without saving state
+ ops = iommu_get_ops();
Uh, no checking if ops->suspend exists?
It worked on the AMD box I tested the code on. Like the comment says -
as far as I can tell, it is architecture independent code.
+ /* Yes i know this is from driver/passthrough/vtd/ but it appears to be
+ * independant, and also bears little/no relation to x2apic. Needs
What about AMD VI IOMMUs? Does it work when that IOMMU is used?
There is a comment in iommu suspend stating that it cant and isn't done,
but rather is left for the local/ioapic_suspend functions which dont
properly work in the kexec path.
Can't that function be done in the suspend code of the IOMMU?
info = kexec_crash_save_info();
info->xen_phys_start = xen_phys_start;
diff -r e80b5280fe2f -r aaf44d1a903d xen/arch/x86/hpet.c
--- a/xen/arch/x86/hpet.c Wed May 18 19:00:13 2011 +0100
+++ b/xen/arch/x86/hpet.c Wed May 18 19:00:13 2011 +0100
@@ -670,6 +670,33 @@ void hpet_disable_legacy_broadcast(void)
+/* This function is similar to the regular
+ * hpet_disable_legacy_broadcast function, except it is called
+ * on the crash path with only the current processor up, so we
+ * can forget the locks and really cant send an event check IPI
+ * to the other processors */
+ u32 cfg;
+ if ( !hpet_events || !(hpet_events->flags& HPET_EVT_LEGACY) )
+ 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);
unsigned int cpu = smp_processor_id();
diff -r e80b5280fe2f -r aaf44d1a903d xen/arch/x86/machine_kexec.c
--- a/xen/arch/x86/machine_kexec.c Wed May 18 19:00:13 2011 +0100
+++ b/xen/arch/x86/machine_kexec.c Wed May 18 19:00:13 2011 +0100
@@ -97,7 +97,7 @@ void machine_kexec(xen_kexec_image_t *im
if ( hpet_broadcast_is_available() )
* compat_machine_kexec() returns to idle pagetables, which requires us
diff -r e80b5280fe2f -r aaf44d1a903d xen/include/asm-x86/hpet.h
--- a/xen/include/asm-x86/hpet.h Wed May 18 19:00:13 2011 +0100
+++ b/xen/include/asm-x86/hpet.h Wed May 18 19:00:13 2011 +0100
@@ -73,5 +73,6 @@ void hpet_broadcast_enter(void);
#endif /* __X86_HPET_H__ */
Xen-devel mailing list
Andrew Cooper - Dom0 Kernel Engineer, Citrix XenServer
T: +44 (0)1223 225 900, http://www.citrix.com
Xen-devel mailing list