qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE
@ 2016-02-09 17:13 Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 1/5] target-i386: Split fxsave/fxrstor implementation Paolo Bonzini
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

The bulk of these patches were posted by Richard several months ago; I
have only refreshed them and made them pass kvm-unit-tests.  They also
pass a quick Fedora 21 boot-test.

Patch 5 also passes the PKU kvm-unit-test.

Paolo

Paolo Bonzini (1):
  target-i386: implement PKE for TCG

Richard Henderson (4):
  target-i386: Split fxsave/fxrstor implementation
  target-i386: Rearrange processing of 0F 01
  target-i386: Add XSAVE extension
  target-i386: Implement XSAVEOPT

 target-i386/cpu.c         |  44 ++--
 target-i386/cpu.h         |  10 +-
 target-i386/fpu_helper.c  | 331 +++++++++++++++++++++------
 target-i386/helper.c      |  61 ++++-
 target-i386/helper.h      |  11 +-
 target-i386/kvm.c         |  16 +-
 target-i386/misc_helper.c |  32 +++
 target-i386/translate.c   | 569 +++++++++++++++++++++++++++-------------------
 8 files changed, 750 insertions(+), 324 deletions(-)

-- 
2.5.0

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 1/5] target-i386: Split fxsave/fxrstor implementation
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
@ 2016-02-09 17:13 ` Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 2/5] target-i386: Rearrange processing of 0F 01 Paolo Bonzini
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

From: Richard Henderson <rth@twiddle.net>

We will be able to reuse these pieces for XSAVE/XRSTOR.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Message-Id: <1436429849-18052-2-git-send-email-rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/fpu_helper.c | 160 ++++++++++++++++++++++++++---------------------
 target-i386/helper.h     |   4 +-
 target-i386/translate.c  |   4 +-
 3 files changed, 92 insertions(+), 76 deletions(-)

diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 2d54b47..dc16023 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1115,18 +1115,11 @@ void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
 }
 #endif
 
-static void do_fxsave(CPUX86State *env, target_ulong ptr, int data64,
-                      uintptr_t retaddr)
+static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
 {
-    int fpus, fptag, i, nb_xmm_regs;
-    floatx80 tmp;
+    int fpus, fptag, i;
     target_ulong addr;
 
-    /* The operand must be 16 byte aligned */
-    if (ptr & 0xf) {
-        raise_exception_ra(env, EXCP0D_GPF, retaddr);
-    }
-
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
     for (i = 0; i < 8; i++) {
@@ -1135,66 +1128,72 @@ static void do_fxsave(CPUX86State *env, target_ulong ptr, int data64,
     cpu_stw_data_ra(env, ptr, env->fpuc, retaddr);
     cpu_stw_data_ra(env, ptr + 2, fpus, retaddr);
     cpu_stw_data_ra(env, ptr + 4, fptag ^ 0xff, retaddr);
-#ifdef TARGET_X86_64
-    if (data64) {
-        cpu_stq_data_ra(env, ptr + 0x08, 0, retaddr); /* rip */
-        cpu_stq_data_ra(env, ptr + 0x10, 0, retaddr); /* rdp */
-    } else
-#endif
-    {
-        cpu_stl_data_ra(env, ptr + 0x08, 0, retaddr); /* eip */
-        cpu_stl_data_ra(env, ptr + 0x0c, 0, retaddr); /* sel  */
-        cpu_stl_data_ra(env, ptr + 0x10, 0, retaddr); /* dp */
-        cpu_stl_data_ra(env, ptr + 0x14, 0, retaddr); /* sel  */
-    }
+
+    /* In 32-bit mode this is eip, sel, dp, sel.
+     * In 64-bit mode this is rip, rdp.
+     * But in either case we don't write actual data, just zeros.
+     */
+    cpu_stq_data_ra(env, ptr + 0x08, 0, retaddr); /* eip+sel; rip */
+    cpu_stq_data_ra(env, ptr + 0x10, 0, retaddr); /* dp+sel; rdp */
 
     addr = ptr + 0x20;
     for (i = 0; i < 8; i++) {
-        tmp = ST(i);
+        floatx80 tmp = ST(i);
         helper_fstt(env, tmp, addr, retaddr);
         addr += 16;
     }
-
-    if (env->cr[4] & CR4_OSFXSR_MASK) {
-        /* XXX: finish it */
-        cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, retaddr); /* mxcsr */
-        cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, retaddr); /* mxcsr_mask */
-        if (env->hflags & HF_CS64_MASK) {
-            nb_xmm_regs = 16;
-        } else {
-            nb_xmm_regs = 8;
-        }
-        addr = ptr + 0xa0;
-        /* 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++) {
-                cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), retaddr);
-                cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), retaddr);
-                addr += 16;
-            }
-        }
-    }
 }
 
-void helper_fxsave(CPUX86State *env, target_ulong ptr, int data64)
+static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
 {
-    do_fxsave(env, ptr, data64, GETPC());
+    cpu_stl_data_ra(env, ptr + 0x18, env->mxcsr, retaddr); /* mxcsr */
+    cpu_stl_data_ra(env, ptr + 0x1c, 0x0000ffff, retaddr); /* mxcsr_mask */
 }
 
-static void do_fxrstor(CPUX86State *env, target_ulong ptr, int data64,
-                       uintptr_t retaddr)
+static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
 {
-    int i, fpus, fptag, nb_xmm_regs;
-    floatx80 tmp;
+    int i, nb_xmm_regs;
     target_ulong addr;
 
+    if (env->hflags & HF_CS64_MASK) {
+        nb_xmm_regs = 16;
+    } else {
+        nb_xmm_regs = 8;
+    }
+
+    addr = ptr + 0xa0;
+    for (i = 0; i < nb_xmm_regs; i++) {
+        cpu_stq_data_ra(env, addr, env->xmm_regs[i].ZMM_Q(0), retaddr);
+        cpu_stq_data_ra(env, addr + 8, env->xmm_regs[i].ZMM_Q(1), retaddr);
+        addr += 16;
+    }
+}
+
+void helper_fxsave(CPUX86State *env, target_ulong ptr)
+{
     /* The operand must be 16 byte aligned */
     if (ptr & 0xf) {
-        raise_exception_ra(env, EXCP0D_GPF, retaddr);
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
     }
 
+    do_xsave_fpu(env, ptr, GETPC());
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        do_xsave_mxcsr(env, ptr, GETPC());
+        /* Fast FXSAVE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+            || (env->hflags & HF_CPL_MASK)
+            || !(env->hflags & HF_LMA_MASK)) {
+            do_xsave_sse(env, ptr, GETPC());
+        }
+     }
+}
+
+static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+{
+    int i, fpus, fptag;
+    target_ulong addr;
+
     cpu_set_fpuc(env, cpu_lduw_data_ra(env, ptr, retaddr));
     fpus = cpu_lduw_data_ra(env, ptr + 2, retaddr);
     fptag = cpu_lduw_data_ra(env, ptr + 4, retaddr);
@@ -1207,39 +1206,56 @@ static void do_fxrstor(CPUX86State *env, target_ulong ptr, int data64,
 
     addr = ptr + 0x20;
     for (i = 0; i < 8; i++) {
-        tmp = helper_fldt(env, addr, retaddr);
+        floatx80 tmp = helper_fldt(env, addr, retaddr);
         ST(i) = tmp;
         addr += 16;
     }
+}
+
+static void do_xrstor_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+{
+    cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, retaddr));
+}
+
+static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+{
+    int i, nb_xmm_regs;
+    target_ulong addr;
+
+    if (env->hflags & HF_CS64_MASK) {
+        nb_xmm_regs = 16;
+    } else {
+        nb_xmm_regs = 8;
+    }
+
+    addr = ptr + 0xa0;
+    for (i = 0; i < nb_xmm_regs; i++) {
+        env->xmm_regs[i].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, retaddr);
+        env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, retaddr);
+        addr += 16;
+    }
+}
+
+void helper_fxrstor(CPUX86State *env, target_ulong ptr)
+{
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    do_xrstor_fpu(env, ptr, GETPC());
 
     if (env->cr[4] & CR4_OSFXSR_MASK) {
-        /* XXX: finish it */
-        cpu_set_mxcsr(env, cpu_ldl_data_ra(env, ptr + 0x18, retaddr));
-        /* cpu_ldl_data_ra(env, ptr + 0x1c, retaddr); */
-        if (env->hflags & HF_CS64_MASK) {
-            nb_xmm_regs = 16;
-        } else {
-            nb_xmm_regs = 8;
-        }
-        addr = ptr + 0xa0;
-        /* Fast FXRESTORE leaves out the XMM registers */
+        do_xrstor_mxcsr(env, ptr, GETPC());
+        /* Fast FXRSTOR 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].ZMM_Q(0) = cpu_ldq_data_ra(env, addr, retaddr);
-                env->xmm_regs[i].ZMM_Q(1) = cpu_ldq_data_ra(env, addr + 8, retaddr);
-                addr += 16;
-            }
+            do_xrstor_sse(env, ptr, GETPC());
         }
     }
 }
 
-void helper_fxrstor(CPUX86State *env, target_ulong ptr, int data64)
-{
-    do_fxrstor(env, ptr, data64, GETPC());
-}
-
 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
 {
     CPU_LDoubleU temp;
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 3a25c3b..6109e46 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -185,8 +185,8 @@ DEF_HELPER_3(fstenv, void, env, tl, int)
 DEF_HELPER_3(fldenv, void, env, tl, int)
 DEF_HELPER_3(fsave, void, env, tl, int)
 DEF_HELPER_3(frstor, void, env, tl, int)
-DEF_HELPER_3(fxsave, void, env, tl, int)
-DEF_HELPER_3(fxrstor, void, env, tl, int)
+DEF_HELPER_FLAGS_2(fxsave, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_2(fxrstor, TCG_CALL_NO_WG, void, env, tl)
 
 DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
diff --git a/target-i386/translate.c b/target-i386/translate.c
index c8e2799..fec2601 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7515,7 +7515,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                 break;
             }
             gen_lea_modrm(env, s, modrm);
-            gen_helper_fxsave(cpu_env, cpu_A0, tcg_const_i32(dflag == MO_64));
+            gen_helper_fxsave(cpu_env, cpu_A0);
             break;
         case 1: /* fxrstor */
             if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
@@ -7526,7 +7526,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                 break;
             }
             gen_lea_modrm(env, s, modrm);
-            gen_helper_fxrstor(cpu_env, cpu_A0, tcg_const_i32(dflag == MO_64));
+            gen_helper_fxrstor(cpu_env, cpu_A0);
             break;
         case 2: /* ldmxcsr */
         case 3: /* stmxcsr */
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 2/5] target-i386: Rearrange processing of 0F 01
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 1/5] target-i386: Split fxsave/fxrstor implementation Paolo Bonzini
@ 2016-02-09 17:13 ` Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 3/5] target-i386: Add XSAVE extension Paolo Bonzini
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

