Commit 3d7374c5dab5670891e34d6f5752d6c3e23259dc

Authored by bellard
1 parent 4f209290

monitor/mwait support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2044 c046a42c-6fe2-441c-8c8c-71466251a162
target-i386/exec.h
... ... @@ -496,6 +496,9 @@ void save_native_fp_state(CPUState *env);
496 496 float approx_rsqrt(float a);
497 497 float approx_rcp(float a);
498 498 void update_fp_status(void);
  499 +void helper_hlt(void);
  500 +void helper_monitor(void);
  501 +void helper_mwait(void);
499 502  
500 503 extern const uint8_t parity_table[256];
501 504 extern const uint8_t rclw_table[32];
... ...
target-i386/helper.c
... ... @@ -3408,6 +3408,34 @@ void helper_bswapq_T0(void)
3408 3408 }
3409 3409 #endif
3410 3410  
  3411 +void helper_hlt(void)
  3412 +{
  3413 + env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
  3414 + env->hflags |= HF_HALTED_MASK;
  3415 + env->exception_index = EXCP_HLT;
  3416 + cpu_loop_exit();
  3417 +}
  3418 +
  3419 +void helper_monitor(void)
  3420 +{
  3421 + if (ECX != 0)
  3422 + raise_exception(EXCP0D_GPF);
  3423 + /* XXX: store address ? */
  3424 +}
  3425 +
  3426 +void helper_mwait(void)
  3427 +{
  3428 + if (ECX != 0)
  3429 + raise_exception(EXCP0D_GPF);
  3430 + /* XXX: not complete but not completely erroneous */
  3431 + if (env->cpu_index != 0 || env->next_cpu != NULL) {
  3432 + /* more than one CPU: do not sleep because another CPU may
  3433 + wake this one */
  3434 + } else {
  3435 + helper_hlt();
  3436 + }
  3437 +}
  3438 +
3411 3439 float approx_rsqrt(float a)
3412 3440 {
3413 3441 return 1.0 / sqrt(a);
... ...
target-i386/op.c
... ... @@ -614,10 +614,17 @@ void OPPROTO op_movq_eip_im64(void)
614 614  
615 615 void OPPROTO op_hlt(void)
616 616 {
617   - env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
618   - env->hflags |= HF_HALTED_MASK;
619   - env->exception_index = EXCP_HLT;
620   - cpu_loop_exit();
  617 + helper_hlt();
  618 +}
  619 +
  620 +void OPPROTO op_monitor(void)
  621 +{
  622 + helper_monitor();
  623 +}
  624 +
  625 +void OPPROTO op_mwait(void)
  626 +{
  627 + helper_mwait();
621 628 }
622 629  
623 630 void OPPROTO op_debug(void)
... ...
target-i386/translate.c
... ... @@ -100,6 +100,7 @@ typedef struct DisasContext {
100 100 int popl_esp_hack; /* for correct popl with esp base handling */
101 101 int rip_offset; /* only used in x86_64, but left for simplicity */
102 102 int cpuid_features;
  103 + int cpuid_ext_features;
103 104 } DisasContext;
104 105  
105 106 static void gen_eob(DisasContext *s);
... ... @@ -5567,26 +5568,69 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
5567 5568 modrm = ldub_code(s->pc++);
5568 5569 mod = (modrm >> 6) & 3;
5569 5570 op = (modrm >> 3) & 7;
  5571 + rm = modrm & 7;
5570 5572 switch(op) {
5571 5573 case 0: /* sgdt */
5572   - case 1: /* sidt */
5573 5574 if (mod == 3)
5574 5575 goto illegal_op;
5575 5576 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
5576   - if (op == 0)
5577   - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
5578   - else
5579   - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
  5577 + gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit));
5580 5578 gen_op_st_T0_A0[OT_WORD + s->mem_index]();
5581 5579 gen_add_A0_im(s, 2);
5582   - if (op == 0)
5583   - gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base));
5584   - else
5585   - gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base));
  5580 + gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base));
5586 5581 if (!s->dflag)
5587 5582 gen_op_andl_T0_im(0xffffff);
5588 5583 gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
5589 5584 break;
  5585 + case 1:
  5586 + if (mod == 3) {
  5587 + switch (rm) {
  5588 + case 0: /* monitor */
  5589 + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
  5590 + s->cpl != 0)
  5591 + goto illegal_op;
  5592 + gen_jmp_im(pc_start - s->cs_base);
  5593 +#ifdef TARGET_X86_64
  5594 + if (s->aflag == 2) {
  5595 + gen_op_movq_A0_reg[R_EBX]();
  5596 + gen_op_addq_A0_AL();
  5597 + } else
  5598 +#endif
  5599 + {
  5600 + gen_op_movl_A0_reg[R_EBX]();
  5601 + gen_op_addl_A0_AL();
  5602 + if (s->aflag == 0)
  5603 + gen_op_andl_A0_ffff();
  5604 + }
  5605 + gen_add_A0_ds_seg(s);
  5606 + gen_op_monitor();
  5607 + break;
  5608 + case 1: /* mwait */
  5609 + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
  5610 + s->cpl != 0)
  5611 + goto illegal_op;
  5612 + if (s->cc_op != CC_OP_DYNAMIC) {
  5613 + gen_op_set_cc_op(s->cc_op);
  5614 + s->cc_op = CC_OP_DYNAMIC;
  5615 + }
  5616 + gen_jmp_im(s->pc - s->cs_base);
  5617 + gen_op_mwait();
  5618 + gen_eob(s);
  5619 + break;
  5620 + default:
  5621 + goto illegal_op;
  5622 + }
  5623 + } else { /* sidt */
  5624 + gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
  5625 + gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit));
  5626 + gen_op_st_T0_A0[OT_WORD + s->mem_index]();
  5627 + gen_add_A0_im(s, 2);
  5628 + gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base));
  5629 + if (!s->dflag)
  5630 + gen_op_andl_T0_im(0xffffff);
  5631 + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
  5632 + }
  5633 + break;
5590 5634 case 2: /* lgdt */
5591 5635 case 3: /* lidt */
5592 5636 if (mod == 3)
... ... @@ -5629,7 +5673,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
5629 5673 } else {
5630 5674 if (mod == 3) {
5631 5675 #ifdef TARGET_X86_64
5632   - if (CODE64(s) && (modrm & 7) == 0) {
  5676 + if (CODE64(s) && rm == 0) {
5633 5677 /* swapgs */
5634 5678 gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base));
5635 5679 gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase));
... ... @@ -6348,6 +6392,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
6348 6392 dc->mem_index = 1 * 4;
6349 6393 }
6350 6394 dc->cpuid_features = env->cpuid_features;
  6395 + dc->cpuid_ext_features = env->cpuid_ext_features;
6351 6396 #ifdef TARGET_X86_64
6352 6397 dc->lma = (flags >> HF_LMA_SHIFT) & 1;
6353 6398 dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
... ...