#include <xen/sched.h>
#include <xen/console.h>
#include <xen/smp.h>
+#include <xen/keyhandler.h>
#include <asm/current.h>
#include <asm/mc146818rtc.h>
#include <asm/msr.h>
#include <asm/mpspec.h>
#include <asm/debugger.h>
#include <asm/div64.h>
+#include <asm/apic.h>
unsigned int nmi_watchdog = NMI_NONE;
static spinlock_t watchdog_lock = SPIN_LOCK_UNLOCKED;
write_watchdog_counter(NULL);
}
}
+
+/*
+ * For some reason the destination shorthand for self is not valid
+ * when used with the NMI delivery mode. This is documented in Tables
+ * 8-3 and 8-4 in IA32 Reference Manual Volume 3. We send the IPI to
+ * our own APIC ID explicitly which is valid.
+ */
+static void do_nmi_trigger(unsigned char key) {
+ u32 id = apic_read(APIC_ID);
+
+ printk("triggering NMI on APIC ID %x\n", id);
+
+ apic_wait_icr_idle();
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(id));
+ apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_INT_ASSERT);
+}
+
+static __init int register_nmi_trigger(void)
+{
+ register_keyhandler('n', do_nmi_trigger, "trigger an NMI");
+ return 0;
+}
+__initcall(register_nmi_trigger);
bit. */
}
+void do_nmi_stats(unsigned char key)
+{
+ int i;
+ struct domain *d;
+ struct vcpu *v;
+ printk("CPU\tNMI\n");
+ for_each_cpu(i)
+ printk("%3d\t%3d\n", i, nmi_count(i));
+
+ if ((d = dom0) == NULL)
+ return;
+ if ((v = d->vcpu[0]) == NULL)
+ return;
+ if (v->vcpu_flags & (VCPUF_nmi_pending|VCPUF_nmi_masked))
+ printk("dom0 vpu0: NMI %s%s\n",
+ v->vcpu_flags & VCPUF_nmi_pending ? "pending " : "",
+ v->vcpu_flags & VCPUF_nmi_masked ? "masked " : "");
+ else
+ printk("dom0 vcpu0: NMI neither pending nor masked\n");
+}
+
#ifndef NDEBUG
void debugtrace_key(unsigned char key)
{
'r', dump_runq, "dump run queues");
register_irq_keyhandler(
'R', halt_machine, "reboot machine");
+ register_keyhandler('N', do_nmi_stats, "NMI statistics");
#ifndef NDEBUG
register_keyhandler(