From: Richard Henderson <rth@twiddle.net>

Rather than nesting tests of OP, MOD, and RM, decode them
all at once with a switch.  Fixes incorrect decoding of
AMD Pacifica extensions (aka vmrun et al) via op==2 path.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Message-Id: <1436429849-18052-3-git-send-email-rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/translate.c | 465 +++++++++++++++++++++++++-----------------------
 1 file changed, 242 insertions(+), 223 deletions(-)

diff --git a/target-i386/translate.c b/target-i386/translate.c
index fec2601..579870b 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -56,6 +56,12 @@
 # define clztl  clz32
 #endif
 
+/* For a switch indexed by MODRM, match all memory operands for a given OP.  */
+#define CASE_MEM_OP(OP) \
+    case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
+    case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
+    case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7
+
 //#define MACRO_TEST   1
 
 /* global register indexes */
@@ -7000,15 +7006,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             goto illegal_op;
         }
         break;
+
     case 0x101:
         modrm = cpu_ldub_code(env, s->pc++);
-        mod = (modrm >> 6) & 3;
-        op = (modrm >> 3) & 7;
-        rm = modrm & 7;
-        switch(op) {
-        case 0: /* sgdt */
-            if (mod == 3)
-                goto illegal_op;
+        switch (modrm) {
+        CASE_MEM_OP(0): /* sgdt */
             gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
             gen_lea_modrm(env, s, modrm);
             tcg_gen_ld32u_tl(cpu_T0,
@@ -7021,178 +7023,200 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             }
             gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
             break;
-        case 1:
-            if (mod == 3) {
-                switch (rm) {
-                case 0: /* monitor */
-                    if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
-                        s->cpl != 0)
-                        goto illegal_op;
-                    gen_update_cc_op(s);
-                    gen_jmp_im(pc_start - s->cs_base);
-                    tcg_gen_mov_tl(cpu_A0, cpu_regs[R_EAX]);
-                    gen_extu(s->aflag, cpu_A0);
-                    gen_add_A0_ds_seg(s);
-                    gen_helper_monitor(cpu_env, cpu_A0);
-                    break;
-                case 1: /* mwait */
-                    if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
-                        s->cpl != 0)
-                        goto illegal_op;
-                    gen_update_cc_op(s);
-                    gen_jmp_im(pc_start - s->cs_base);
-                    gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
-                    gen_eob(s);
-                    break;
-                case 2: /* clac */
-                    if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
-                        s->cpl != 0) {
-                        goto illegal_op;
-                    }
-                    gen_helper_clac(cpu_env);
-                    gen_jmp_im(s->pc - s->cs_base);
-                    gen_eob(s);
-                    break;
-                case 3: /* stac */
-                    if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
-                        s->cpl != 0) {
-                        goto illegal_op;
-                    }
-                    gen_helper_stac(cpu_env);
-                    gen_jmp_im(s->pc - s->cs_base);
-                    gen_eob(s);
-                    break;
-                default:
-                    goto illegal_op;
-                }
-            } else { /* sidt */
-                gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
-                gen_lea_modrm(env, s, modrm);
-                tcg_gen_ld32u_tl(cpu_T0,
-                                 cpu_env, offsetof(CPUX86State, idt.limit));
-                gen_op_st_v(s, MO_16, cpu_T0, cpu_A0);
-                gen_add_A0_im(s, 2);
-                tcg_gen_ld_tl(cpu_T0,
-                              cpu_env, offsetof(CPUX86State, idt.base));
-                if (dflag == MO_16) {
-                    tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
-                }
-                gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+
+        case 0xc8: /* monitor */
+            if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+                goto illegal_op;
             }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            tcg_gen_mov_tl(cpu_A0, cpu_regs[R_EAX]);
+            gen_extu(s->aflag, cpu_A0);
+            gen_add_A0_ds_seg(s);
+            gen_helper_monitor(cpu_env, cpu_A0);
             break;
