From c50c0c3fbf65ce7a1cf42a2ea8974a930be7b667 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 10 May 2003 15:07:51 +0000 Subject: [PATCH] TF flag support - fixed eflags computation before exception git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@145 c046a42c-6fe2-441c-8c8c-71466251a162 --- translate-i386.c | 69 +++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/translate-i386.c b/translate-i386.c index ba36bedf9..da58a052e 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -132,6 +132,7 @@ typedef struct DisasContext { int vm86; /* vm86 mode */ int cpl; int iopl; + int tf; /* TF cpu flag */ } DisasContext; /* i386 arith/logic operations */ @@ -1366,6 +1367,15 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_mov_reg_T1[ot][R_ESP](); } +static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_exception(trapno); + s->is_jmp = 1; +} + /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr is set to true if the instruction sets the PC (last instruction of a basic block) */ @@ -2770,8 +2780,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x6d: if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2788,8 +2797,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x6f: if (s->cpl > s->iopl || s->vm86) { /* NOTE: even for (E)CX = 0 the exception is raised */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2808,8 +2816,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe4: case 0xe5: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2824,8 +2831,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xe6: case 0xe7: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2840,8 +2846,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xec: case 0xed: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2855,8 +2860,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0xee: case 0xef: if (s->cpl > s->iopl || s->vm86) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if ((b & 1) == 0) ot = OT_BYTE; @@ -2928,8 +2932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xcf: /* iret */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { /* XXX: not restartable */ /* pop offset */ @@ -3066,8 +3069,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* flags */ case 0x9c: /* pushf */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); @@ -3077,8 +3079,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x9d: /* popf */ if (s->vm86 && s->iopl != 3) { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_pop_T0(s); if (s->dflag) { @@ -3248,11 +3249,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x90: /* nop */ break; case 0xcc: /* int3 */ - gen_op_int3((long)pc_start); - s->is_jmp = 1; + gen_exception(s, EXCP03_INT3, pc_start - s->cs_base); break; case 0xcd: /* int N */ val = ldub(s->pc++); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_int_im(val, pc_start - s->cs_base); s->is_jmp = 1; break; @@ -3266,15 +3268,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl <= s->iopl) { gen_op_cli(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_op_cli(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; @@ -3283,15 +3283,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) if (s->cpl <= s->iopl) { gen_op_sti(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } else { if (s->iopl == 3) { gen_op_sti(); } else { - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } } break; @@ -3343,8 +3341,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xf4: /* hlt */ /* XXX: if cpl == 0, then should do something else */ - gen_op_gpf(pc_start - s->cs_base); - s->is_jmp = 1; + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); break; default: goto illegal_op; @@ -3453,7 +3450,6 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, [INDEX_op_movl_T0_eflags] = CC_OSZAPC, - [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC, [INDEX_op_cmc] = CC_C, [INDEX_op_salc] = CC_C, @@ -3504,9 +3500,7 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, [INDEX_op_movw_eflags_T0] = CC_OSZAPC, - [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_movl_eflags_T0] = CC_OSZAPC, - [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC, [INDEX_op_clc] = CC_C, [INDEX_op_stc] = CC_C, [INDEX_op_cmc] = CC_C, @@ -3726,6 +3720,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; + dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; dc->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3747,6 +3742,10 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, break; } pc_ptr = (void *)ret; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (dc->tf) + break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end); /* we must store the eflags state if it is not already done */ if (dc->cc_op != CC_OP_DYNAMIC) @@ -3755,6 +3754,10 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, /* we add an additionnal jmp to update the simulated PC */ gen_op_jmp_im(ret - (unsigned long)dc->cs_base); } + if (dc->tf) { + gen_op_raise_exception(EXCP01_SSTP); + } + *gen_opc_ptr = INDEX_op_end; #ifdef DEBUG_DISAS