Implement FFXSR (Alexander Graf)
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 2 Feb 2009 17:10:52 +0000 (17:10 +0000)
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 2 Feb 2009 17:10:52 +0000 (17:10 +0000)
Newer AMD CPUs have the FFXSR capability. This leaves out XMM
register in FXSAVE/FXRESTORE when in CPL=0 and 64-bit mode.

This is required for Hyper-V.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6500 c046a42c-6fe2-441c-8c8c-71466251a162

target-i386/op_helper.c

index c2eda86..87c7a57 100644 (file)
@@ -3030,6 +3030,8 @@ void helper_wrmsr(void)
                 update_mask |= MSR_EFER_NXE;
             if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
                 update_mask |= MSR_EFER_SVME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
             cpu_load_efer(env, (env->efer & ~update_mask) |
                           (val & update_mask));
         }
@@ -4352,10 +4354,15 @@ void helper_fxsave(target_ulong ptr, int data64)
         else
             nb_xmm_regs = 8;
         addr = ptr + 0xa0;
-        for(i = 0; i < nb_xmm_regs; i++) {
-            stq(addr, env->xmm_regs[i].XMM_Q(0));
-            stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
-            addr += 16;
+        /* Fast FXSAVE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                stq(addr, env->xmm_regs[i].XMM_Q(0));
+                stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
+                addr += 16;
+            }
         }
     }
 }
@@ -4392,10 +4399,15 @@ void helper_fxrstor(target_ulong ptr, int data64)
         else
             nb_xmm_regs = 8;
         addr = ptr + 0xa0;
-        for(i = 0; i < nb_xmm_regs; i++) {
-            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
-            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
-            addr += 16;
+        /* Fast FXRESTORE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                env->xmm_regs[i].XMM_Q(0) = ldq(addr);
+                env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+                addr += 16;
+            }
         }
     }
 }