-        case 2: /* lgdt */
-        case 3: /* lidt */
-            if (mod == 3) {
-                gen_update_cc_op(s);
-                gen_jmp_im(pc_start - s->cs_base);
-                switch(rm) {
-                case 0: /* VMRUN */
-                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
-                                         tcg_const_i32(s->pc - pc_start));
-                        tcg_gen_exit_tb(0);
-                        s->is_jmp = DISAS_TB_JUMP;
-                    }
-                    break;
-                case 1: /* VMMCALL */
-                    if (!(s->flags & HF_SVME_MASK))
-                        goto illegal_op;
-                    gen_helper_vmmcall(cpu_env);
-                    break;
-                case 2: /* VMLOAD */
-                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1));
-                    }
-                    break;
-                case 3: /* VMSAVE */
-                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1));
-                    }
-                    break;
-                case 4: /* STGI */
-                    if ((!(s->flags & HF_SVME_MASK) &&
-                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
-                        !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_stgi(cpu_env);
-                    }
-                    break;
-                case 5: /* CLGI */
-                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_clgi(cpu_env);
-                    }
-                    break;
-                case 6: /* SKINIT */
-                    if ((!(s->flags & HF_SVME_MASK) && 
-                         !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) || 
-                        !s->pe)
-                        goto illegal_op;
-                    gen_helper_skinit(cpu_env);
-                    break;
-                case 7: /* INVLPGA */
-                    if (!(s->flags & HF_SVME_MASK) || !s->pe)
-                        goto illegal_op;
-                    if (s->cpl != 0) {
-                        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        break;
-                    } else {
-                        gen_helper_invlpga(cpu_env,
-                                           tcg_const_i32(s->aflag - 1));
-                    }
-                    break;
-                default:
-                    goto illegal_op;
-                }
-            } else if (s->cpl != 0) {
+
+        case 0xc9: /* mwait */
+            if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || s->cpl != 0) {
+                goto illegal_op;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
+            gen_eob(s);
+            break;
+
+        case 0xca: /* clac */
+            if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
+                || s->cpl != 0) {
+                goto illegal_op;
+            }
+            gen_helper_clac(cpu_env);
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+            break;
+
+        case 0xcb: /* stac */
+            if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
+                || s->cpl != 0) {
+                goto illegal_op;
+            }
+            gen_helper_stac(cpu_env);
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+            break;
+
+        CASE_MEM_OP(1): /* sidt */
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
+            gen_lea_modrm(env, s, modrm);
+            tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.limit));
+            gen_op_st_v(s, MO_16, cpu_T0, cpu_A0);
+            gen_add_A0_im(s, 2);
+            tcg_gen_ld_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.base));
+            if (dflag == MO_16) {
+                tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+            }
+            gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+            break;
+
+        case 0xd8: /* VMRUN */
+            if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-            } else {
-                gen_svm_check_intercept(s, pc_start,
-                                        op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE);
-                gen_lea_modrm(env, s, modrm);
-                gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
-                gen_add_A0_im(s, 2);
-                gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
-                if (dflag == MO_16) {
-                    tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
-                }
-                if (op == 2) {
-                    tcg_gen_st_tl(cpu_T0, cpu_env,
-                                  offsetof(CPUX86State, gdt.base));
-                    tcg_gen_st32_tl(cpu_T1, cpu_env,
-                                    offsetof(CPUX86State, gdt.limit));
-                } else {
-                    tcg_gen_st_tl(cpu_T0, cpu_env,
-                                  offsetof(CPUX86State, idt.base));
-                    tcg_gen_st32_tl(cpu_T1, cpu_env,
-                                    offsetof(CPUX86State, idt.limit));
-                }
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
+                             tcg_const_i32(s->pc - pc_start));
+            tcg_gen_exit_tb(0);
+            s->is_jmp = DISAS_TB_JUMP;
+            break;
+
+        case 0xd9: /* VMMCALL */
+            if (!(s->flags & HF_SVME_MASK)) {
+                goto illegal_op;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_vmmcall(cpu_env);
+            break;
+
+        case 0xda: /* VMLOAD */
+            if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1));
+            break;
+
+        case 0xdb: /* VMSAVE */
+            if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1));
+            break;
+
+        case 0xdc: /* STGI */
+            if ((!(s->flags & HF_SVME_MASK)
+                   && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+                || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_stgi(cpu_env);
+            break;
+
+        case 0xdd: /* CLGI */
+            if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_clgi(cpu_env);
+            break;
+
+        case 0xde: /* SKINIT */
+            if ((!(s->flags & HF_SVME_MASK)
+                 && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
+                || !s->pe) {
+                goto illegal_op;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_skinit(cpu_env);
+            break;
+
+        case 0xdf: /* INVLPGA */
+            if (!(s->flags & HF_SVME_MASK) || !s->pe) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1));
+            break;
+
+        CASE_MEM_OP(2): /* lgdt */
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_WRITE);
+            gen_lea_modrm(env, s, modrm);
+            gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
+            gen_add_A0_im(s, 2);
+            gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+            if (dflag == MO_16) {
+                tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+            }
+            tcg_gen_st_tl(cpu_T0, cpu_env, offsetof(CPUX86State, gdt.base));
+            tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, gdt.limit));
+            break;
+
+        CASE_MEM_OP(3): /* lidt */
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
             }
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_WRITE);
+            gen_lea_modrm(env, s, modrm);
+            gen_op_ld_v(s, MO_16, cpu_T1, cpu_A0);
+            gen_add_A0_im(s, 2);
+            gen_op_ld_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
+            if (dflag == MO_16) {
+                tcg_gen_andi_tl(cpu_T0, cpu_T0, 0xffffff);
+            }
+            tcg_gen_st_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.base));
+            tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, idt.limit));
             break;
-        case 4: /* smsw */
+
+        CASE_MEM_OP(4): /* smsw */
             gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
 #if defined TARGET_X86_64 && defined HOST_WORDS_BIGENDIAN
             tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, cr[0]) + 4);
@@ -7201,66 +7225,61 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
 #endif
             gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 1);
             break;
-        case 6: /* lmsw */
+        CASE_MEM_OP(6): /* lmsw */
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-            } else {
-                gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
-                gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
-                gen_helper_lmsw(cpu_env, cpu_T0);
-                gen_jmp_im(s->pc - s->cs_base);
-                gen_eob(s);
+                break;
             }
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
+            gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
+            gen_helper_lmsw(cpu_env, cpu_T0);
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
             break;
-        case 7:
-            if (mod != 3) { /* invlpg */
+        CASE_MEM_OP(7):
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_lea_modrm(env, s, modrm);
+            gen_helper_invlpg(cpu_env, cpu_A0);
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+            break;
+        case 0xf8: /* swapgs */
+#ifdef TARGET_X86_64
+            if (CODE64(s)) {
                 if (s->cpl != 0) {
                     gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
                 } else {
-                    gen_update_cc_op(s);
-                    gen_jmp_im(pc_start - s->cs_base);
-                    gen_lea_modrm(env, s, modrm);
-                    gen_helper_invlpg(cpu_env, cpu_A0);
-                    gen_jmp_im(s->pc - s->cs_base);
-                    gen_eob(s);
+                    tcg_gen_mov_tl(cpu_T0, cpu_seg_base[R_GS]);
+                    tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
+                                  offsetof(CPUX86State, kernelgsbase));
+                    tcg_gen_st_tl(cpu_T0, cpu_env,
+                                  offsetof(CPUX86State, kernelgsbase));
                 }
-            } else {
-                switch (rm) {
-                case 0: /* swapgs */
-#ifdef TARGET_X86_64
-                    if (CODE64(s)) {
-                        if (s->cpl != 0) {
-                            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-                        } else {
-                            tcg_gen_mov_tl(cpu_T0, cpu_seg_base[R_GS]);
-                            tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
-                                          offsetof(CPUX86State, kernelgsbase));
-                            tcg_gen_st_tl(cpu_T0, cpu_env,
-                                          offsetof(CPUX86State, kernelgsbase));
-                        }
-                        break;
-                    }
+                break;
+            }
 #endif
