* [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).