WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] x86: allow NMI injection

To: <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] x86: allow NMI injection
From: "Jan Beulich" <jbeulich@xxxxxxxxxx>
Date: Wed, 28 Feb 2007 11:39:31 +0000
Delivery-date: Wed, 28 Feb 2007 03:38:01 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
NetWare's internal debugger needs the ability to send NMI IPIs, and
there is no reason to not allow domUs or dom0's vCPUs other than vCPU 0
to handle NMIs (they just will never see hardware generated ones).

While currently not having a frontend, the added hypercall also allows
for being used to inject NMIs into foreign VMs.

Along the lines, this fixes a potential race condition caused by
previously accessing the VCPU flags field non-atomically in entry.S.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>

Index: 2007-02-27/xen/arch/x86/physdev.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/physdev.c      2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/arch/x86/physdev.c   2007-02-28 12:14:58.000000000 +0100
@@ -143,6 +143,57 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
         break;
     }
 
+    case PHYSDEVOP_send_nmi: {
+        struct physdev_send_nmi send_nmi;
+        struct domain *d;
+
+        ret = -EFAULT;
+        if ( copy_from_guest(&send_nmi, arg, 1) != 0 )
+            break;
+
+        ret = -EPERM;
+        if ( send_nmi.domain == DOMID_SELF )
+            d = current->domain;
+        else if ( !IS_PRIV(current->domain) )
+            break;
+        else
+            d = get_domain_by_id(send_nmi.domain);
+        ret = -ESRCH;
+        if ( d == NULL )
+            break;
+
+        switch ( send_nmi.vcpu )
+        {
+            struct vcpu *v;
+
+        case XEN_SEND_NMI_ALL:
+        case XEN_SEND_NMI_ALL_BUT_SELF:
+            for_each_vcpu(d, v)
+            {
+                if ( (send_nmi.vcpu == XEN_SEND_NMI_ALL || v != current) &&
+                     !test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) )
+                    vcpu_kick(v);
+            }
+            ret = 0;
+            break;
+        case 0 ... MAX_VIRT_CPUS - 1:
+            if ( (v = d->vcpu[send_nmi.vcpu]) != NULL )
+            {
+                if ( !test_and_set_bit(_VCPUF_nmi_pending, &v->vcpu_flags) )
+                    vcpu_kick(v);
+                ret = 0;
+            }
+            break;
+        default:
+            ret = EINVAL;
+            break;
+        }
+
+        if ( send_nmi.domain != DOMID_SELF )
+            put_domain(d);
+        break;
+    }
+
     default:
         ret = -ENOSYS;
         break;
Index: 2007-02-27/xen/arch/x86/traps.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/traps.c        2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/arch/x86/traps.c     2007-02-28 12:08:44.000000000 +0100
@@ -2123,6 +2123,12 @@ long do_set_trap_table(XEN_GUEST_HANDLE(
         if ( cur.address == 0 )
             break;
 
+        if ( cur.vector == 2 && !TI_GET_IF(&cur) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
         fixup_guest_code_selector(current->domain, cur.cs);
 
         memcpy(&dst[cur.vector], &cur, sizeof(cur));
Index: 2007-02-27/xen/arch/x86/x86_32/asm-offsets.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_32/asm-offsets.c   2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/arch/x86/x86_32/asm-offsets.c        2007-02-28 
12:08:44.000000000 +0100
@@ -68,6 +68,7 @@ void __dummy__(void)
     OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt);
     OFFSET(VCPU_flags, struct vcpu, vcpu_flags);
     OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr);
+    OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs);
     DEFINE(_VCPUF_nmi_pending, _VCPUF_nmi_pending);
     DEFINE(_VCPUF_nmi_masked, _VCPUF_nmi_masked);
     DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);
Index: 2007-02-27/xen/arch/x86/x86_32/entry.S
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_32/entry.S 2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/arch/x86/x86_32/entry.S      2007-02-28 12:08:44.000000000 
+0100
@@ -232,7 +232,7 @@ test_all_events:
         shl  $IRQSTAT_shift,%eax
         test %ecx,irq_stat(%eax,1)
         jnz  process_softirqs