-                    goto illegal_op;
-                case 1: /* rdtscp */
-                    if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP))
-                        goto illegal_op;
-                    gen_update_cc_op(s);
-                    gen_jmp_im(pc_start - s->cs_base);
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
-                        gen_io_start();
-		    }
-                    gen_helper_rdtscp(cpu_env);
-                    if (s->tb->cflags & CF_USE_ICOUNT) {
-                        gen_io_end();
-                        gen_jmp(s, s->pc - s->cs_base);
-                    }
-                    break;
-                default:
-                    goto illegal_op;
-                }
+            goto illegal_op;
+        case 0xf9: /* rdtscp */
+            if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP)) {
+                goto illegal_op;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            if (s->tb->cflags & CF_USE_ICOUNT) {
+                gen_io_start();
+            }
+            gen_helper_rdtscp(cpu_env);
+            if (s->tb->cflags & CF_USE_ICOUNT) {
+                gen_io_end();
+                gen_jmp(s, s->pc - s->cs_base);
             }
             break;
+
         default:
             goto illegal_op;
         }
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 3/5] target-i386: Add XSAVE extension
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 1/5] target-i386: Split fxsave/fxrstor implementation Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 2/5] target-i386: Rearrange processing of 0F 01 Paolo Bonzini
@ 2016-02-09 17:13 ` Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 4/5] target-i386: Implement XSAVEOPT Paolo Bonzini
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

From: Richard Henderson <rth@twiddle.net>

This includes XSAVE, XRSTOR, XGETBV, XSETBV, which are all related,
as well as the associate cpuid bits.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Message-Id: <1436429849-18052-4-git-send-email-rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/cpu.c        |  42 +++++++++-------
 target-i386/cpu.h        |   2 +
 target-i386/fpu_helper.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/helper.c     |  33 ++++++++++---
 target-i386/helper.h     |   4 ++
 target-i386/kvm.c        |  16 ++++--
 target-i386/translate.c  |  72 ++++++++++++++++++++++++++-
 7 files changed, 263 insertions(+), 29 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3fa14bf..ae24b75 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -331,14 +331,14 @@ static const char *cpuid_6_feature_name[] = {
 #define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | \
           CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | \
           CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
+          CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */   \
           CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR)
           /* missing:
           CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
           CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
           CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
-          CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_XSAVE,
-          CPUID_EXT_OSXSAVE, CPUID_EXT_AVX, CPUID_EXT_F16C,
-          CPUID_EXT_RDRAND */
+          CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX,
+          CPUID_EXT_F16C, CPUID_EXT_RDRAND */
 
 #ifdef TARGET_X86_64
 #define TCG_EXT2_X86_64_FEATURES (CPUID_EXT2_SYSCALL | CPUID_EXT2_LM)
@@ -440,7 +440,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
         .cpuid_eax = 0xd,
         .cpuid_needs_ecx = true, .cpuid_ecx = 1,
         .cpuid_reg = R_EAX,
-        .tcg_features = 0,
+        .tcg_features = CPUID_XSAVE_XGETBV1,
     },
     [FEAT_6_EAX] = {
         .feat_names = cpuid_6_feature_name,
@@ -2323,10 +2323,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *ebx = (cpu->apic_id << 24) |
                8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
         *ecx = env->features[FEAT_1_ECX];
+        if ((*ecx & CPUID_EXT_XSAVE) && (env->hflags & HF_OSXSAVE_MASK)) {
+            *ecx |= CPUID_EXT_OSXSAVE;
+        }
         *edx = env->features[FEAT_1_EDX];
         if (cs->nr_cores * cs->nr_threads > 1) {
             *ebx |= (cs->nr_cores * cs->nr_threads) << 16;
-            *edx |= 1 << 28;    /* HTT bit */
+            *edx |= CPUID_HT;
         }
         break;
     case 2:
@@ -2450,7 +2453,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         break;
     case 0xD: {
         KVMState *s = cs->kvm_state;
-        uint64_t kvm_mask;
+        uint64_t ena_mask;
         int i;
 
         /* Processor Extended State */
@@ -2458,35 +2461,40 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *ebx = 0;
         *ecx = 0;
         *edx = 0;
-        if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) || !kvm_enabled()) {
+        if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
             break;
         }
-        kvm_mask =
-            kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX) |
-            ((uint64_t)kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX) << 32);
+        if (kvm_enabled()) {
+            ena_mask = kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EDX);
+            ena_mask <<= 32;
+            ena_mask |= kvm_arch_get_supported_cpuid(s, 0xd, 0, R_EAX);
+        } else {
+            ena_mask = -1;
+        }
 
         if (count == 0) {
             *ecx = 0x240;
             for (i = 2; i < ARRAY_SIZE(ext_save_areas); i++) {
                 const ExtSaveArea *esa = &ext_save_areas[i];
-                if ((env->features[esa->feature] & esa->bits) == esa->bits &&
-                    (kvm_mask & (1 << i)) != 0) {
+                if (esa->bits
+                    && (env->features[esa->feature] & esa->bits) == esa->bits
+                    && ((ena_mask >> i) & 1) != 0) {
                     if (i < 32) {
-                        *eax |= 1 << i;
+                        *eax |= 1u << i;
                     } else {
-                        *edx |= 1 << (i - 32);
+                        *edx |= 1u << (i - 32);
                     }
                     *ecx = MAX(*ecx, esa->offset + esa->size);
                 }
             }
-            *eax |= kvm_mask & (XSTATE_FP | XSTATE_SSE);
+            *eax |= ena_mask & (XSTATE_FP | XSTATE_SSE);
             *ebx = *ecx;
         } else if (count == 1) {
             *eax = env->features[FEAT_XSAVE];
         } else if (count < ARRAY_SIZE(ext_save_areas)) {
             const ExtSaveArea *esa = &ext_save_areas[count];
-            if ((env->features[esa->feature] & esa->bits) == esa->bits &&
-                (kvm_mask & (1 << count)) != 0) {
+            if ((env->features[esa->feature] & esa->bits) == esa->bits
+                && ((ena_mask >> count) & 1) != 0) {
                 *eax = esa->size;
                 *ebx = esa->offset;
             }
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a990ea7..e32df8a 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -156,6 +156,7 @@
 #define HF_OSFXSR_SHIFT     22 /* CR4.OSFXSR */
 #define HF_SMAP_SHIFT       23 /* CR4.SMAP */
 #define HF_IOBPT_SHIFT      24 /* an io breakpoint enabled */
+#define HF_OSXSAVE_SHIFT    25 /* CR4.OSXSAVE */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
@@ -180,6 +181,7 @@
 #define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
 #define HF_SMAP_MASK         (1 << HF_SMAP_SHIFT)
 #define HF_IOBPT_MASK        (1 << HF_IOBPT_SHIFT)
+#define HF_OSXSAVE_MASK      (1 << HF_OSXSAVE_SHIFT)
 
 /* hflags2 */
 
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index dc16023..568a9b8 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1189,6 +1189,39 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr)
      }
 }
 
+static uint64_t get_xinuse(CPUX86State *env)
+{
+    /* We don't track XINUSE.  We could calculate it here, but it's
+       probably less work to simply indicate all components in use.  */
+    return -1;
+}
+
+void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+    uint64_t old_bv, new_bv;
+
+    /* The operand must be 64 byte aligned.  */
+    if (ptr & 63) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    /* Never save anything not enabled by XCR0.  */
+    rfbm &= env->xcr0;
+
+    if (rfbm & XSTATE_FP) {
+        do_xsave_fpu(env, ptr, GETPC());
+    }
+    if (rfbm & XSTATE_SSE) {
+        do_xsave_mxcsr(env, ptr, GETPC());
+        do_xsave_sse(env, ptr, GETPC());
+    }
+
+    /* Update the XSTATE_BV field.  */
+    old_bv = cpu_ldq_data_ra(env, ptr + 512, GETPC());
+    new_bv = (old_bv & ~rfbm) | (get_xinuse(env) & rfbm);
+    cpu_stq_data_ra(env, ptr + 512, new_bv, GETPC());
+}
+
 static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
 {
     int i, fpus, fptag;
@@ -1256,6 +1289,96 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr)
     }
 }
 
+void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+    uint64_t xstate_bv, xcomp_bv0, xcomp_bv1;
+
+    rfbm &= env->xcr0;
+
+    /* The operand must be 64 byte aligned.  */
+    if (ptr & 63) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    xstate_bv = cpu_ldq_data_ra(env, ptr + 512, GETPC());
+
+    if ((int64_t)xstate_bv < 0) {
+        /* FIXME: Compact form.  */
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    /* Standard form.  */
+
+    /* The XSTATE field must not set bits not present in XCR0.  */
+    if (xstate_bv & ~env->xcr0) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    /* The XCOMP field must be zero.  */
+    xcomp_bv0 = cpu_ldq_data_ra(env, ptr + 520, GETPC());
+    xcomp_bv1 = cpu_ldq_data_ra(env, ptr + 528, GETPC());
+    if (xcomp_bv0 || xcomp_bv1) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+    }
+
+    if (rfbm & XSTATE_FP) {
+        if (xstate_bv & XSTATE_FP) {
+            do_xrstor_fpu(env, ptr, GETPC());
+        } else {
+            helper_fninit(env);
+            memset(env->fpregs, 0, sizeof(env->fpregs));
+        }
+    }
+    if (rfbm & XSTATE_SSE) {
+        /* Note that the standard form of XRSTOR loads MXCSR from memory
+           whether or not the XSTATE_BV bit is set.  */
+        do_xrstor_mxcsr(env, ptr, GETPC());
+        if (xstate_bv & XSTATE_SSE) {
+            do_xrstor_sse(env, ptr, GETPC());
+        } else {
+            /* ??? When AVX is implemented, we may have to be more
+               selective in the clearing.  */
+            memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
+        }
+    }
+}
+
+uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
+{
+    switch (ecx) {
+    case 0:
+        return env->xcr0;
+    case 1:
+        /* FIXME: #GP if !CPUID.(EAX=0DH,ECX=1):EAX.XG1[bit 2].  */
+        return env->xcr0 & get_xinuse(env);
+    }
+    raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+}
+
+void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
+{
+    uint32_t dummy, ena_lo, ena_hi;
+    uint64_t ena;
+
+    /* Only XCR0 is defined at present; the FPU may not be disabled.  */
+    if (ecx != 0 || (mask & XSTATE_FP) == 0) {
+        goto do_gpf;
+    }
+
+    /* Disallow enabling unimplemented features.  */
+    cpu_x86_cpuid(env, 0x0d, 0, &ena_lo, &dummy, &dummy, &ena_hi);
+    ena = ((uint64_t)ena_hi << 32) | ena_lo;
+    if (mask & ~ena) {
+        goto do_gpf;
+    }
+
+    env->xcr0 = mask;
+    return;
+
+ do_gpf:
+    raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+}
+
 void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
 {
     CPU_LDoubleU temp;
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 3802ed9..f5f0bec 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -647,6 +647,7 @@ void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
 {
     X86CPU *cpu = x86_env_get_cpu(env);
+    uint32_t hflags;
 
 #if defined(DEBUG_MMU)
     printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
@@ -656,24 +657,44 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
          CR4_SMEP_MASK | CR4_SMAP_MASK)) {
         tlb_flush(CPU(cpu), 1);
     }
+
+    /* Clear bits we're going to recompute.  */
+    hflags = env->hflags & ~(HF_OSFXSR_MASK | HF_OSXSAVE_MASK | HF_SMAP_MASK);
+
     /* SSE handling */
     if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
-        new_cr4 &= ~CR4_OSFXSR_MASK;
+        if (new_cr4 & CR4_OSFXSR_MASK) {
+            goto do_gpf;
+        }
     }
-    env->hflags &= ~HF_OSFXSR_MASK;
     if (new_cr4 & CR4_OSFXSR_MASK) {
-        env->hflags |= HF_OSFXSR_MASK;
+        hflags |= HF_OSFXSR_MASK;
+    }
+
+    if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
+        if (new_cr4 & CR4_OSXSAVE_MASK) {
+            goto do_gpf;
+        }
+    }
+    if (new_cr4 & CR4_OSXSAVE_MASK) {
+        hflags |= HF_OSXSAVE_MASK;
     }
 
     if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
-        new_cr4 &= ~CR4_SMAP_MASK;
+        if (new_cr4 & CR4_SMAP_MASK) {
+            goto do_gpf;
+        }
     }
-    env->hflags &= ~HF_SMAP_MASK;
     if (new_cr4 & CR4_SMAP_MASK) {
-        env->hflags |= HF_SMAP_MASK;
+        hflags |= HF_SMAP_MASK;
     }
 
     env->cr[4] = new_cr4;
+    env->hflags = hflags;
+    return;
+
+do_gpf:
+    raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
 }
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 6109e46..9dfc735 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -187,6 +187,10 @@ DEF_HELPER_3(fsave, void, env, tl, int)
 DEF_HELPER_3(frstor, void, env, tl, int)
 DEF_HELPER_FLAGS_2(fxsave, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_2(fxrstor, TCG_CALL_NO_WG, void, env, tl)
+DEF_HELPER_FLAGS_3(xsave, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_3(xrstor, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_2(xgetbv, TCG_CALL_NO_WG, i64, env, i32)
+DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
 
 DEF_HELPER_FLAGS_1(clz, TCG_CALL_NO_RWG_SE, tl, tl)
 DEF_HELPER_FLAGS_1(ctz, TCG_CALL_NO_RWG_SE, tl, tl)
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 94024bc..fb3a595 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1852,16 +1852,22 @@ static int kvm_get_sregs(X86CPU *cpu)
 #define HFLAG_COPY_MASK \
     ~( HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \
        HF_TS_MASK | HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK | \
-       HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \
+       HF_OSFXSR_MASK | HF_OSXSAVE_MASK | HF_LMA_MASK | HF_CS32_MASK | \
        HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)
 
-    hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
+    hflags = env->hflags & HFLAG_COPY_MASK;
+    hflags |= (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK;
     hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT);
     hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) &
                 (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK);
     hflags |= (env->eflags & (HF_TF_MASK | HF_VM_MASK | HF_IOPL_MASK));
-    hflags |= (env->cr[4] & CR4_OSFXSR_MASK) <<
-                (HF_OSFXSR_SHIFT - CR4_OSFXSR_SHIFT);
+
+    if (env->cr[4] & CR4_OSFXSR_MASK) {
+        hflags |= HF_OSFXSR_MASK;
+    }
+    if (env->cr[4] & CR4_OSXSAVE_MASK) {
+        hflags |= HF_OSXSAVE_MASK;
+    }
 
     if (env->efer & MSR_EFER_LMA) {
         hflags |= HF_LMA_MASK;
@@ -1882,7 +1888,7 @@ static int kvm_get_sregs(X86CPU *cpu)
                         env->segs[R_SS].base) != 0) << HF_ADDSEG_SHIFT;
         }
     }
-    env->hflags = (env->hflags & HFLAG_COPY_MASK) | hflags;
+    env->hflags = hflags;
 
     return 0;
 }
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 579870b..8301270 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7079,6 +7079,42 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
             gen_op_st_v(s, CODE64(s) + MO_32, cpu_T0, cpu_A0);
             break;
 
+        case 0xd0: /* xgetbv */
+            if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+                || (s->flags & HF_OSXSAVE_MASK) == 0
+                || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+                                 | PREFIX_REPZ | PREFIX_REPNZ))) {
+                goto illegal_op;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
+            gen_helper_xgetbv(cpu_tmp1_i64, cpu_env, cpu_tmp2_i32);
+            tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], cpu_tmp1_i64);
+            break;
+
+        case 0xd1: /* xsetbv */
+            if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+                || (s->flags & HF_OSXSAVE_MASK) == 0
+                || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+                                 | PREFIX_REPZ | PREFIX_REPNZ))) {
+                goto illegal_op;
+            }
+            if (s->cpl != 0) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+                break;
+            }
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+                                  cpu_regs[R_EDX]);
+            tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_ECX]);
+            gen_helper_xsetbv(cpu_env, cpu_tmp2_i32, cpu_tmp1_i64);
+            /* End TB because translation flags may change.  */
+            gen_jmp_im(s->pc - s->cs_base);
+            gen_eob(s);
+            break;
+
         case 0xd8: /* VMRUN */
             if (!(s->flags & HF_SVME_MASK) || !s->pe) {
                 goto illegal_op;
@@ -7567,10 +7603,44 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                 gen_op_st_v(s, MO_32, cpu_T0, cpu_A0);
             }
             break;
-        case 5: /* lfence */
+        case 4: /* xsave */
+            if (mod == 3
+                || (s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+                || (s->flags & HF_OSXSAVE_MASK) == 0
+                || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+                                 | PREFIX_REPZ | PREFIX_REPNZ))) {
+                goto illegal_op;
+            }
+            gen_lea_modrm(env, s, modrm);
+            tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+                                  cpu_regs[R_EDX]);
+            gen_helper_xsave(cpu_env, cpu_A0, cpu_tmp1_i64);
+            break;
             if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
                 goto illegal_op;
             break;
+        case 5:
+            if (mod == 3) {
+                /* lfence */
+                if (!(s->cpuid_features & CPUID_SSE2)
+                    || (s->prefix & PREFIX_LOCK)) {
+                    goto illegal_op;
+                }
+                /* no-op */
+            } else {
+                /* xrstor */
+                if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+                    || (s->flags & HF_OSXSAVE_MASK) == 0
+                    || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+                                     | PREFIX_REPZ | PREFIX_REPNZ))) {
+                    goto illegal_op;
+                }
+                gen_lea_modrm(env, s, modrm);
+                tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+                                      cpu_regs[R_EDX]);
+                gen_helper_xrstor(cpu_env, cpu_A0, cpu_tmp1_i64);
+            }
+            break;
         case 6: /* mfence/clwb */
             if (s->prefix & PREFIX_DATA) {
                 /* clwb */
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 4/5] target-i386: Implement XSAVEOPT
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
                   ` (2 preceding siblings ...)
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 3/5] target-i386: Add XSAVE extension Paolo Bonzini
@ 2016-02-09 17:13 ` Paolo Bonzini
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG Paolo Bonzini
  2016-02-09 17:43 ` [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Richard Henderson
  5 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

From: Richard Henderson <rth@twiddle.net>

Note the cpu.c change -- don't advertise more XSAVE features
than we implement.

Signed-off-by: Richard Henderson <rth@twiddle.net>
Message-Id: <1436429849-18052-5-git-send-email-rth@twiddle.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/cpu.c        |  2 +-
 target-i386/fpu_helper.c | 38 ++++++++++++++++++++++++++++----------
 target-i386/helper.h     |  1 +
 target-i386/translate.c  | 22 ++++++++++++++++++++--
 4 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index ae24b75..b500419 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -440,7 +440,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
         .cpuid_eax = 0xd,
         .cpuid_needs_ecx = true, .cpuid_ecx = 1,
         .cpuid_reg = R_EAX,
-        .tcg_features = CPUID_XSAVE_XGETBV1,
+        .tcg_features = CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1,
     },
     [FEAT_6_EAX] = {
         .feat_names = cpuid_6_feature_name,
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 568a9b8..a8512ea 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1196,7 +1196,8 @@ static uint64_t get_xinuse(CPUX86State *env)
     return -1;
 }
 
