x86: Allow NMI callback CS to be specified via set_trap_table()
authorKeir Fraser <keir@xensource.com>
Mon, 22 Oct 2007 12:04:32 +0000 (13:04 +0100)
committerKeir Fraser <keir@xensource.com>
Mon, 22 Oct 2007 12:04:32 +0000 (13:04 +0100)
hypercall.
Based on a patch by Jan Beulich.
Signed-off-by: Keir Fraser <keir@xensource.com>
12 files changed:
xen/arch/x86/traps.c
xen/arch/x86/x86_32/asm-offsets.c
xen/arch/x86/x86_32/entry.S
xen/arch/x86/x86_64/asm-offsets.c
xen/arch/x86/x86_64/compat/entry.S
xen/arch/x86/x86_64/compat/traps.c
xen/common/kernel.c
xen/include/asm-ia64/linux-null/asm/nmi.h
xen/include/asm-powerpc/nmi.h
xen/include/asm-x86/nmi.h
xen/include/xen/nmi.h
xen/include/xen/sched.h

index 6d085784e29b8bf4dde2c10754d5fd0a69167fab..8ccbeee2c6761b333b3083e636060abddf23a471 100644 (file)
@@ -2229,6 +2229,37 @@ void __init trap_init(void)
     open_softirq(NMI_SOFTIRQ, nmi_softirq);
 }
 
+long register_guest_nmi_callback(unsigned long address)
+{
+    struct vcpu *v = current;
+    struct domain *d = current->domain;
+    struct trap_info *t = &v->arch.guest_context.trap_ctxt[TRAP_nmi];
+
+    t->vector  = TRAP_nmi;
+    t->flags   = 0;
+    t->cs      = !IS_COMPAT(d) ? FLAT_KERNEL_CS : FLAT_COMPAT_KERNEL_CS;
+    t->address = address;
+    TI_SET_IF(t, 1);
+
+    /*
+     * If no handler was registered we can 'lose the NMI edge'. Re-assert it
+     * now.
+     */
+    if ( (v->vcpu_id == 0) && (arch_get_nmi_reason(d) != 0) )
+        v->nmi_pending = 1;
+
+    return 0;
+}
+
+long unregister_guest_nmi_callback(void)
+{
+    struct vcpu *v = current;
+    struct trap_info *t = &v->arch.guest_context.trap_ctxt[TRAP_nmi];
+
+    memset(t, 0, sizeof(*t));
+
+    return 0;
+}
 
 long do_set_trap_table(XEN_GUEST_HANDLE(trap_info_t) traps)
 {
@@ -2262,6 +2293,12 @@ long do_set_trap_table(XEN_GUEST_HANDLE(trap_info_t) traps)
         if ( cur.address == 0 )
             break;
 
+        if ( (cur.vector == TRAP_nmi) && !TI_GET_IF(&cur) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
         fixup_guest_code_selector(current->domain, cur.cs);
 
         memcpy(&dst[cur.vector], &cur, sizeof(cur));
index 86e3682e0ada7a246ab5343abef335fa7df7c5db..bb59330fbf51b5c6ebce05da8dc4e3ec7921224e 100644 (file)
@@ -66,7 +66,10 @@ void __dummy__(void)
            arch.guest_context.kernel_sp);
     OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags);
     OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt);
-    OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr);
+    OFFSET(VCPU_nmi_cs, struct vcpu,
+           arch.guest_context.trap_ctxt[TRAP_nmi].cs);
+    OFFSET(VCPU_nmi_addr, struct vcpu,
+           arch.guest_context.trap_ctxt[TRAP_nmi].address);
     OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending);
     OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked);
     DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);
index 37ed92d6125aabceb41447b849ede9a4103d0b1b..bff00eb5c797359e249ee0ad133c6378c3f4f0e2 100644 (file)
@@ -257,13 +257,15 @@ process_nmi:
         testb $1,VCPU_nmi_masked(%ebx)
         jnz  test_guest_events
         movb $0,VCPU_nmi_pending(%ebx)
-        movl VCPU_nmi_addr(%ebx),%eax
+        movzwl VCPU_nmi_cs(%ebx),%eax
+        movl VCPU_nmi_addr(%ebx),%ecx
         test %eax,%eax
         jz   test_guest_events
         movb $1,VCPU_nmi_masked(%ebx)
         sti
         leal VCPU_trap_bounce(%ebx),%edx
-        movl %eax,TRAPBOUNCE_eip(%edx)
+        movw %ax,TRAPBOUNCE_cs(%edx)
+        movl %ecx,TRAPBOUNCE_eip(%edx)
         movw $FLAT_KERNEL_CS,TRAPBOUNCE_cs(%edx)
         movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx)
         call create_bounce_frame
index 120f0d0e3d71c0452328128c398fd5d4e955435f..365f227b8dc2d623baf670bb5e2614fa5e8524dd 100644 (file)
@@ -75,7 +75,10 @@ void __dummy__(void)
     OFFSET(VCPU_kernel_ss, struct vcpu, arch.guest_context.kernel_ss);
     OFFSET(VCPU_guest_context_flags, struct vcpu, arch.guest_context.flags);
     OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt);
-    OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr);
+    OFFSET(VCPU_nmi_cs, struct vcpu,
+           arch.guest_context.trap_ctxt[TRAP_nmi].cs);
+    OFFSET(VCPU_nmi_addr, struct vcpu,
+           arch.guest_context.trap_ctxt[TRAP_nmi].address);
     OFFSET(VCPU_nmi_pending, struct vcpu, nmi_pending);
     OFFSET(VCPU_nmi_masked, struct vcpu, nmi_masked);
     DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);