-        btr  $_VCPUF_nmi_pending,VCPU_flags(%ebx)
+        lock btrl $_VCPUF_nmi_pending,VCPU_flags(%ebx)
         jc   process_nmi
 test_guest_events:
         movl VCPU_vcpu_info(%ebx),%eax
@@ -259,19 +259,20 @@ process_softirqs:
 
         ALIGN
 process_nmi:
-        movl VCPU_nmi_addr(%ebx),%eax
+        movzwl VCPU_nmi_cs(%ebx),%eax
+        movl VCPU_nmi_addr(%ebx),%ecx
         test %eax,%eax
         jz   test_all_events
-        bts  $_VCPUF_nmi_masked,VCPU_flags(%ebx)
+        lock btsl $_VCPUF_nmi_masked,VCPU_flags(%ebx)
         jc   1f
         sti
         leal VCPU_trap_bounce(%ebx),%edx
-        movl %eax,TRAPBOUNCE_eip(%edx)
-        movw $FLAT_KERNEL_CS,TRAPBOUNCE_cs(%edx)
+        movl %ecx,TRAPBOUNCE_eip(%edx)
+        movw %ax,TRAPBOUNCE_cs(%edx)
         movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx)
         call create_bounce_frame
         jmp  test_all_events
-1:      bts  $_VCPUF_nmi_pending,VCPU_flags(%ebx)
+1:      lock btsl $_VCPUF_nmi_pending,VCPU_flags(%ebx)
         jmp  test_guest_events
 
 bad_hypercall:
Index: 2007-02-27/xen/arch/x86/x86_64/asm-offsets.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_64/asm-offsets.c   2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/arch/x86/x86_64/asm-offsets.c        2007-02-28 
12:08:44.000000000 +0100
@@ -76,6 +76,7 @@ void __dummy__(void)
     OFFSET(VCPU_arch_guest_fpu_ctxt, struct vcpu, arch.guest_context.fpu_ctxt);
     OFFSET(VCPU_flags, struct vcpu, vcpu_flags);
     OFFSET(VCPU_nmi_addr, struct vcpu, nmi_addr);
+    OFFSET(VCPU_nmi_cs, struct vcpu, arch.guest_context.trap_ctxt[2].cs);
     DEFINE(_VCPUF_nmi_pending, _VCPUF_nmi_pending);
     DEFINE(_VCPUF_nmi_masked, _VCPUF_nmi_masked);
     DEFINE(_VGCF_failsafe_disables_events, _VGCF_failsafe_disables_events);
Index: 2007-02-27/xen/arch/x86/x86_64/compat/entry.S
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_64/compat/entry.S  2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/arch/x86/x86_64/compat/entry.S       2007-02-28 
12:08:44.000000000 +0100
@@ -87,7 +87,7 @@ ENTRY(compat_test_all_events)
         leaq  irq_stat(%rip),%rcx
         testl $~0,(%rcx,%rax,1)
         jnz   compat_process_softirqs
-        btrq  $_VCPUF_nmi_pending,VCPU_flags(%rbx)
+        lock btrl $_VCPUF_nmi_pending,VCPU_flags(%rbx)
         jc    compat_process_nmi
 compat_test_guest_events:
         movq  VCPU_vcpu_info(%rbx),%rax
@@ -101,7 +101,7 @@ compat_test_guest_events:
         movl  VCPU_event_addr(%rbx),%eax
         movl  %eax,TRAPBOUNCE_eip(%rdx)
         movl  VCPU_event_sel(%rbx),%eax
-        movl  %eax,TRAPBOUNCE_cs(%rdx)
+        movw  %ax,TRAPBOUNCE_cs(%rdx)
         movw  $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
         call  compat_create_bounce_frame
         jmp   compat_test_all_events
@@ -116,20 +116,21 @@ compat_process_softirqs:
        ALIGN
 /* %rbx: struct vcpu */
 compat_process_nmi:
-        movl  VCPU_nmi_addr(%rbx),%eax
+        movzwl VCPU_nmi_cs(%rbx),%eax
+        movl  VCPU_nmi_addr(%rbx),%ecx
         testl %eax,%eax
         jz    compat_test_all_events