-void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+static void do_xsave(CPUX86State *env, target_ulong ptr,
+                     uint64_t rfbm, uint64_t inuse, uint64_t opt, uintptr_t retaddr)
 {
     uint64_t old_bv, new_bv;
 
@@ -1207,19 +1208,34 @@ void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
 
     /* Never save anything not enabled by XCR0.  */
     rfbm &= env->xcr0;
+    opt &= rfbm;
 
-    if (rfbm & XSTATE_FP) {
-        do_xsave_fpu(env, ptr, GETPC());
+    if (opt & XSTATE_FP) {
+        do_xsave_fpu(env, ptr, retaddr);
     }
     if (rfbm & XSTATE_SSE) {
-        do_xsave_mxcsr(env, ptr, GETPC());
-        do_xsave_sse(env, ptr, GETPC());
+        /* Note that saving MXCSR is not suppressed by XSAVEOPT.  */
+        do_xsave_mxcsr(env, ptr, retaddr);
+    }
+    if (opt & XSTATE_SSE) {
+        do_xsave_sse(env, ptr, retaddr);
     }
 
     /* Update the XSTATE_BV field.  */
-    old_bv = cpu_ldq_data_ra(env, ptr + 512, GETPC());
-    new_bv = (old_bv & ~rfbm) | (get_xinuse(env) & rfbm);
-    cpu_stq_data_ra(env, ptr + 512, new_bv, GETPC());
+    old_bv = cpu_ldq_data_ra(env, ptr + 512, retaddr);
+    new_bv = (old_bv & ~rfbm) | (inuse & rfbm);
+    cpu_stq_data_ra(env, ptr + 512, new_bv, retaddr);
+}
+
+void helper_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+    do_xsave(env, ptr, rfbm, get_xinuse(env), -1, GETPC());
+}
+
+void helper_xsaveopt(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
+{
+    uint64_t inuse = get_xinuse(env);
+    do_xsave(env, ptr, rfbm, inuse, inuse, GETPC());
 }
 
 static void do_xrstor_fpu(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
@@ -1349,8 +1365,10 @@ uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
     case 0:
         return env->xcr0;
     case 1:
-        /* FIXME: #GP if !CPUID.(EAX=0DH,ECX=1):EAX.XG1[bit 2].  */
-        return env->xcr0 & get_xinuse(env);
+        if (env->features[FEAT_XSAVE] & CPUID_XSAVE_XGETBV1) {
+            return env->xcr0 & get_xinuse(env);
+        }
+        break;
     }
     raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
 }
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 9dfc735..9a83955 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -188,6 +188,7 @@ DEF_HELPER_3(frstor, void, env, tl, int)
 DEF_HELPER_FLAGS_2(fxsave, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_2(fxrstor, TCG_CALL_NO_WG, void, env, tl)
 DEF_HELPER_FLAGS_3(xsave, TCG_CALL_NO_WG, void, env, tl, i64)
+DEF_HELPER_FLAGS_3(xsaveopt, TCG_CALL_NO_WG, void, env, tl, i64)
 DEF_HELPER_FLAGS_3(xrstor, TCG_CALL_NO_WG, void, env, tl, i64)
 DEF_HELPER_FLAGS_2(xgetbv, TCG_CALL_NO_WG, i64, env, i32)
 DEF_HELPER_FLAGS_3(xsetbv, TCG_CALL_NO_WG, void, env, i32, i64)
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 8301270..b84ce3b 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -127,6 +127,7 @@ typedef struct DisasContext {
     int cpuid_ext2_features;
     int cpuid_ext3_features;
     int cpuid_7_0_ebx_features;
+    int cpuid_xsave_features;
 } DisasContext;
 
 static void gen_eob(DisasContext *s);
@@ -7647,10 +7648,26 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
                 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLWB))
                     goto illegal_op;
                 gen_nop_modrm(env, s, modrm);
