[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] hvm vmx: Support 'virtual NMI' feature of VMX.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1183484760 -3600
# Node ID e6d5e4709466b66146d2538574df9704ecb9a5e1
# Parent  9fa9346e1c700d0ea81a99318c564c4b9bccaa8a
hvm vmx: Support 'virtual NMI' feature of VMX.
Signed-off-by: Haitao Shan <haitao.shan@xxxxxxxxx>
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>
Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/vmx/intr.c        |   65 ++++++++++++++++++++++++++-----------
 xen/arch/x86/hvm/vmx/vmcs.c        |    2 -
 xen/arch/x86/hvm/vmx/vmx.c         |   21 +++++++++--
 xen/include/asm-x86/hvm/vmx/vmcs.h |    2 +
 xen/include/asm-x86/hvm/vmx/vmx.h  |    2 +
 5 files changed, 69 insertions(+), 23 deletions(-)

diff -r 9fa9346e1c70 -r e6d5e4709466 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c       Tue Jul 03 17:22:17 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/intr.c       Tue Jul 03 18:46:00 2007 +0100
@@ -71,13 +71,38 @@
  * the effect is cleared. (i.e., MOV-SS-blocking 'dominates' STI-blocking).
  */
 
-static void enable_irq_window(struct vcpu *v)
-{
-    u32  *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
-    
-    if ( !(*cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING) )
-    {
-        *cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+static void enable_intr_window(struct vcpu *v, enum hvm_intack intr_source)
+{
+    u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
+    u32 ctl = CPU_BASED_VIRTUAL_INTR_PENDING;
+
+    if ( unlikely(intr_source == hvm_intack_none) )
+        return;
+
+    if ( unlikely(intr_source == hvm_intack_nmi) && cpu_has_vmx_vnmi )
+    {
+        /*
+         * We set MOV-SS blocking in lieu of STI blocking when delivering an
+         * NMI. This is because it is processor-specific whether STI-blocking
+         * blocks NMIs. Hence we *must* check for STI-blocking on NMI delivery
+         * (otherwise vmentry will fail on processors that check for STI-
+         * blocking) but if the processor does not check for STI-blocking then
+         * we may immediately vmexit and hance make no progress!
+         * (see SDM 3B 21.3, "Other Causes of VM Exits").
+         */
+        u32 intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
+        if ( intr_shadow & VMX_INTR_SHADOW_STI )
+        {
+            /* Having both STI-blocking and MOV-SS-blocking fails vmentry. */
+            intr_shadow &= ~VMX_INTR_SHADOW_STI;
+            intr_shadow |= VMX_INTR_SHADOW_MOV_SS;
+        }
+        ctl = CPU_BASED_VIRTUAL_NMI_PENDING;
+    }
+
+    if ( !(*cpu_exec_control & ctl) )
+    {
+        *cpu_exec_control |= ctl;
         __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
     }
 }
@@ -120,8 +145,7 @@ asmlinkage void vmx_intr_assist(void)
         if ( unlikely(v->arch.hvm_vmx.vector_injected) )
         {
             v->arch.hvm_vmx.vector_injected = 0;
-            if ( unlikely(intr_source != hvm_intack_none) )
-                enable_irq_window(v);
+            enable_intr_window(v, intr_source);
             return;
         }
 
@@ -129,7 +153,9 @@ asmlinkage void vmx_intr_assist(void)
         idtv_info_field = __vmread(IDT_VECTORING_INFO_FIELD);
         if ( unlikely(idtv_info_field & INTR_INFO_VALID_MASK) )
         {
-            __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+            /* See SDM 3B 25.7.1.1 and .2 for info about masking resvd bits. */
+            __vmwrite(VM_ENTRY_INTR_INFO_FIELD,
+                      idtv_info_field & ~INTR_INFO_RESVD_BITS_MASK);
 
             /*
              * Safe: the length will only be interpreted for software
@@ -143,8 +169,16 @@ asmlinkage void vmx_intr_assist(void)
             if ( unlikely(idtv_info_field & 0x800) ) /* valid error code */
                 __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE,
                           __vmread(IDT_VECTORING_ERROR_CODE));
-            if ( unlikely(intr_source != hvm_intack_none) )
-                enable_irq_window(v);
+            enable_intr_window(v, intr_source);
+
+            /*
+             * Clear NMI-blocking interruptibility info if an NMI delivery
+             * faulted. Re-delivery will re-set it (see SDM 3B 25.7.1.2).
+             */
+            if ( (idtv_info_field&INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI )
+                __vmwrite(GUEST_INTERRUPTIBILITY_INFO,
+                          __vmread(GUEST_INTERRUPTIBILITY_INFO) &
+                          ~VMX_INTR_SHADOW_NMI);
 
             HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
             return;
@@ -153,14 +187,9 @@ asmlinkage void vmx_intr_assist(void)
         if ( likely(intr_source == hvm_intack_none) )
             return;
 
-        /*
-         * TODO: Better NMI handling. Shouldn't wait for EFLAGS.IF==1, but
-         * should wait for exit from 'NMI blocking' window (NMI injection to
-         * next IRET). This requires us to use the new 'virtual NMI' support.
-         */
         if ( !hvm_interrupts_enabled(v, intr_source) )
         {
-            enable_irq_window(v);
+            enable_intr_window(v, intr_source);
             return;
         }
     } while ( !hvm_vcpu_ack_pending_irq(v, intr_source, &intr_vector) );
diff -r 9fa9346e1c70 -r e6d5e4709466 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c       Tue Jul 03 17:22:17 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmcs.c       Tue Jul 03 18:46:00 2007 +0100
@@ -75,7 +75,7 @@ void vmx_init_vmcs_config(void)
 
     min = (PIN_BASED_EXT_INTR_MASK |
            PIN_BASED_NMI_EXITING);
-    opt = 0; /*PIN_BASED_VIRTUAL_NMIS*/
+    opt = PIN_BASED_VIRTUAL_NMIS;
     _vmx_pin_based_exec_control = adjust_vmx_controls(
         min, opt, MSR_IA32_VMX_PINBASED_CTLS);
 
diff -r 9fa9346e1c70 -r e6d5e4709466 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Tue Jul 03 17:22:17 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Tue Jul 03 18:46:00 2007 +0100
@@ -1106,15 +1106,17 @@ static int vmx_interrupts_enabled(struct
 
     ASSERT(v == current);
 
-    intr_shadow  = __vmread(GUEST_INTERRUPTIBILITY_INFO);
-    intr_shadow &= VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS;
+    intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
 
     if ( type == hvm_intack_nmi )
-        return !intr_shadow;
+        return !(intr_shadow & (VMX_INTR_SHADOW_STI|
+                                VMX_INTR_SHADOW_MOV_SS|
+                                VMX_INTR_SHADOW_NMI));
 
     ASSERT((type == hvm_intack_pic) || (type == hvm_intack_lapic));
     eflags = __vmread(GUEST_RFLAGS);
-    return !irq_masked(eflags) && !intr_shadow;
+    return (!irq_masked(eflags) &&
+            !(intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS)));
 }
 
 static void vmx_update_host_cr3(struct vcpu *v)
@@ -2911,6 +2913,17 @@ asmlinkage void vmx_vmexit_handler(struc
 
         vector = intr_info & INTR_INFO_VECTOR_MASK;
 
+        /*
+         * Re-set the NMI shadow if vmexit caused by a guest IRET fault (see 3B
+         * 25.7.1.2, "Resuming Guest Software after Handling an Exception").
+         * (NB. If we emulate this IRET for any reason, we should re-clear!)
+         */
+        if ( unlikely(intr_info & INTR_INFO_NMI_UNBLOCKED_BY_IRET) &&
+             !(__vmread(IDT_VECTORING_INFO_FIELD) & INTR_INFO_VALID_MASK) &&
+             (vector != TRAP_double_fault) )
+            __vmwrite(GUEST_INTERRUPTIBILITY_INFO,
+                    __vmread(GUEST_INTERRUPTIBILITY_INFO)|VMX_INTR_SHADOW_NMI);
+
         perfc_incra(cause_vector, vector);
 
         switch ( vector )
diff -r 9fa9346e1c70 -r e6d5e4709466 xen/include/asm-x86/hvm/vmx/vmcs.h
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h        Tue Jul 03 17:22:17 2007 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h        Tue Jul 03 18:46:00 2007 +0100
@@ -137,6 +137,8 @@ extern bool_t cpu_has_vmx_ins_outs_instr
     (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)
 #define cpu_has_vmx_tpr_shadow \
     (vmx_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)
+#define cpu_has_vmx_vnmi \
+    (vmx_pin_based_exec_control & PIN_BASED_VIRTUAL_NMIS)
 #define cpu_has_vmx_msr_bitmap \
     (vmx_cpu_based_exec_control & CPU_BASED_ACTIVATE_MSR_BITMAP)
 extern char *vmx_msr_bitmap;
diff -r 9fa9346e1c70 -r e6d5e4709466 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Tue Jul 03 17:22:17 2007 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Tue Jul 03 18:46:00 2007 +0100
@@ -90,7 +90,9 @@ void vmx_vlapic_msr_changed(struct vcpu 
 #define INTR_INFO_VECTOR_MASK           0xff            /* 7:0 */
 #define INTR_INFO_INTR_TYPE_MASK        0x700           /* 10:8 */
 #define INTR_INFO_DELIVER_CODE_MASK     0x800           /* 11 */
+#define INTR_INFO_NMI_UNBLOCKED_BY_IRET 0x1000          /* 12 */
 #define INTR_INFO_VALID_MASK            0x80000000      /* 31 */
+#define INTR_INFO_RESVD_BITS_MASK       0x7ffff000
 
 #define INTR_TYPE_EXT_INTR              (0 << 8)    /* external interrupt */
 #define INTR_TYPE_NMI                   (2 << 8)    /* NMI                */

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.