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
This commit is contained in:
parent
3ab493de4c
commit
f115e911d7
|
@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = {
|
||||||
gen_op_outl_DX_T0,
|
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)
|
static inline void gen_movs(DisasContext *s, int ot)
|
||||||
{
|
{
|
||||||
gen_string_movl_A0_ESI(s);
|
gen_string_movl_A0_ESI(s);
|
||||||
|
@ -912,18 +949,6 @@ GEN_REPZ(outs)
|
||||||
GEN_REPZ2(scas)
|
GEN_REPZ2(scas)
|
||||||
GEN_REPZ2(cmps)
|
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 {
|
enum {
|
||||||
JCC_O,
|
JCC_O,
|
||||||
JCC_B,
|
JCC_B,
|
||||||
|
@ -3221,98 +3246,78 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
break;
|
break;
|
||||||
case 0x6c: /* insS */
|
case 0x6c: /* insS */
|
||||||
case 0x6d:
|
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);
|
|
||||||
} else {
|
|
||||||
if ((b & 1) == 0)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
|
gen_check_io(s, ot, 1, pc_start - s->cs_base);
|
||||||
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
|
||||||
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||||
} else {
|
} else {
|
||||||
gen_ins(s, ot);
|
gen_ins(s, ot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0x6e: /* outsS */
|
case 0x6e: /* outsS */
|
||||||
case 0x6f:
|
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);
|
|
||||||
} else {
|
|
||||||
if ((b & 1) == 0)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
|
gen_check_io(s, ot, 1, pc_start - s->cs_base);
|
||||||
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
|
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
|
||||||
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
|
||||||
} else {
|
} else {
|
||||||
gen_outs(s, ot);
|
gen_outs(s, ot);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/************************/
|
/************************/
|
||||||
/* port I/O */
|
/* port I/O */
|
||||||
case 0xe4:
|
case 0xe4:
|
||||||
case 0xe5:
|
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)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
val = ldub_code(s->pc++);
|
val = ldub_code(s->pc++);
|
||||||
gen_op_movl_T0_im(val);
|
gen_op_movl_T0_im(val);
|
||||||
|
gen_check_io(s, ot, 0, pc_start - s->cs_base);
|
||||||
gen_op_in[ot]();
|
gen_op_in[ot]();
|
||||||
gen_op_mov_reg_T1[ot][R_EAX]();
|
gen_op_mov_reg_T1[ot][R_EAX]();
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0xe6:
|
case 0xe6:
|
||||||
case 0xe7:
|
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)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
val = ldub_code(s->pc++);
|
val = ldub_code(s->pc++);
|
||||||
gen_op_movl_T0_im(val);
|
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_mov_TN_reg[ot][1][R_EAX]();
|
||||||
gen_op_out[ot]();
|
gen_op_out[ot]();
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0xec:
|
case 0xec:
|
||||||
case 0xed:
|
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)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
|
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_in[ot]();
|
||||||
gen_op_mov_reg_T1[ot][R_EAX]();
|
gen_op_mov_reg_T1[ot][R_EAX]();
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 0xee:
|
case 0xee:
|
||||||
case 0xef:
|
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)
|
if ((b & 1) == 0)
|
||||||
ot = OT_BYTE;
|
ot = OT_BYTE;
|
||||||
else
|
else
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
ot = dflag ? OT_LONG : OT_WORD;
|
||||||
gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
|
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_mov_TN_reg[ot][1][R_EAX]();
|
||||||
gen_op_out[ot]();
|
gen_op_out[ot]();
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/************************/
|
/************************/
|
||||||
|
@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
/* real mode */
|
/* real mode */
|
||||||
gen_op_iret_real(s->dflag);
|
gen_op_iret_real(s->dflag);
|
||||||
s->cc_op = CC_OP_EFLAGS;
|
s->cc_op = CC_OP_EFLAGS;
|
||||||
} else if (s->vm86 && s->iopl != 3) {
|
} else if (s->vm86) {
|
||||||
|
if (s->iopl != 3) {
|
||||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||||
|
} else {
|
||||||
|
gen_op_iret_real(s->dflag);
|
||||||
|
s->cc_op = CC_OP_EFLAGS;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (s->cc_op != CC_OP_DYNAMIC)
|
if (s->cc_op != CC_OP_DYNAMIC)
|
||||||
gen_op_set_cc_op(s->cc_op);
|
gen_op_set_cc_op(s->cc_op);
|
||||||
|
@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
break;
|
break;
|
||||||
case 0xcd: /* int N */
|
case 0xcd: /* int N */
|
||||||
val = ldub_code(s->pc++);
|
val = ldub_code(s->pc++);
|
||||||
/* XXX: add error code for vm86 GPF */
|
if (s->vm86 && s->iopl != 3) {
|
||||||
if (!s->vm86)
|
|
||||||
gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
|
|
||||||
else
|
|
||||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
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;
|
break;
|
||||||
case 0xce: /* into */
|
case 0xce: /* into */
|
||||||
if (s->cc_op != CC_OP_DYNAMIC)
|
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;
|
op = (modrm >> 3) & 7;
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case 0: /* sldt */
|
case 0: /* sldt */
|
||||||
|
if (!s->pe || s->vm86)
|
||||||
|
goto illegal_op;
|
||||||
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
|
gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
|
||||||
ot = OT_WORD;
|
ot = OT_WORD;
|
||||||
if (mod == 3)
|
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);
|
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
|
||||||
break;
|
break;
|
||||||
case 2: /* lldt */
|
case 2: /* lldt */
|
||||||
|
if (!s->pe || s->vm86)
|
||||||
|
goto illegal_op;
|
||||||
if (s->cpl != 0) {
|
if (s->cpl != 0) {
|
||||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: /* str */
|
case 1: /* str */
|
||||||
|
if (!s->pe || s->vm86)
|
||||||
|
goto illegal_op;
|
||||||
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
|
gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
|
||||||
ot = OT_WORD;
|
ot = OT_WORD;
|
||||||
if (mod == 3)
|
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);
|
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
|
||||||
break;
|
break;
|
||||||
case 3: /* ltr */
|
case 3: /* ltr */
|
||||||
|
if (!s->pe || s->vm86)
|
||||||
|
goto illegal_op;
|
||||||
if (s->cpl != 0) {
|
if (s->cpl != 0) {
|
||||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
break;
|
break;
|
||||||
case 4: /* verr */
|
case 4: /* verr */
|
||||||
case 5: /* verw */
|
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:
|
default:
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
}
|
||||||
|
@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
}
|
||||||
break;
|
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, ®_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 0x102: /* lar */
|
||||||
case 0x103: /* lsl */
|
case 0x103: /* lsl */
|
||||||
if (!s->pe || s->vm86)
|
if (!s->pe || s->vm86)
|
||||||
|
|
Loading…
Reference in a new issue