-            } else {
+            } else if ((modrm & 0xc7) == 0xc0) {
                 /* mfence */
-                if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
+                if (!(s->cpuid_features & CPUID_SSE2)
+                    || (s->prefix & PREFIX_LOCK)) {
                     goto illegal_op;
+                }
+                /* no-op */
+            } else {
+                /* xsaveopt */
+                if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
+                    || (s->cpuid_xsave_features & CPUID_XSAVE_XSAVEOPT) == 0
+                    || (s->flags & HF_OSXSAVE_MASK) == 0
+                    || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
+                                     | PREFIX_REPZ | PREFIX_REPNZ))) {
+                    goto illegal_op;
+                }
+                gen_lea_modrm(env, s, modrm);
+                tcg_gen_concat_tl_i64(cpu_tmp1_i64, cpu_regs[R_EAX],
+                                      cpu_regs[R_EDX]);
+                gen_helper_xsaveopt(cpu_env, cpu_A0, cpu_tmp1_i64);
             }
             break;
         case 7: /* sfence / clflush / clflushopt / pcommit */
@@ -7859,6 +7876,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
     dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX];
     dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
     dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
+    dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
 #ifdef TARGET_X86_64
     dc->lma = (flags >> HF_LMA_SHIFT) & 1;
     dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
                   ` (3 preceding siblings ...)
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 4/5] target-i386: Implement XSAVEOPT Paolo Bonzini
@ 2016-02-09 17:13 ` Paolo Bonzini
  2016-02-09 18:13   ` Richard Henderson
  2016-02-09 17:43 ` [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Richard Henderson
  5 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 17:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: rth

This includes setting up TLB permissions, the new RDPKRU/WRPKRU
instructions, and XSAVE support.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 target-i386/cpu.c         |  2 +-
 target-i386/cpu.h         |  8 ++++++-
 target-i386/fpu_helper.c  | 54 +++++++++++++++++++++++++++++++++++++++++++----
 target-i386/helper.c      | 28 ++++++++++++++++++++++++
 target-i386/helper.h      |  2 ++
 target-i386/misc_helper.c | 32 ++++++++++++++++++++++++++++
 target-i386/translate.c   |  6 ++++++
 7 files changed, 126 insertions(+), 6 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index b500419..267a492 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -363,7 +363,7 @@ static const char *cpuid_6_feature_name[] = {
           CPUID_7_0_EBX_FSGSBASE, CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2,
           CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
           CPUID_7_0_EBX_RDSEED */
-#define TCG_7_0_ECX_FEATURES 0
+#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_PKU | CPUID_7_0_ECX_OSPKE)
 #define TCG_APM_FEATURES 0
 #define TCG_6_EAX_FEATURES CPUID_6_EAX_ARAT
 
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index e32df8a..d932293 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -157,6 +157,7 @@
 #define HF_SMAP_SHIFT       23 /* CR4.SMAP */
 #define HF_IOBPT_SHIFT      24 /* an io breakpoint enabled */
 #define HF_OSXSAVE_SHIFT    25 /* CR4.OSXSAVE */
+#define HF_PKE_SHIFT        26 /* CR4.PKE enabled */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
@@ -182,6 +183,7 @@
 #define HF_SMAP_MASK         (1 << HF_SMAP_SHIFT)
 #define HF_IOBPT_MASK        (1 << HF_IOBPT_SHIFT)
 #define HF_OSXSAVE_MASK      (1 << HF_OSXSAVE_SHIFT)
+#define HF_PKE_MASK          (1 << HF_PKE_SHIFT)
 
 /* hflags2 */
 
@@ -229,6 +231,7 @@
 #define CR4_OSXSAVE_MASK (1U << 18)
 #define CR4_SMEP_MASK   (1U << 20)
 #define CR4_SMAP_MASK   (1U << 21)
+#define CR4_PKE_MASK   (1U << 22)
 
 #define DR6_BD          (1 << 13)
 #define DR6_BS          (1 << 14)
@@ -257,6 +260,7 @@
 #define PG_PSE_BIT      7
 #define PG_GLOBAL_BIT   8
 #define PG_PSE_PAT_BIT  12
+#define PG_PKRU_BIT     59
 #define PG_NX_BIT       63
 
 #define PG_PRESENT_MASK  (1 << PG_PRESENT_BIT)
@@ -272,7 +276,8 @@
 #define PG_ADDRESS_MASK  0x000ffffffffff000LL
 #define PG_HI_RSVD_MASK  (PG_ADDRESS_MASK & ~PHYS_ADDR_MASK)
 #define PG_HI_USER_MASK  0x7ff0000000000000LL
-#define PG_NX_MASK       (1LL << PG_NX_BIT)
+#define PG_PKRU_MASK     (15ULL << PG_PKRU_BIT)
+#define PG_NX_MASK       (1ULL << PG_NX_BIT)
 
 #define PG_ERROR_W_BIT     1
 
@@ -281,6 +286,7 @@
 #define PG_ERROR_U_MASK    0x04
 #define PG_ERROR_RSVD_MASK 0x08
 #define PG_ERROR_I_D_MASK  0x10
+#define PG_ERROR_PK_MASK   0x20
 
 #define MCG_CTL_P       (1ULL<<8)   /* MCG_CAP register available */
 #define MCG_SER_P       (1ULL<<24) /* MCA recovery/new status bits */
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index a8512ea..f0f14f4 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -1169,6 +1169,11 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
     }
 }
 
