aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-11-13 01:43:28 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-11-13 01:43:28 +0000
commitf115e911d70dedbbab90efe589b267bf53178f10 (patch)
tree793523813eb82a66cace65c90aee663b8b70d3c0
parent3ab493de4c524926bb75b04765b644f9189ccf01 (diff)
iret and int fix for vm86 - added undefined instructions for real and vm86 modes - added verr, verrw, arpl - added port io map
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--target-i386/translate.c230
1 files changed, 142 insertions, 88 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c
index ab4fe09e6b..7ce8f4bdee 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = {
gen_op_outl_DX_T0,
};
+static GenOpFunc *gen_op_in[3] = {
+ gen_op_inb_T0_T1,
+ gen_op_inw_T0_T1,
+ gen_op_inl_T0_T1,
+};
+
+static GenOpFunc *gen_op_out[3] = {
+ gen_op_outb_T0_T1,
+ gen_op_outw_T0_T1,
+ gen_op_outl_T0_T1,
+};
+
+static GenOpFunc *gen_check_io_T0[3] = {
+ gen_op_check_iob_T0,
+ gen_op_check_iow_T0,
+ gen_op_check_iol_T0,
+};
+
+static GenOpFunc *gen_check_io_DX[3] = {
+ gen_op_check_iob_DX,
+ gen_op_check_iow_DX,
+ gen_op_check_iol_DX,
+};
+
+static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip)
+{
+ if (s->pe && (s->cpl > s->iopl || s->vm86)) {
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_jmp_im(cur_eip);
+ if (use_dx)
+ gen_check_io_DX[ot]();
+ else
+ gen_check_io_T0[ot]();
+ }
+}
+
static inline void gen_movs(DisasContext *s, int ot)
{
gen_string_movl_A0_ESI(s);
@@ -912,18 +949,6 @@ GEN_REPZ(outs)
GEN_REPZ2(scas)
GEN_REPZ2(cmps)
-static GenOpFunc *gen_op_in[3] = {
- gen_op_inb_T0_T1,
- gen_op_inw_T0_T1,
- gen_op_inl_T0_T1,
-};
-
-static GenOpFunc *gen_op_out[3] = {
- gen_op_outb_T0_T1,
- gen_op_outw_T0_T1,
- gen_op_outl_T0_T1,
-};
-
enum {
JCC_O,
JCC_B,
@@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 0x6c: /* insS */
case 0x6d:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- /* NOTE: even for (E)CX = 0 the exception is raised */
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ gen_check_io(s, ot, 1, pc_start - s->cs_base);
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+ gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_ins(s, ot);
- }
+ gen_ins(s, ot);
}
break;
case 0x6e: /* outsS */
case 0x6f:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- /* NOTE: even for (E)CX = 0 the exception is raised */
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ gen_check_io(s, ot, 1, pc_start - s->cs_base);
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+ gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_outs(s, ot);
- }
+ gen_outs(s, ot);
}
break;
@@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
/* port I/O */
case 0xe4:
case 0xe5:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
- gen_op_movl_T0_im(val);
- gen_op_in[ot]();
- gen_op_mov_reg_T1[ot][R_EAX]();
- }
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ val = ldub_code(s->pc++);
+ gen_op_movl_T0_im(val);
+ gen_check_io(s, ot, 0, pc_start - s->cs_base);
+ gen_op_in[ot]();
+ gen_op_mov_reg_T1[ot][R_EAX]();
break;
case 0xe6:
case 0xe7:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
- gen_op_movl_T0_im(val);
- gen_op_mov_TN_reg[ot][1][R_EAX]();
- gen_op_out[ot]();
- }
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ val = ldub_code(s->pc++);
+ gen_op_movl_T0_im(val);
+ gen_check_io(s, ot, 0, pc_start - s->cs_base);
+ gen_op_mov_TN_reg[ot][1][R_EAX]();
+ gen_op_out[ot]();
break;
case 0xec:
case 0xed:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- gen_exception(s, EXCP0D_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]();
- }
+ 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_check_io(s, ot, 0, pc_start - s->cs_base);
+ gen_op_in[ot]();
+ gen_op_mov_reg_T1[ot][R_EAX]();
break;
case 0xee:
case 0xef:
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- gen_exception(s, EXCP0D_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]();
- }
+ 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_check_io(s, ot, 0, pc_start - s->cs_base);
+ gen_op_mov_TN_reg[ot][1][R_EAX]();
+ gen_op_out[ot]();
break;
/************************/
@@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
/* real mode */
gen_op_iret_real(s->dflag);
s->cc_op = CC_OP_EFLAGS;
- } else if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else if (s->vm86) {
+ if (s->iopl != 3) {
+ gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_op_iret_real(s->dflag);
+ s->cc_op = CC_OP_EFLAGS;
+ }
} else {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
@@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 0xcd: /* int N */
val = ldub_code(s->pc++);
- /* XXX: add error code for vm86 GPF */
- if (!s->vm86)
- gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
- else
+ if (s->vm86 && s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+ } else {
+ gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
+ }
break;
case 0xce: /* into */
if (s->cc_op != CC_OP_DYNAMIC)
@@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
op = (modrm >> 3) & 7;
switch(op) {
case 0: /* sldt */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
ot = OT_WORD;
if (mod == 3)
@@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
break;
case 2: /* lldt */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
@@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
}
break;
case 1: /* str */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
ot = OT_WORD;
if (mod == 3)
@@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
break;
case 3: /* ltr */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
@@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 4: /* verr */
case 5: /* verw */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
+ gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ if (op == 4)
+ gen_op_verr();
+ else
+ gen_op_verw();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
default:
goto illegal_op;
}
@@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
goto illegal_op;
}
break;
+ case 0x63: /* arpl */
+ if (!s->pe || s->vm86)
+ goto illegal_op;
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub_code(s->pc++);
+ reg = (modrm >> 3) & 7;
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot + s->mem_index]();
+ } else {
+ gen_op_mov_TN_reg[ot][0][rm]();
+ }
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_arpl();
+ s->cc_op = CC_OP_EFLAGS;
+ if (mod != 3) {
+ gen_op_st_T0_A0[ot + s->mem_index]();
+ } else {
+ gen_op_mov_reg_T0[ot][rm]();
+ }
+ gen_op_arpl_update();
+ break;
case 0x102: /* lar */
case 0x103: /* lsl */
if (!s->pe || s->vm86)