-        btsq  $_VCPUF_nmi_masked,VCPU_flags(%rbx)
+        lock btsl $_VCPUF_nmi_masked,VCPU_flags(%rbx)
         jc    1f
         sti
         leaq  VCPU_trap_bounce(%rbx),%rdx
-        movl  %eax,TRAPBOUNCE_eip(%rdx)
-        movl  $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx)
+        movl  %ecx,TRAPBOUNCE_eip(%rdx)
+        movw  %ax,TRAPBOUNCE_cs(%rdx)
         movw  $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
         call  compat_create_bounce_frame
         jmp   compat_test_all_events
 1:
-        btsq  $_VCPUF_nmi_pending,VCPU_flags(%rbx)
+        lock btsl $_VCPUF_nmi_pending,VCPU_flags(%rbx)
         jmp   compat_test_guest_events
 
 compat_bad_hypercall:
@@ -164,7 +165,7 @@ compat_failsafe_callback:
         movl  VCPU_failsafe_addr(%rbx),%eax
         movl  %eax,TRAPBOUNCE_eip(%rdx)
         movl  VCPU_failsafe_sel(%rbx),%eax
-        movl  %eax,TRAPBOUNCE_cs(%rdx)
+        movw  %ax,TRAPBOUNCE_cs(%rdx)
         movw  $TBF_FAILSAFE,TRAPBOUNCE_flags(%rdx)
         btq   $_VGCF_failsafe_disables_events,VCPU_guest_context_flags(%rbx)
         jnc   1f
