diff options
-rw-r--r-- | target-i386/exec.h | 3 | ||||
-rw-r--r-- | target-i386/helper.c | 28 | ||||
-rw-r--r-- | target-i386/op.c | 15 | ||||
-rw-r--r-- | target-i386/translate.c | 65 |
4 files changed, 97 insertions, 14 deletions
diff --git a/target-i386/exec.h b/target-i386/exec.h index 4ff527f..609a586 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -496,6 +496,9 @@ void save_native_fp_state(CPUState *env); float approx_rsqrt(float a); float approx_rcp(float a); void update_fp_status(void); +void helper_hlt(void); +void helper_monitor(void); +void helper_mwait(void); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/target-i386/helper.c b/target-i386/helper.c index d7b41ea..70e9fae 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -3408,6 +3408,34 @@ void helper_bswapq_T0(void) } #endif +void helper_hlt(void) +{ + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ + env->hflags |= HF_HALTED_MASK; + env->exception_index = EXCP_HLT; + cpu_loop_exit(); +} + +void helper_monitor(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: store address ? */ +} + +void helper_mwait(void) +{ + if (ECX != 0) + raise_exception(EXCP0D_GPF); + /* XXX: not complete but not completely erroneous */ + if (env->cpu_index != 0 || env->next_cpu != NULL) { + /* more than one CPU: do not sleep because another CPU may + wake this one */ + } else { + helper_hlt(); + } +} + float approx_rsqrt(float a) { return 1.0 / sqrt(a); diff --git a/target-i386/op.c b/target-i386/op.c index a9a8665..7a3aa77 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -614,10 +614,17 @@ void OPPROTO op_movq_eip_im64(void) void OPPROTO op_hlt(void) { - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ - env->hflags |= HF_HALTED_MASK; - env->exception_index = EXCP_HLT; - cpu_loop_exit(); + helper_hlt(); +} + +void OPPROTO op_monitor(void) +{ + helper_monitor(); +} + +void OPPROTO op_mwait(void) +{ + helper_mwait(); } void OPPROTO op_debug(void) diff --git a/target-i386/translate.c b/target-i386/translate.c index c61f964..f905f32 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -100,6 +100,7 @@ typedef struct DisasContext { int popl_esp_hack; /* for correct popl with esp base handling */ int rip_offset; /* only used in x86_64, but left for simplicity */ int cpuid_features; + int cpuid_ext_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -5567,26 +5568,69 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; + rm = modrm & 7; switch(op) { case 0: /* sgdt */ - case 1: /* sidt */ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); gen_add_A0_im(s, 2); - if (op == 0) - gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); - else - gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); 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_jmp_im(pc_start - s->cs_base); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[R_EBX](); + gen_op_addq_A0_AL(); + } else +#endif + { + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + gen_op_monitor(); + break; + case 1: /* mwait */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(s->pc - s->cs_base); + gen_op_mwait(); + gen_eob(s); + break; + default: + goto illegal_op; + } + } else { /* sidt */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_add_A0_im(s, 2); + gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + } + break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) @@ -5629,7 +5673,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { if (mod == 3) { #ifdef TARGET_X86_64 - if (CODE64(s) && (modrm & 7) == 0) { + if (CODE64(s) && rm == 0) { /* swapgs */ gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); @@ -6348,6 +6392,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 1 * 4; } dc->cpuid_features = env->cpuid_features; + dc->cpuid_ext_features = env->cpuid_ext_features; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1; |