diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-05-08 15:44:24 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-05-08 15:44:24 +0000 |
commit | 982b431579c926712633f3d8254bae24b34a4d83 (patch) | |
tree | efdd2bbdc84d2c3f1c8589f74a608863fac28e54 /translate-i386.c | |
parent | bf7c65bdf482923f34c3cbb42bd93f10416e3025 (diff) |
added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@134 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r-- | translate-i386.c | 169 |
1 files changed, 112 insertions, 57 deletions
diff --git a/translate-i386.c b/translate-i386.c index 1cdad2d908..8ddf14e729 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -130,6 +130,8 @@ typedef struct DisasContext { int addseg; /* non zero if either DS/ES/SS have a non zero base */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ + int cpl; + int iopl; } DisasContext; /* i386 arith/logic operations */ @@ -2766,26 +2768,36 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0x6c: /* insS */ case 0x6d: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { - gen_string_es(s, ot, gen_op_ins + 9); + 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); } else { - gen_string_es(s, ot, gen_op_ins); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_string_es(s, ot, gen_op_ins + 9); + } else { + gen_string_es(s, ot, gen_op_ins); + } } break; case 0x6e: /* outsS */ case 0x6f: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - if (prefixes & PREFIX_REPZ) { - gen_string_ds(s, ot, gen_op_outs + 9); + 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); } else { - gen_string_ds(s, ot, gen_op_outs); + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPZ) { + gen_string_ds(s, ot, gen_op_outs + 9); + } else { + gen_string_ds(s, ot, gen_op_outs); + } } break; @@ -2793,45 +2805,61 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) /* port I/O */ case 0xe4: case 0xe5: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } break; case 0xe6: case 0xe7: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - val = ldub(s->pc++); - gen_op_movl_T0_im(val); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } break; case 0xec: case 0xed: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_in[ot](); - gen_op_mov_reg_T1[ot][R_EAX](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } break; case 0xee: case 0xef: - if ((b & 1) == 0) - ot = OT_BYTE; - else - ot = dflag ? OT_LONG : OT_WORD; - gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); - gen_op_mov_TN_reg[ot][1][R_EAX](); - gen_op_out[ot](); + if (s->cpl > s->iopl || s->vm86) { + gen_op_gpf(pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } break; /************************/ @@ -3219,8 +3247,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) break; case 0xcd: /* int N */ val = ldub(s->pc++); - /* XXX: currently we ignore the interrupt number */ - gen_op_int_im(pc_start - s->cs_base); + gen_op_int_im(val, pc_start - s->cs_base); s->is_jmp = 1; break; case 0xce: /* into */ @@ -3229,16 +3256,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) gen_op_into(); break; case 0xfa: /* cli */ - if (s->vm86) - gen_op_cli_vm(); - else - gen_op_cli(); + if (!s->vm86) { + if (s->cpl <= s->iopl) + gen_op_cli(); + else + gen_op_gpf(pc_start - s->cs_base); + } else { + if (s->iopl == 3) + gen_op_cli(); + else + gen_op_cli_vm(); + } break; case 0xfb: /* sti */ - if (s->vm86) - gen_op_sti_vm(pc_start - s->cs_base); - else - gen_op_sti(); + if (!s->vm86) { + if (s->cpl <= s->iopl) + gen_op_sti(); + else + gen_op_gpf(pc_start - s->cs_base); + } else { + if (s->iopl == 3) + gen_op_sti(); + else + gen_op_sti_vm(pc_start - s->cs_base); + } break; case 0x62: /* bound */ ot = dflag ? OT_LONG : OT_WORD; @@ -3286,6 +3327,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) case 0x1a2: /* cpuid */ gen_op_cpuid(); break; + case 0xf4: /* hlt */ + if (s->cpl == 0) { + /* ignored */ + } else { + gen_op_gpf(pc_start - s->cs_base); + } + break; default: goto illegal_op; } @@ -3315,6 +3363,10 @@ static uint16_t opc_read_flags[NB_OPS] = { [INDEX_op_sbbw_T0_T1_cc] = CC_C, [INDEX_op_sbbl_T0_T1_cc] = CC_C, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_incl_T0_cc] = CC_C, + [INDEX_op_decl_T0_cc] = CC_C, + [INDEX_op_into] = CC_O, [INDEX_op_jo_cc] = CC_O, @@ -3416,8 +3468,9 @@ static uint16_t opc_write_flags[NB_OPS] = { [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_negl_T0_cc] = CC_OSZAPC, - [INDEX_op_incl_T0_cc] = CC_OSZAP, - [INDEX_op_decl_T0_cc] = CC_OSZAP, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_incl_T0_cc] = CC_OSZAPC, + [INDEX_op_decl_T0_cc] = CC_OSZAPC, [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, [INDEX_op_mulb_AL_T0] = CC_OSZAPC, @@ -3659,6 +3712,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; 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->cc_op = CC_OP_DYNAMIC; dc->cs_base = cs_base; @@ -3697,7 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, disas(logfile, pc_start, pc_ptr - pc_start, dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086); fprintf(logfile, "\n"); - + fprintf(logfile, "OP:\n"); dump_ops(gen_opc_buf, gen_opparam_buf); fprintf(logfile, "\n"); |