aboutsummaryrefslogtreecommitdiff
path: root/translate-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-07-27 21:11:27 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-07-27 21:11:27 +0000
commit2c1794c42ef9d23dc6aeb5e07673f2fcd885b9eb (patch)
tree7ab3deee77c00745360376cd34038e0aec8ca617 /translate-i386.c
parent8a4c1cc4118720fb69f0e9aa3c15275e13294946 (diff)
more generic ljmp and lcall - fixed REPNZ usage for non compare string ops (FreeDos boot loader fix)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@340 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r--translate-i386.c99
1 files changed, 43 insertions, 56 deletions
diff --git a/translate-i386.c b/translate-i386.c
index 7fce0e24bf..820cc65c30 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -1832,19 +1832,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1;
break;
case 3: /* lcall Ev */
- /* push return segment + offset */
- gen_op_movl_T0_seg(R_CS);
- gen_push_T0(s);
- next_eip = s->pc - s->cs_base;
- gen_op_movl_T0_im(next_eip);
- gen_push_T0(s);
-
gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
gen_op_lduw_T0_A0();
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_op_movl_T0_T1();
- gen_op_jmp_T0();
+ do_lcall:
+ if (s->pe && !s->vm86) {
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base);
+ } else {
+ gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base);
+ }
s->is_jmp = 1;
break;
case 4: /* jmp Ev */
@@ -1857,10 +1856,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
gen_op_lduw_T0_A0();
+ do_ljmp:
if (s->pe && !s->vm86) {
- /* we compute EIP to handle the exception case */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
gen_op_jmp_im(pc_start - s->cs_base);
- gen_op_ljmp_T0_T1();
+ gen_op_ljmp_protected_T0_T1();
} else {
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
gen_op_movl_T0_T1();
@@ -2867,7 +2868,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else
ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & PREFIX_REPZ) {
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_string_ds(s, ot, gen_op_movs + 9);
} else {
gen_string_ds(s, ot, gen_op_movs);
@@ -2881,7 +2882,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else
ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & PREFIX_REPZ) {
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_string_es(s, ot, gen_op_stos + 9);
} else {
gen_string_es(s, ot, gen_op_stos);
@@ -2893,7 +2894,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & PREFIX_REPZ) {
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_string_ds(s, ot, gen_op_lods + 9);
} else {
gen_string_ds(s, ot, gen_op_lods);
@@ -2952,7 +2953,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & PREFIX_REPZ) {
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_string_es(s, ot, gen_op_ins + 9);
} else {
gen_string_es(s, ot, gen_op_ins);
@@ -2969,7 +2970,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
- if (prefixes & PREFIX_REPZ) {
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_string_ds(s, ot, gen_op_outs + 9);
} else {
gen_string_ds(s, ot, gen_op_outs);
@@ -3062,20 +3063,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val = ldsw(s->pc);
s->pc += 2;
do_lret:
- gen_stack_A0(s);
- /* pop offset */
- gen_op_ld_T0_A0[1 + s->dflag]();
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- /* NOTE: keeping EIP updated is not a problem in case of
- exception */
- gen_op_jmp_T0();
- /* pop selector */
- gen_op_addl_A0_im(2 << s->dflag);
- gen_op_ld_T0_A0[1 + s->dflag]();
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- /* add stack offset */
- gen_stack_update(s, val + (4 << s->dflag));
+ if (s->pe && !s->vm86) {
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_jmp_im(pc_start - s->cs_base);
+ gen_op_lret_protected(s->dflag, val);
+ } else {
+ gen_stack_A0(s);
+ /* pop offset */
+ gen_op_ld_T0_A0[1 + s->dflag]();
+ if (s->dflag == 0)
+ gen_op_andl_T0_ffff();
+ /* NOTE: keeping EIP updated is not a problem in case of
+ exception */
+ gen_op_jmp_T0();
+ /* pop selector */
+ gen_op_addl_A0_im(2 << s->dflag);
+ gen_op_ld_T0_A0[1 + s->dflag]();
+ gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
+ /* add stack offset */
+ gen_stack_update(s, val + (4 << s->dflag));
+ }
s->is_jmp = 1;
break;
case 0xcb: /* lret */
@@ -3114,26 +3122,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x9a: /* lcall im */
{
unsigned int selector, offset;
- /* XXX: not restartable */
ot = dflag ? OT_LONG : OT_WORD;
offset = insn_get(s, ot);
selector = insn_get(s, OT_WORD);
- /* push return segment + offset */
- gen_op_movl_T0_seg(R_CS);
- gen_push_T0(s);
- next_eip = s->pc - s->cs_base;
- gen_op_movl_T0_im(next_eip);
- gen_push_T0(s);
-
- /* change cs and pc */
gen_op_movl_T0_im(selector);
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_op_jmp_im((unsigned long)offset);
- s->is_jmp = 1;
+ gen_op_movl_T1_im(offset);
}
- break;
+ goto do_lcall;
case 0xe9: /* jmp */
ot = dflag ? OT_LONG : OT_WORD;
val = insn_get(s, ot);
@@ -3150,20 +3147,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
offset = insn_get(s, ot);
selector = insn_get(s, OT_WORD);
- /* change cs and pc */
gen_op_movl_T0_im(selector);
- if (s->pe && !s->vm86) {
- /* we compute EIP to handle the exception case */
- gen_op_jmp_im(pc_start - s->cs_base);
- gen_op_movl_T1_im(offset);
- gen_op_ljmp_T0_T1();
- } else {
- gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
- gen_op_jmp_im((unsigned long)offset);
- }
- s->is_jmp = 1;
+ gen_op_movl_T1_im(offset);
}
- break;
+ goto do_ljmp;
case 0xeb: /* jmp Jb */
val = (int8_t)insn_get(s, OT_BYTE);
val += s->pc - s->cs_base;