Index: 2007-02-27/xen/arch/x86/x86_64/compat/traps.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_64/compat/traps.c  2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/arch/x86/x86_64/compat/traps.c       2007-02-28 
12:08:44.000000000 +0100
@@ -287,6 +287,12 @@ int compat_set_trap_table(XEN_GUEST_HAND
         if ( cur.address == 0 )
             break;
 
+        if ( cur.vector == 2 && !TI_GET_IF(&cur) )
+        {
+            rc = -EINVAL;
+            break;
+        }
+
         fixup_guest_code_selector(current->domain, cur.cs);
 
         XLAT_trap_info(dst + cur.vector, &cur);
Index: 2007-02-27/xen/arch/x86/x86_64/entry.S
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_64/entry.S 2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/arch/x86/x86_64/entry.S      2007-02-28 12:08:44.000000000 
+0100
@@ -177,7 +177,7 @@ test_all_events:
         leaq  irq_stat(%rip),%rcx
         testl $~0,(%rcx,%rax,1)
         jnz   process_softirqs
-        btr   $_VCPUF_nmi_pending,VCPU_flags(%rbx)
+        lock btrl $_VCPUF_nmi_pending,VCPU_flags(%rbx)
         jc    process_nmi
 test_guest_events:
         movq  VCPU_vcpu_info(%rbx),%rax
@@ -207,7 +207,7 @@ process_nmi:
         movq VCPU_nmi_addr(%rbx),%rax
         test %rax,%rax
         jz   test_all_events
-        bts  $_VCPUF_nmi_masked,VCPU_flags(%rbx)
+        lock btsl $_VCPUF_nmi_masked,VCPU_flags(%rbx)
         jc   1f
         sti
         leaq VCPU_trap_bounce(%rbx),%rdx
@@ -215,7 +215,7 @@ process_nmi:
         movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
         call create_bounce_frame
         jmp  test_all_events
-1:      bts  $_VCPUF_nmi_pending,VCPU_flags(%rbx)
+1:      lock btsl $_VCPUF_nmi_pending,VCPU_flags(%rbx)
         jmp  test_guest_events
 
 bad_hypercall:
Index: 2007-02-27/xen/arch/x86/x86_64/physdev.c
===================================================================
--- 2007-02-27.orig/xen/arch/x86/x86_64/physdev.c       2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/arch/x86/x86_64/physdev.c    2007-02-28 12:08:44.000000000 
+0100
@@ -30,6 +30,10 @@
 #define physdev_irq_status_query   compat_physdev_irq_status_query
 #define physdev_irq_status_query_t physdev_irq_status_query_compat_t
 
+#define xen_physdev_send_nmi       physdev_send_nmi
+CHECK_physdev_send_nmi;
+#undef xen_physdev_send_nmi
+
 #define COMPAT
 #undef guest_handle_okay
 #define guest_handle_okay          compat_handle_okay
Index: 2007-02-27/xen/common/kernel.c
===================================================================
--- 2007-02-27.orig/xen/common/kernel.c 2007-02-28 12:14:26.000000000 +0100
+++ 2007-02-27/xen/common/kernel.c      2007-02-28 12:08:44.000000000 +0100
@@ -246,16 +246,20 @@ long register_guest_nmi_callback(unsigne
     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
+    v->arch.guest_context.trap_ctxt[2].vector = 2;
+    v->arch.guest_context.trap_ctxt[2].flags = 0;
+    TI_SET_IF(v->arch.guest_context.trap_ctxt + 2, 1);
+    v->arch.guest_context.trap_ctxt[2].cs =
+        !IS_COMPAT(d) ? FLAT_KERNEL_CS : FLAT_COMPAT_KERNEL_CS;
+
     /*
      * If no handler was registered we can 'lose the NMI edge'. Re-assert it
      * now.
      */
-    if ( arch_get_nmi_reason(d) != 0 )
+    if ( d->domain_id == 0 && v->vcpu_id == 0 &&
+         arch_get_nmi_reason(d) != 0 )
         set_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
 #endif
 
@@ -266,6 +270,11 @@ long unregister_guest_nmi_callback(void)
 {
     struct vcpu *v = current;
 
+#ifdef CONFIG_X86
+    v->arch.guest_context.trap_ctxt[2].cs = 0;
+    v->arch.guest_context.trap_ctxt[2].vector = 0;
+    v->arch.guest_context.trap_ctxt[2].flags = 0;
+#endif
     v->nmi_addr = 0;
 
     return 0;
Index: 2007-02-27/xen/include/public/physdev.h
===================================================================
--- 2007-02-27.orig/xen/include/public/physdev.h        2007-02-28 
12:14:26.000000000 +0100
+++ 2007-02-27/xen/include/public/physdev.h     2007-02-28 12:08:44.000000000 
+0100
@@ -119,6 +119,22 @@ typedef struct physdev_irq physdev_irq_t
 DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
 
 /*
+ * Allocate or free a physical upcall vector for the specified IRQ line.
+ * @arg == pointer to physdev_irq structure.
+ */
+#define PHYSDEVOP_send_nmi              13
+struct physdev_send_nmi {
+    /* IN */
+    domid_t domain;
+    uint32_t vcpu;
+};
+typedef struct physdev_send_nmi physdev_send_nmi_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_send_nmi_t);
+
+#define XEN_SEND_NMI_ALL          (~(uint32_t)0)
+#define XEN_SEND_NMI_ALL_BUT_SELF (~(uint32_t)1)
+
+/*
  * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
  * hypercall since 0x00030202.
  */
Index: 2007-02-27/xen/include/xen/sched.h
===================================================================
--- 2007-02-27.orig/xen/include/xen/sched.h     2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/include/xen/sched.h  2007-02-28 12:08:44.000000000 +0100
@@ -108,7 +108,11 @@ struct vcpu 
     /* Bitmask of CPUs on which this VCPU may run. */
     cpumask_t        cpu_affinity;
 
+#ifndef CONFIG_X86
     unsigned long    nmi_addr;      /* NMI callback address. */
+#else
+# define nmi_addr arch.guest_context.trap_ctxt[2].address
+#endif
 
     /* Bitmask of CPUs which are holding onto this VCPU's state. */
     cpumask_t        vcpu_dirty_cpumask;
Index: 2007-02-27/xen/include/xlat.lst
===================================================================
--- 2007-02-27.orig/xen/include/xlat.lst        2007-02-28 12:14:26.000000000 
+0100
+++ 2007-02-27/xen/include/xlat.lst     2007-02-28 12:08:44.000000000 +0100
@@ -36,6 +36,7 @@
 !      memory_map                      memory.h
 !      memory_reservation              memory.h
 !      translate_gpfn_list             memory.h
+?      physdev_send_nmi                physdev.h
 !      sched_poll                      sched.h
 ?      sched_remote_shutdown           sched.h
 ?      sched_shutdown                  sched.h



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>