index 3504e2605881e467f9ffe5927559eb7f6258410a..b1e762bdd0efa5cb9609533cb09a70d72d9910a6 100644 (file)
@@ -131,13 +131,15 @@ compat_process_nmi:
         testb $1,VCPU_nmi_masked(%rbx)
         jnz   compat_test_guest_events
         movb  $0,VCPU_nmi_pending(%rbx)
-        movl  VCPU_nmi_addr(%rbx),%eax
+        movzwl VCPU_nmi_cs(%rbx),%eax
+        movl  VCPU_nmi_addr(%rbx),%ecx
         testl %eax,%eax
         jz    compat_test_guest_events
         movb  $1,VCPU_nmi_masked(%rbx)
         sti
         leaq  VCPU_trap_bounce(%rbx),%rdx
-        movl  %eax,TRAPBOUNCE_eip(%rdx)
+        movw  %ax,TRAPBOUNCE_cs(%rdx)
+        movl  %ecx,TRAPBOUNCE_eip(%rdx)
         movw  $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx)
         movb  $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
         call  compat_create_bounce_frame
index 4c6298dd5805069d84142d0e128171589fea7e1b..0c704b942a68b94a223fcd6c001352d11beb0d41 100644 (file)
@@ -294,6 +294,12 @@ int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps)
         if ( cur.address == 0 )
             break;
 
+        if ( (cur.vector == TRAP_nmi) && !TI_GET_IF(&cur) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
         fixup_guest_code_selector(current->domain, cur.cs);
 
         XLAT_trap_info(dst + cur.vector, &cur);
index 034ff211d35987bb3eadd235126d958074659168..1ce1720afc5d335d0c04ec2b5caf5d6af5b42dd4 100644 (file)
@@ -247,40 +247,6 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDLE(void) arg)
     return -ENOSYS;
 }
 
-#ifndef COMPAT
-
-long register_guest_nmi_callback(unsigned long address)
-{
-    struct vcpu *v = current;
-    struct domain *d = current->domain;
-
-    if ( (d->domain_id != 0) || (v->vcpu_id != 0) )
-        return -EINVAL;
-
-    v->nmi_addr = address;
-#ifdef CONFIG_X86
-    /*
-     * If no handler was registered we can 'lose the NMI edge'. Re-assert it
-     * now.
-     */
-    if ( arch_get_nmi_reason(d) != 0 )
-        v->nmi_pending = 1;
-#endif
-
-    return 0;
-}
-
-long unregister_guest_nmi_callback(void)
-{
-    struct vcpu *v = current;
-
-    v->nmi_addr = 0;
-
-    return 0;
-}
-
-#endif
-
 DO(nmi_op)(unsigned int cmd, XEN_GUEST_HANDLE(void) arg)
 {
     struct xennmi_callback cb;
index 29f4f4cd69fcb9a8d88795e7cdfc0b2493661f22..846325096835dca287b02398b50a6b59a485cd0f 100644 (file)
@@ -1 +1,7 @@
-/* This file is intentionally left empty. */
+#ifndef __IA64_NMI_H__
+#define __IA64_NMI_H__
+
+#define register_guest_nmi_callback(a)  (-ENOSYS)
+#define unregister_guest_nmi_callback() (-ENOSYS)
+
+#endif /* __IA64_NMI_H__ */
index 4618b4b1402b023cedc9d3a7e47835833d07d90f..edbc554e801245779521f6f5ed10fac9beeeaef2 100644 (file)
@@ -3,4 +3,7 @@
 
 #include <public/nmi.h>
 
+#define register_guest_nmi_callback(a)  (-ENOSYS)
+#define unregister_guest_nmi_callback() (-ENOSYS)
+
 #endif /* ASM_NMI_H */
index d79b823ee25990b7dad74eeefe4e8443453ea802..af1ff2e00865b58c9d66c1e263cd6d215229f444 100644 (file)
@@ -23,4 +23,19 @@ void set_nmi_callback(nmi_callback_t callback);
  */
 void unset_nmi_callback(void);
  
+/**
+ * register_guest_nmi_callback
+ *
+ * The default NMI handler passes the NMI to a guest callback. This
+ * function registers the address of that callback.
+ */
+long register_guest_nmi_callback(unsigned long address);
+
+/**
+ * unregister_guest_nmi_callback
+ *
+ * Unregister a guest NMI handler.
+ */
+long unregister_guest_nmi_callback(void);
+
 #endif /* ASM_NMI_H */
index a13e797273b22dd0ad86c48d8ab60797da91a499..e526b6ab6f41694740bd0f9f4efb8ff1aebfee8a 100644 (file)
 
 #include <asm/nmi.h>
 
-/**
- * register_guest_nmi_callback
- *
- * The default NMI handler passes the NMI to a guest callback. This
- * function registers the address of that callback.
- */
-extern long register_guest_nmi_callback(unsigned long address);
-
-/**
- * unregister_guest_nmi_callback
- *
- * Unregister a guest NMI handler.
- */
-extern long unregister_guest_nmi_callback(void);
-
 #endif /* __XEN_NMI_H__ */
index 67a203b96977c91a8f234b81094f315d243c95e4..85cdb6e9a50604c5753aba4b48a24ecafd6d23c2 100644 (file)
@@ -131,8 +131,6 @@ struct vcpu
     /* Bitmask of CPUs on which this VCPU may run. */
     cpumask_t        cpu_affinity;
 
-    unsigned long    nmi_addr;      /* NMI callback address. */
-
     /* Bitmask of CPUs which are holding onto this VCPU's state. */
     cpumask_t        vcpu_dirty_cpumask;