aboutsummaryrefslogtreecommitdiff
path: root/target-i386/translate.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2006-07-10 19:53:04 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2006-07-10 19:53:04 +0000
commit3d7374c5dab5670891e34d6f5752d6c3e23259dc (patch)
tree9eadbbcd05302aebe1a5522fee441608b2364faa /target-i386/translate.c
parent4f2092904d80257dfc9be7569cdf58ffbe0182a8 (diff)
monitor/mwait support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2044 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-i386/translate.c')
-rw-r--r--target-i386/translate.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c
index c61f964c07..f905f323dd 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, &reg_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, &reg_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;