+static void do_xsave_pkru(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+{
+    cpu_stq_data_ra(env, ptr + 0xA80, env->pkru, retaddr);
+}
+
 void helper_fxsave(CPUX86State *env, target_ulong ptr)
 {
     /* The operand must be 16 byte aligned */
@@ -1191,9 +1196,18 @@ void helper_fxsave(CPUX86State *env, target_ulong ptr)
 
 static uint64_t get_xinuse(CPUX86State *env)
 {
-    /* We don't track XINUSE.  We could calculate it here, but it's
-       probably less work to simply indicate all components in use.  */
-    return -1;
+    uint64_t inuse = -1;
+
+    /* For the most part, we don't track XINUSE.  We could calculate it
+     * here for all components, but it's probably less work to simply
+     * indicate in use.  That said, for state that is important
+     * enough to track in HFLAGS, we might as well use that here.
+     */
+    if ((env->hflags & HF_PKE_MASK) == 0) {
+       inuse &= ~XSTATE_PKRU;
+    }
+    return inuse;
+}
 }
 
 static void do_xsave(CPUX86State *env, target_ulong ptr,
@@ -1220,6 +1248,9 @@ static void do_xsave(CPUX86State *env, target_ulong ptr,
     if (opt & XSTATE_SSE) {
         do_xsave_sse(env, ptr, retaddr);
     }
+    if (opt & XSTATE_PKRU) {
+        do_xsave_pkru(env, ptr, retaddr);
+    }
 
     /* Update the XSTATE_BV field.  */
     old_bv = cpu_ldq_data_ra(env, ptr + 512, retaddr);
@@ -1285,6 +1317,16 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
     }
 }
 
+static void do_xrstor_pkru(CPUX86State *env, target_ulong ptr, uintptr_t retaddr)
+{
+    uint64_t old_pkru = env->pkru;
+    env->pkru = cpu_ldq_data_ra(env, ptr + 0xA80, retaddr);
+    if (env->pkru != old_pkru) {
+        CPUState *cs = CPU(x86_env_get_cpu(env));
+        tlb_flush(cs, 1);
+    }
+}
+
 void helper_fxrstor(CPUX86State *env, target_ulong ptr)
 {
     /* The operand must be 16 byte aligned */
@@ -1357,6 +1399,10 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
             memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
         }
     }
+
+    if (rfbm & XSTATE_PKRU) {
+        do_xrstor_pkru(env, ptr, GETPC());
+    }
 }
 
 uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
diff --git a/target-i386/helper.c b/target-i386/helper.c
index f5f0bec..a55628f 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -689,6 +689,16 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
         hflags |= HF_SMAP_MASK;
     }
 
+    if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) {
+        new_cr4 &= ~CR4_PKE_MASK;
+    }
+    env->hflags &= ~HF_PKE_MASK;
+    env->features[FEAT_7_0_ECX] &= ~CPUID_7_0_ECX_OSPKE;
+    if (new_cr4 & CR4_PKE_MASK) {
+        env->hflags |= HF_PKE_MASK;
+	env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_OSPKE;
+    }
+
     env->cr[4] = new_cr4;
     env->hflags = hflags;
     return;
@@ -935,6 +945,24 @@ do_check_protect_pse36:
         goto do_fault_protect;
     }
 
+    if ((env->cr[4] & CR4_PKE_MASK) && (env->hflags & HF_LMA_MASK) &&
+        (ptep & PG_USER_MASK) && env->pkru) {
+        uint32_t pk = (pte & PG_PKRU_MASK) >> PG_PKRU_BIT;
+        uint32_t pkru_ad = (env->pkru >> pk * 2) & 1;
+        uint32_t pkru_wd = (env->pkru >> pk * 2) & 2;
+
+        if (pkru_ad) {
+            prot &= ~(PAGE_READ | PAGE_WRITE);
+        } else if (pkru_wd && (is_user || env->cr[0] & CR0_WP_MASK)) {
+            prot &= ~PAGE_WRITE;
+        }
+        if ((prot & (1 << is_write1)) == 0) {
+            assert(is_write1 != 2);
+            error_code |= PG_ERROR_PK_MASK;
+            goto do_fault_protect;
+        }
+    }
+
     /* yes, it can! */
     is_dirty = is_write && !(pte & PG_DIRTY_MASK);
     if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
diff --git a/target-i386/helper.h b/target-i386/helper.h
index 9a83955..89af181 100644
--- a/target-i386/helper.h
+++ b/target-i386/helper.h
@@ -79,6 +79,8 @@ DEF_HELPER_1(rdtscp, void, env)
 DEF_HELPER_1(rdpmc, void, env)
 DEF_HELPER_1(rdmsr, void, env)
 DEF_HELPER_1(wrmsr, void, env)
+DEF_HELPER_1(rdpkru, void, env)
+DEF_HELPER_1(wrpkru, void, env)
 
 DEF_HELPER_2(check_iob, void, env, i32)
 DEF_HELPER_2(check_iow, void, env, i32)
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 460257f..b517559 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -600,3 +600,35 @@ void helper_debug(CPUX86State *env)
     cs->exception_index = EXCP_DEBUG;
     cpu_loop_exit(cs);
 }
+
+void helper_rdpkru(CPUX86State *env)
+{
+    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
+        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
+        return;
+    }
+    if (env->regs[R_ECX] != 0) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+        return;
+    }
+
+    env->regs[R_EAX] = env->pkru;
+    env->regs[R_EDX] = 0;
+}
+
+void helper_wrpkru(CPUX86State *env)
+{
+    CPUState *cs = CPU(x86_env_get_cpu(env));
+
+    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
+        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
+        return;
+    }
+    if (env->regs[R_ECX] != 0) {
+        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
+        return;
+    }
+
+    env->pkru = env->regs[R_EAX];
+    tlb_flush(cs, 1);
+}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index b84ce3b..e2726d4 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7262,6 +7262,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
 #endif
             gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 1);
             break;
+        case 0xee: /* rdpkru */
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_rdpkru(cpu_env);
+            break;
+        case 0xef: /* wrpkru */
+            gen_update_cc_op(s);
+            gen_jmp_im(pc_start - s->cs_base);
+            gen_helper_wrpkru(cpu_env);
+            break;
         CASE_MEM_OP(6): /* lmsw */
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-- 
2.5.0

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE
  2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
                   ` (4 preceding siblings ...)
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG Paolo Bonzini
@ 2016-02-09 17:43 ` Richard Henderson
  2016-02-09 18:14   ` Paolo Bonzini
  5 siblings, 1 reply; 11+ messages in thread
From: Richard Henderson @ 2016-02-09 17:43 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel

On 02/10/2016 04:13 AM, Paolo Bonzini wrote:
> The bulk of these patches were posted by Richard several months ago; I
> have only refreshed them and made them pass kvm-unit-tests.  They also
> pass a quick Fedora 21 boot-test.

I have done some work on them since then, incorporating the feedback you gave, 
as well as tidying up the decoding of the xsave instructions themselves.  I'll 
post it again in a moment.


r~

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG
  2016-02-09 17:13 ` [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG Paolo Bonzini
@ 2016-02-09 18:13   ` Richard Henderson
  2016-02-17 10:33     ` Paolo Bonzini
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Henderson @ 2016-02-09 18:13 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel

On 02/10/2016 04:13 AM, Paolo Bonzini wrote:
> @@ -157,6 +157,7 @@
>   #define HF_SMAP_SHIFT       23 /* CR4.SMAP */
>   #define HF_IOBPT_SHIFT      24 /* an io breakpoint enabled */
>   #define HF_OSXSAVE_SHIFT    25 /* CR4.OSXSAVE */
> +#define HF_PKE_SHIFT        26 /* CR4.PKE enabled */

I don't believe you need this bit at all.  Certainly you don't use it in 
translate.c, where any such test ought to have been.

>   static uint64_t get_xinuse(CPUX86State *env)
>   {
> -    /* We don't track XINUSE.  We could calculate it here, but it's
> -       probably less work to simply indicate all components in use.  */
> -    return -1;
> +    uint64_t inuse = -1;
> +
> +    /* For the most part, we don't track XINUSE.  We could calculate it
> +     * here for all components, but it's probably less work to simply
> +     * indicate in use.  That said, for state that is important
> +     * enough to track in HFLAGS, we might as well use that here.
> +     */
> +    if ((env->hflags & HF_PKE_MASK) == 0) {
> +       inuse &= ~XSTATE_PKRU;
> +    }
> +    return inuse;
> +}

That does change this of course.  But the entire state of the feature is one 
32-bit integer -- it's just as easy to test that.

> @@ -1357,6 +1399,10 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
>               memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
>           }
>       }
> +
> +    if (rfbm & XSTATE_PKRU) {
> +        do_xrstor_pkru(env, ptr, GETPC());
> +    }

