Pass NMIs to DOM0 via a dedicated callback, Xen/Linux i386 support.
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Wed, 11 Jan 2006 15:52:54 +0000 (15:52 +0000)
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Wed, 11 Jan 2006 15:52:54 +0000 (15:52 +0000)
Register our NMI handler with Xen. Use a pseudo-flag in EFLAGS in
indicate that we should return from the NMI via a hypervisor iret.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
linux-2.6-xen-sparse/arch/xen/i386/kernel/entry.S
linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h
linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_traps.h [new file with mode: 0644]
linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_post.h

index 6522f7a249a52130f42d91961b26ba17562d2bfb..9c50c32426730086c860c0cfb1d5c6423044cb40 100644 (file)
@@ -76,7 +76,9 @@ IF_MASK               = 0x00000200
 DF_MASK                = 0x00000400 
 NT_MASK                = 0x00004000
 VM_MASK                = 0x00020000
-
+/* pseudo-eflags */
+NMI_MASK       = 0x80000000
+       
 /* Offsets into shared_info_t. */
 #define evtchn_upcall_pending          /* 0 */
 #define evtchn_upcall_mask             1
@@ -305,8 +307,8 @@ restore_all:
        je ldt_ss                       # returning to user-space with LDT SS
 #endif /* XEN */
 restore_nocheck:
-       testl $VM_MASK, EFLAGS(%esp)
-       jnz resume_vm86
+       testl $(VM_MASK|NMI_MASK), EFLAGS(%esp)
+       jnz hypervisor_iret
        movb EVENT_MASK(%esp), %al
        notb %al                        # %al == ~saved_mask
        XEN_GET_VCPU_INFO(%esi)
@@ -328,11 +330,11 @@ iret_exc:
        .long 1b,iret_exc
 .previous
 
-resume_vm86:
-       XEN_UNBLOCK_EVENTS(%esi)
+hypervisor_iret:
+       andl $~NMI_MASK, EFLAGS(%esp)
        RESTORE_REGS
        movl %eax,(%esp)
-       movl $__HYPERVISOR_switch_vm86,%eax
+       movl $__HYPERVISOR_iret,%eax
        int $0x82
        ud2
 
@@ -691,6 +693,15 @@ debug_stack_correct:
        call do_debug
        jmp ret_from_exception
 
+ENTRY(nmi)
+       pushl %eax
+       SAVE_ALL
+       xorl %edx,%edx          # zero error code
+       movl %esp,%eax          # pt_regs pointer
+       call do_nmi
+       orl  $NMI_MASK, EFLAGS(%esp)
+       jmp restore_all
+
 #if 0 /* XEN */
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
index 6fc4203116c8061702401b17c23bd014ab63f43e..04edbd3741507d8125e35029484f5a38767c29d3 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <asm-xen/xen-public/xen.h>
 #include <asm-xen/xen-public/sched.h>
+#include <asm-xen/xen-public/nmi.h>
 
 #define _hypercall0(type, name)                        \
 ({                                             \
@@ -300,6 +301,14 @@ HYPERVISOR_suspend(
                           SHUTDOWN_suspend, srec);
 }
 
+static inline int
+HYPERVISOR_nmi_op(
+       unsigned long op,
+       unsigned long arg)
+{
+       return _hypercall2(int, nmi_op, op, arg);
+}
+
 #endif /* __HYPERCALL_H__ */
 
 /*
diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_traps.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/mach-xen/mach_traps.h
new file mode 100644 (file)
index 0000000..14c6079
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ *  include/asm-xen/asm-i386/mach-xen/mach_traps.h
+ *
+ *  Machine specific NMI handling for Xen
+ */
+#ifndef _MACH_TRAPS_H
+#define _MACH_TRAPS_H
+
+#include <linux/bitops.h>
+#include <asm-xen/xen-public/nmi.h>
+
+static inline void clear_mem_error(unsigned char reason) {}
+static inline void clear_io_check_error(unsigned char reason) {}
+
+static inline unsigned char get_nmi_reason(void)
+{
+       shared_info_t *s = HYPERVISOR_shared_info;
+       unsigned char reason = 0;
+
+       /* construct a value which looks like it came from
+        * port 0x61.
+        */
+       if (test_bit(_XEN_NMIREASON_io_error, &s->arch.nmi_reason))
+               reason |= 0x40;
+       if (test_bit(_XEN_NMIREASON_parity_error, &s->arch.nmi_reason))
+               reason |= 0x80;
+
+        return reason;
+}
+
+static inline void reassert_nmi(void) {}
+
+#endif /* !_MACH_TRAPS_H */
index b30853d2cf5024bac98ed2e4e8ecdfcd44dc16a3..fa7d6191b13d9d82546a98516f711d57b1b6a0aa 100644 (file)
@@ -29,6 +29,7 @@ void __init machine_specific_modify_cpu_capabilities(struct cpuinfo_x86 *c)
 
 extern void hypervisor_callback(void);
 extern void failsafe_callback(void);
+extern void nmi(void);
 
 static void __init machine_specific_arch_setup(void)
 {
@@ -36,5 +37,7 @@ static void __init machine_specific_arch_setup(void)
            __KERNEL_CS, (unsigned long)hypervisor_callback,
            __KERNEL_CS, (unsigned long)failsafe_callback);
 
+       HYPERVISOR_nmi_op(XENNMI_register_callback, (unsigned long)&nmi);
+
        machine_specific_modify_cpu_capabilities(&boot_cpu_data);
 }