@@ -42,9 +42,8 @@ DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
DEF_HELPER_2(iret_real, void, env, int)
DEF_HELPER_3(iret_protected, void, env, int, int)
DEF_HELPER_3(lret_protected, void, env, int, int)
-DEF_HELPER_2(read_crN, tl, env, int)
-DEF_HELPER_3(write_crN, void, env, int, tl)
-DEF_HELPER_2(lmsw, void, env, tl)
+DEF_HELPER_FLAGS_2(read_crN, TCG_CALL_NO_RWG, tl, env, int)
+DEF_HELPER_FLAGS_3(write_crN, TCG_CALL_NO_RWG, void, env, int, tl)
DEF_HELPER_1(clts, void, env)
#ifndef CONFIG_USER_ONLY
@@ -60,14 +60,6 @@ void helper_cpuid(CPUX86State *env)
env->regs[R_EDX] = edx;
}
-void helper_lmsw(CPUX86State *env, target_ulong t0)
-{
- /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
- if already set to one. */
- t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
- helper_write_crN(env, 0, t0);
-}
-
void helper_invlpg(CPUX86State *env, target_ulong addr)
{
X86CPU *cpu = env_archcpu(env);
@@ -65,7 +65,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
{
target_ulong val;
- cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
switch (reg) {
default:
val = env->cr[reg];
@@ -83,7 +82,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
{
- cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
switch (reg) {
case 0:
cpu_x86_update_cr0(env, t0);
@@ -7654,13 +7654,22 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64);
break;
+
CASE_MODRM_OP(6): /* lmsw */
if (!check_cpl0(s)) {
break;
}
gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
- gen_helper_lmsw(cpu_env, s->T0);
+ /*
+ * Only the 4 lower bits of CR0 are modified.
+ * PE cannot be set to zero if already set to one.
+ */
+ tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0]));
+ tcg_gen_andi_tl(s->T0, s->T0, 0xf);
+ tcg_gen_andi_tl(s->T1, s->T1, ~0xe);
+ tcg_gen_or_tl(s->T0, s->T0, s->T1);
+ gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0);
gen_jmp_im(s, s->pc - s->cs_base);
gen_eob(s);
break;
@@ -8034,58 +8043,56 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
modrm = x86_ldub_code(env, s);
gen_nop_modrm(env, s, modrm);
break;
+
case 0x120: /* mov reg, crN */
case 0x122: /* mov crN, reg */
- if (check_cpl0(s)) {
- modrm = x86_ldub_code(env, s);
- /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
- * AMD documentation (24594.pdf) and testing of
- * intel 386 and 486 processors all show that the mod bits
- * are assumed to be 1's, regardless of actual values.
- */
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | REX_R(s);
- if (CODE64(s))
- ot = MO_64;
- else
- ot = MO_32;
- if ((prefixes & PREFIX_LOCK) && (reg == 0) &&
+ if (!check_cpl0(s)) {
+ break;
+ }
+ modrm = x86_ldub_code(env, s);
+ /*
+ * Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of Intel 386 and 486
+ * processors all show that the mod bits are assumed to be 1's,
+ * regardless of actual values.
+ */
+ rm = (modrm & 7) | REX_B(s);
+ reg = ((modrm >> 3) & 7) | REX_R(s);
+ switch (reg) {
+ case 0:
+ if ((prefixes & PREFIX_LOCK) &&
(s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) {
reg = 8;
}
- switch(reg) {
- case 0:
- case 2:
- case 3:
- case 4:
- case 8:
- gen_update_cc_op(s);
- gen_jmp_im(s, pc_start - s->cs_base);
- if (b & 2) {
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_op_mov_v_reg(s, ot, s->T0, rm);
- gen_helper_write_crN(cpu_env, tcg_const_i32(reg),
- s->T0);
- gen_jmp_im(s, s->pc - s->cs_base);
- gen_eob(s);
- } else {
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_io_start();
- }
- gen_helper_read_crN(s->T0, cpu_env, tcg_const_i32(reg));
- gen_op_mov_reg_v(s, ot, rm, s->T0);
- if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
- gen_jmp(s, s->pc - s->cs_base);
- }
- }
- break;
- default:
- goto unknown_op;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ goto unknown_op;
+ }
+ ot = (CODE64(s) ? MO_64 : MO_32);
+
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ if (b & 2) {
+ gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg);
+ gen_op_mov_v_reg(s, ot, s->T0, rm);
+ gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0);
+ gen_jmp_im(s, s->pc - s->cs_base);
+ gen_eob(s);
+ } else {
+ gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg);
+ gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg));
+ gen_op_mov_reg_v(s, ot, rm, s->T0);
+ if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
+ gen_jmp(s, s->pc - s->cs_base);
}
}
break;
+
case 0x121: /* mov reg, drN */
case 0x123: /* mov drN, reg */
if (check_cpl0(s)) {
Pull the svm intercept check into the translator. Pull the entire implementation of lmsw into the translator. Push the check for CR8LEG into the regno validation switch. Unify the gen_io_start check between read/write. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/i386/helper.h | 5 +- target/i386/tcg/misc_helper.c | 8 --- target/i386/tcg/sysemu/misc_helper.c | 2 - target/i386/tcg/translate.c | 97 +++++++++++++++------------- 4 files changed, 54 insertions(+), 58 deletions(-) -- 2.25.1