There should be an "ra" variable at the top of this function that already holds 
GETPC.  Are you forgetting a check on xstate_bv here, to clear pkru?

> diff --git a/target-i386/helper.c b/target-i386/helper.c
> index f5f0bec..a55628f 100644
> --- a/target-i386/helper.c
> +++ b/target-i386/helper.c
> @@ -689,6 +689,16 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
>           hflags |= HF_SMAP_MASK;
>       }
>
> +    if (!(env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKU)) {
> +        new_cr4 &= ~CR4_PKE_MASK;
> +    }
> +    env->hflags &= ~HF_PKE_MASK;
> +    env->features[FEAT_7_0_ECX] &= ~CPUID_7_0_ECX_OSPKE;
> +    if (new_cr4 & CR4_PKE_MASK) {
> +        env->hflags |= HF_PKE_MASK;
> +	env->features[FEAT_7_0_ECX] |= CPUID_7_0_ECX_OSPKE;
> +    }

Don't change features bits.  Do this test in cpu_x86_cpuid instead.  See where 
we give the same treatment to OSXSAVE.

> diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
> index 460257f..b517559 100644
> --- a/target-i386/misc_helper.c
> +++ b/target-i386/misc_helper.c
> @@ -600,3 +600,35 @@ void helper_debug(CPUX86State *env)
>       cs->exception_index = EXCP_DEBUG;
>       cpu_loop_exit(cs);
>   }
> +
> +void helper_rdpkru(CPUX86State *env)
> +{
> +    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
> +        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
> +        return;
> +    }

The document I have says #GP for this case, not #UD.

> +    if (env->regs[R_ECX] != 0) {
> +        raise_exception_err_ra(env, EXCP0D_GPF, 0, GETPC());
> +        return;
> +    }

In 64-bit mode, ecx 63:32 are ignored.

> +
> +    env->regs[R_EAX] = env->pkru;
> +    env->regs[R_EDX] = 0;
> +}

It would be better to return a 64-bit value, split and assign it to eax:edx in 
the translator, so that this function does not modify tcg registers.

> +
> +void helper_wrpkru(CPUX86State *env)
> +{
> +    CPUState *cs = CPU(x86_env_get_cpu(env));
> +
> +    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
> +        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
> +        return;
> +    }

Similarly.

> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index b84ce3b..e2726d4 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -7262,6 +7262,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
>   #endif
>               gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 1);
>               break;
> +        case 0xee: /* rdpkru */
> +            gen_update_cc_op(s);
> +            gen_jmp_im(pc_start - s->cs_base);
> +            gen_helper_rdpkru(cpu_env);
> +            break;

No need for either update_cc_op or gen_jmp_im, now that we've got 
raise_exception_err_ra.

Missing check for lock prefix.

If you make the change to return a 64-bit value, this would look like

   gen_helper_rdpkru(cpu_tmp1_i64, cpu_env);
   tcg_gen_extr_i64_tl(cpu_regs[REG_EAX], cpu_regs[REG_EDX], cpu_tmp1_i64);


> +        case 0xef: /* wrpkru */
> +            gen_update_cc_op(s);
> +            gen_jmp_im(pc_start - s->cs_base);
> +            gen_helper_wrpkru(cpu_env);
> +            break;
>           CASE_MEM_OP(6): /* lmsw */
>               if (s->cpl != 0) {
>                   gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
>



r~

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE
  2016-02-09 17:43 ` [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Richard Henderson
@ 2016-02-09 18:14   ` Paolo Bonzini
  2016-02-09 18:25     ` Richard Henderson
  0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-09 18:14 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel



On 09/02/2016 18:43, Richard Henderson wrote:
> On 02/10/2016 04:13 AM, Paolo Bonzini wrote:
>> The bulk of these patches were posted by Richard several months ago; I
>> have only refreshed them and made them pass kvm-unit-tests.  They also
>> pass a quick Fedora 21 boot-test.
> 
> I have done some work on them since then, incorporating the feedback you
> gave, as well as tidying up the decoding of the xsave instructions
> themselves.  I'll post it again in a moment.

Ok, the changes I made for kvm-unit-tests to pass were really minimal,
so I can build on top of your version.  Feel free to send a pull request
for XSAVE and MPX support; I won't really have time to review them in
depth soon, but I'll be able to fix myself any bugs exposed by the unit
tests.

Thanks,

Paolo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE
  2016-02-09 18:14   ` Paolo Bonzini
@ 2016-02-09 18:25     ` Richard Henderson
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2016-02-09 18:25 UTC (permalink / raw)
  To: Paolo Bonzini, qemu-devel

On 02/10/2016 05:14 AM, Paolo Bonzini wrote:
>> I have done some work on them since then, incorporating the feedback you
>> gave, as well as tidying up the decoding of the xsave instructions
>> themselves.  I'll post it again in a moment.
>
> Ok, the changes I made for kvm-unit-tests to pass were really minimal,
> so I can build on top of your version.  Feel free to send a pull request
> for XSAVE and MPX support; I won't really have time to review them in
> depth soon, but I'll be able to fix myself any bugs exposed by the unit
> tests.

Ok, I'll do that as soon as your current pull request lands.


r~

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG
  2016-02-09 18:13   ` Richard Henderson
@ 2016-02-17 10:33     ` Paolo Bonzini
  0 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2016-02-17 10:33 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel



On 09/02/2016 19:13, Richard Henderson wrote:
>>
>> +{
>> +    if ((env->cr[4] & CR4_PKE_MASK) == 0) {
>> +        raise_exception_err_ra(env, EXCP06_ILLOP, 0, GETPC());
>> +        return;
>> +    }
> 
> The document I have says #GP for this case, not #UD.

The text says #GP, the "Protected Mode Exceptions" section says #UD. :(

I think #UD is more likely, as it's similar to XSAVE.

> If you make the change to return a 64-bit value, this would look like
> 
>   gen_helper_rdpkru(cpu_tmp1_i64, cpu_env);
>   tcg_gen_extr_i64_tl(cpu_regs[REG_EAX], cpu_regs[REG_EDX], cpu_tmp1_i64); 

Yup, I can steal all that's needed from xgetbv and xsetbv.

Paolo

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2016-02-17 10:34 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-09 17:13 [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Paolo Bonzini
2016-02-09 17:13 ` [Qemu-devel] [PATCH 1/5] target-i386: Split fxsave/fxrstor implementation Paolo Bonzini
2016-02-09 17:13 ` [Qemu-devel] [PATCH 2/5] target-i386: Rearrange processing of 0F 01 Paolo Bonzini
2016-02-09 17:13 ` [Qemu-devel] [PATCH 3/5] target-i386: Add XSAVE extension Paolo Bonzini
2016-02-09 17:13 ` [Qemu-devel] [PATCH 4/5] target-i386: Implement XSAVEOPT Paolo Bonzini
2016-02-09 17:13 ` [Qemu-devel] [PATCH 5/5] target-i386: implement PKE for TCG Paolo Bonzini
2016-02-09 18:13   ` Richard Henderson
2016-02-17 10:33     ` Paolo Bonzini
2016-02-09 17:43 ` [Qemu-devel] [PATCH 0/5] TCG support for XSAVE and PKE Richard Henderson
2016-02-09 18:14   ` Paolo Bonzini
2016-02-09 18:25     ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).