diff --git a/target-i386/helper.h b/target-i386/helper.h index d6974dfd6b3b0902c596904ca389853bc0275ed2..3775abeba78fde6dac4590a767b49b645dd04b18 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -58,6 +58,7 @@ DEF_HELPER_2(sysret, void, env, int) DEF_HELPER_2(hlt, void, env, int) DEF_HELPER_2(monitor, void, env, tl) DEF_HELPER_2(mwait, void, env, int) +DEF_HELPER_2(pause, void, env, int) DEF_HELPER_1(debug, void, env) DEF_HELPER_1(reset_rf, void, env) DEF_HELPER_3(raise_interrupt, void, env, int, int) diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 93933fd1628d2048b7ddf437409282f3072b738a..b6307ca3862e2d5a9c993a0bc7c90352ad26218a 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -566,6 +566,15 @@ void helper_rdmsr(CPUX86State *env) } #endif +static void do_pause(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + /* Just let another CPU run. */ + env->exception_index = EXCP_INTERRUPT; + cpu_loop_exit(env); +} + static void do_hlt(X86CPU *cpu) { CPUState *cs = CPU(cpu); @@ -611,13 +620,22 @@ void helper_mwait(CPUX86State *env, int next_eip_addend) cs = CPU(cpu); /* XXX: not complete but not completely erroneous */ if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) { - /* more than one CPU: do not sleep because another CPU may - wake this one */ + do_pause(cpu); } else { do_hlt(cpu); } } +void helper_pause(CPUX86State *env, int next_eip_addend) +{ + X86CPU *cpu = x86_env_get_cpu(env); + + cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0); + env->eip += next_eip_addend; + + do_pause(cpu); +} + void helper_debug(CPUX86State *env) { env->exception_index = EXCP_DEBUG; diff --git a/target-i386/translate.c b/target-i386/translate.c index eb0ea93dbbd4aa0bc2c7f337a869f3562254ab66..ecf16b389b755fdd14ca3257a0a2236cd4be6521 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7224,7 +7224,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, goto do_xchg_reg_eax; } if (prefixes & PREFIX_REPZ) { - gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE); + gen_update_cc_op(s); + gen_jmp_im(pc_start - s->cs_base); + gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start)); + s->is_jmp = DISAS_TB_JUMP; } break; case 0x9b: /* fwait */