EFER loading fixes, including SVME bit
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 4 Jun 2008 13:35:58 +0000 (13:35 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 4 Jun 2008 13:35:58 +0000 (13:35 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4659 c046a42c-6fe2-441c-8c8c-71466251a162

target-i386/cpu.h
target-i386/exec.h
target-i386/op_helper.c

index d9253a1..76d2e7b 100644 (file)
 #define HF_GIF_SHIFT        20 /* if set CPU takes interrupts */
 #define HF_HIF_SHIFT        21 /* shadow copy of IF_MASK when in SVM */
 #define HF_NMI_SHIFT        22 /* CPU serving NMI */
-#define HF_SVME_SHIFT       23 /* SVME enabled (copy of EFER.SVME */
+#define HF_SVME_SHIFT       23 /* SVME enabled (copy of EFER.SVME) */
 #define HF_SVMI_SHIFT       24 /* SVM intercepts are active */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
index 90b82f3..035881e 100644 (file)
@@ -397,3 +397,14 @@ static inline int cpu_halted(CPUState *env) {
     return EXCP_HALTED;
 }
 
+/* load efer and update the corresponding hflags. XXX: do consistency
+   checks with cpuid bits ? */
+static inline void cpu_load_efer(CPUState *env, uint64_t val)
+{
+    env->efer = val;
+    env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
+    if (env->efer & MSR_EFER_LMA)
+        env->hflags |= HF_LMA_MASK;
+    if (env->efer & MSR_EFER_SVME)
+        env->hflags |= HF_SVME_MASK;
+}
index 83fa69a..56bef6e 100644 (file)
@@ -1435,8 +1435,7 @@ void do_smm_enter(void)
     /* init SMM cpu state */
 
 #ifdef TARGET_X86_64
-    env->efer = 0;
-    env->hflags &= ~HF_LMA_MASK;
+    cpu_load_efer(env, 0);
 #endif
     load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
     env->eip = 0x00008000;
@@ -1463,11 +1462,7 @@ void helper_rsm(void)
 
     sm_state = env->smbase + 0x8000;
 #ifdef TARGET_X86_64
-    env->efer = ldq_phys(sm_state + 0x7ed0);
-    if (env->efer & MSR_EFER_LMA)
-        env->hflags |= HF_LMA_MASK;
-    else
-        env->hflags &= ~HF_LMA_MASK;
+    cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
 
     for(i = 0; i < 6; i++) {
         offset = 0x7e00 + i * 16;
@@ -3069,8 +3064,10 @@ void helper_wrmsr(void)
                 update_mask |= MSR_EFER_FFXSR;
             if (env->cpuid_ext2_features & CPUID_EXT2_NX)
                 update_mask |= MSR_EFER_NXE;
-            env->efer = (env->efer & ~update_mask) |
-            (val & update_mask);
+            if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
+                update_mask |= MSR_EFER_SVME;
+            cpu_load_efer(env, (env->efer & ~update_mask) |
+                          (val & update_mask));
         }
         break;
     case MSR_STAR:
@@ -4873,10 +4870,8 @@ void helper_vmrun(void)
     }
 
 #ifdef TARGET_X86_64
-    env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer));
-    env->hflags &= ~HF_LMA_MASK;
-    if (env->efer & MSR_EFER_LMA)
-       env->hflags |= HF_LMA_MASK;
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
 #endif
     env->eflags = 0;
     load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
@@ -5224,20 +5219,11 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
         env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8));
         cpu_set_apic_tpr(env, env->cr[8]);
     }
-    /* we need to set the efer after the crs so the hidden flags get set properly */
+    /* we need to set the efer after the crs so the hidden flags get
+       set properly */
 #ifdef TARGET_X86_64
-    env->efer  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer));
-    env->hflags &= ~HF_LMA_MASK;
-    if (env->efer & MSR_EFER_LMA)
-       env->hflags |= HF_LMA_MASK;
-    /* XXX: should also emulate the VM_CR MSR */
-    env->hflags &= ~HF_SVME_MASK;
-    if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
-        if (env->efer & MSR_EFER_SVME)
-            env->hflags |= HF_SVME_MASK;
-    } else {
-        env->efer &= ~MSR_EFER_SVME;
-    }
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
 #endif
 
     env->eflags = 0;