From: Paolo Bonzini <pbonzini@redhat.com>
To: "Hervé Poussineau" <hpoussin@reactos.org>,
"Richard Henderson" <rth@twiddle.net>,
qemu-devel <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [QEMU] Windows XP / Windows 95 / MS-DOS 6 regressions
Date: Wed, 2 Mar 2016 15:06:14 +0100 [thread overview]
Message-ID: <56D6F356.9060003@redhat.com> (raw)
In-Reply-To: <56D69EEE.3090709@reactos.org>
On 02/03/2016 09:06, Hervé Poussineau wrote:
>>
>
> I just reconfirmed that
> d6a2914984c89fa0a3125b9842e0cbf68de79a3d~1 +
> 88c73d16ad1b6c22a2ab082064d0d521f756296a works,
> while
> d6a2914984c89fa0a3125b9842e0cbf68de79a3d +
> 88c73d16ad1b6c22a2ab082064d0d521f756296a bugchecks.
>
> a5af12871fd4601c44f08d9e49131e9ca13ef102 that you tested is after
> d6a2914984c89fa0a3125b9842e0cbf68de79a3d which broke Windows 9x, that's
> why you're seeing it broken.
>
> It also has been a long time that Windows 9x doesn't work with
> -enable-kvm. Maybe even always...
This was tricky because the faulting instruction is some kind of
generated thunk. In the good QEMU it is like:
0x000000008030a4da: mov $0x16f,%ax
0x000000008030a4dd: mov %ax,%es
0x000000008030a4df: movzwl %cx,%ecx
0x000000008030a4e3: addr32 mov %es:-0x400aa28c(%ecx),%edx
0x000000008030a4ec: ljmpl $0x167,$0xbff71903
In the bad one, the address is %es:0(%ecx) and everything goes south
from there. Therefore I copied the old code, changed to generate the
effective address in a new temp cpu_A1, then I added a helper that gets
the two effective addresses and asserts if they mismatch. Sure enough
it fired on an
addr16 mov %gs:(%bx),%eax
The issue is that the
/* ADDSEG will only be false in 16-bit mode for LEA. */
comment is false when in 32-bit mode but with an addr16 prefix. I
still have to forward port it, and test on a newer commit, but the
attached patch can boot Windows 98.
Paolo
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 282f4a1..0a2d091 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -61,6 +61,7 @@
/* global register indexes */
static TCGv_ptr cpu_env;
static TCGv cpu_A0;
+static TCGv cpu_A1;
static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2, cpu_cc_srcT;
static TCGv_i32 cpu_cc_op;
static TCGv cpu_regs[CPU_NB_REGS];
@@ -419,6 +420,18 @@ static inline void gen_op_add_reg_T0(TCGMemOp size, int reg)
gen_op_mov_reg_v(size, reg, cpu_tmp0);
}
+static inline void gen_op_addl_A1_seg(DisasContext *s, int reg)
+{
+ tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUX86State, segs[reg].base));
+ if (CODE64(s)) {
+ tcg_gen_ext32u_tl(cpu_A1, cpu_A1);
+ tcg_gen_add_tl(cpu_A1, cpu_A1, cpu_tmp0);
+ } else {
+ tcg_gen_add_tl(cpu_A1, cpu_A1, cpu_tmp0);
+ tcg_gen_ext32u_tl(cpu_A1, cpu_A1);
+ }
+}
+
static inline void gen_op_addl_A0_seg(DisasContext *s, int reg)
{
tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUX86State, segs[reg].base));
@@ -485,13 +498,13 @@ static void gen_lea_v_seg(DisasContext *s, TCGv a0, int def_seg, int ovr_seg)
break;
case MO_16:
/* 16 bit address */
- if (ovr_seg < 0) {
- ovr_seg = def_seg;
- }
tcg_gen_ext16u_tl(cpu_A0, a0);
- /* ADDSEG will only be false in 16-bit mode for LEA. */
- if (!s->addseg) {
- return;
+ if (ovr_seg < 0) {
+ if (s->addseg) {
+ ovr_seg = def_seg;
+ } else {
+ return;
+ }
}
a0 = cpu_A0;
break;
@@ -1838,12 +1851,198 @@ static void gen_shifti(DisasContext *s1, int op, TCGMemOp ot, int d, int c)
}
}
+static void gen_lea_modrm_old(CPUX86State *env, DisasContext *s, int modrm)
+{
+ target_long disp;
+ int havesib;
+ int base;
+ int index;
+ int scale;
+ int mod, rm, code, override, must_add_seg;
+ TCGv sum;
+
+ override = s->override;
+ must_add_seg = s->addseg;
+ if (override >= 0)
+ must_add_seg = 1;
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+
+ switch (s->aflag) {
+ case MO_64:
+ case MO_32:
+ havesib = 0;
+ base = rm;
+ index = -1;
+ scale = 0;
+
+ if (base == 4) {
+ havesib = 1;
+ code = cpu_ldub_code(env, s->pc++);
+ scale = (code >> 6) & 3;
+ index = ((code >> 3) & 7) | REX_X(s);
+ if (index == 4) {
+ index = -1; /* no index */
+ }
+ base = (code & 7);
+ }
+ base |= REX_B(s);
+
+ switch (mod) {
+ case 0:
+ if ((base & 7) == 5) {
+ base = -1;
+ disp = (int32_t)cpu_ldl_code(env, s->pc);
+ s->pc += 4;
+ if (CODE64(s) && !havesib) {
+ disp += s->pc + s->rip_offset;
+ }
+ } else {
+ disp = 0;
+ }
+ break;
+ case 1:
+ disp = (int8_t)cpu_ldub_code(env, s->pc++);
+ break;
+ default:
+ case 2:
+ disp = (int32_t)cpu_ldl_code(env, s->pc);
+ s->pc += 4;
+ break;
+ }
+
+ /* For correct popl handling with esp. */
+ if (base == R_ESP && s->popl_esp_hack) {
+ disp += s->popl_esp_hack;
+ }
+
+ /* Compute the address, with a minimum number of TCG ops. */
+ TCGV_UNUSED(sum);
+ if (index >= 0) {
+ if (scale == 0) {
+ sum = cpu_regs[index];
+ } else {
+ tcg_gen_shli_tl(cpu_A1, cpu_regs[index], scale);
+ sum = cpu_A1;
+ }
+ if (base >= 0) {
+ tcg_gen_add_tl(cpu_A1, sum, cpu_regs[base]);
+ sum = cpu_A1;
+ }
+ } else if (base >= 0) {
+ sum = cpu_regs[base];
+ }
+ if (TCGV_IS_UNUSED(sum)) {
+ tcg_gen_movi_tl(cpu_A1, disp);
+ } else {
+ tcg_gen_addi_tl(cpu_A1, sum, disp);
+ }
+
+ if (must_add_seg) {
+ if (override < 0) {
+ if (base == R_EBP || base == R_ESP) {
+ override = R_SS;
+ } else {
+ override = R_DS;
+ }
+ }
+
+ tcg_gen_ld_tl(cpu_tmp0, cpu_env,
+ offsetof(CPUX86State, segs[override].base));
+ if (CODE64(s)) {
+ if (s->aflag == MO_32) {
+ tcg_gen_ext32u_tl(cpu_A1, cpu_A1);
+ }
+ tcg_gen_add_tl(cpu_A1, cpu_A1, cpu_tmp0);
+ return;
+ }
+
+ tcg_gen_add_tl(cpu_A1, cpu_A1, cpu_tmp0);
+ }
+
+ if (s->aflag == MO_32) {
+ tcg_gen_ext32u_tl(cpu_A1, cpu_A1);
+ }
+ break;
+
+ case MO_16:
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ disp = cpu_lduw_code(env, s->pc);
+ s->pc += 2;
+ tcg_gen_movi_tl(cpu_A1, disp);
+ rm = 0; /* avoid SS override */
+ goto no_rm;
+ } else {
+ disp = 0;
+ }
+ break;
+ case 1:
+ disp = (int8_t)cpu_ldub_code(env, s->pc++);
+ break;
+ default:
+ case 2:
+ disp = (int16_t)cpu_lduw_code(env, s->pc);
+ s->pc += 2;
+ break;
+ }
+
+ sum = cpu_A1;
+ switch (rm) {
+ case 0:
+ tcg_gen_add_tl(cpu_A1, cpu_regs[R_EBX], cpu_regs[R_ESI]);
+ break;
+ case 1:
+ tcg_gen_add_tl(cpu_A1, cpu_regs[R_EBX], cpu_regs[R_EDI]);
+ break;
+ case 2:
+ tcg_gen_add_tl(cpu_A1, cpu_regs[R_EBP], cpu_regs[R_ESI]);
+ break;
+ case 3:
+ tcg_gen_add_tl(cpu_A1, cpu_regs[R_EBP], cpu_regs[R_EDI]);
+ break;
+ case 4:
+ sum = cpu_regs[R_ESI];
+ break;
+ case 5:
+ sum = cpu_regs[R_EDI];
+ break;
+ case 6:
+ sum = cpu_regs[R_EBP];
+ break;
+ default:
+ case 7:
+ sum = cpu_regs[R_EBX];
+ break;
+ }
+ tcg_gen_addi_tl(cpu_A1, sum, disp);
+ tcg_gen_ext16u_tl(cpu_A1, cpu_A1);
+ no_rm:
+ if (must_add_seg) {
+ if (override < 0) {
+ if (rm == 2 || rm == 3 || rm == 6) {
+ override = R_SS;
+ } else {
+ override = R_DS;
+ }
+ }
+ gen_op_addl_A1_seg(s, override);
+ }
+ break;
+
+ default:
+ tcg_abort();
+ }
+}
+
static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
{
target_long disp;
int havesib, base, index, scale;
int mod, rm, code, def_seg, ovr_seg;
TCGv sum;
+ target_long pc = s->pc, save_pc;
def_seg = R_DS;
ovr_seg = s->override;
@@ -1985,6 +2184,11 @@ static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
}
gen_lea_v_seg(s, sum, def_seg, ovr_seg);
+ save_pc = s->pc;
+ s->pc = pc;
+ gen_lea_modrm_old(env, s, modrm);
+ assert(s->pc == save_pc);
+ gen_helper_compare(cpu_A0, cpu_A1);
}
static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
@@ -7858,6 +8062,7 @@ void gen_intermediate_code(CPUX86State *env, TranslationBlock *tb)
cpu_T[0] = tcg_temp_new();
cpu_T[1] = tcg_temp_new();
cpu_A0 = tcg_temp_new();
+ cpu_A1 = tcg_temp_new();
cpu_tmp0 = tcg_temp_new();
cpu_tmp1_i64 = tcg_temp_new_i64();
prev parent reply other threads:[~2016-03-02 14:06 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-28 21:49 [Qemu-devel] [QEMU] Windows XP / Windows 95 / MS-DOS 6 regressions Hervé Poussineau
2016-03-01 13:49 ` Paolo Bonzini
2016-03-01 15:12 ` Paolo Bonzini
2016-03-01 20:03 ` Hervé Poussineau
2016-03-01 21:06 ` Paolo Bonzini
2016-03-02 4:05 ` Richard Henderson
2016-03-02 8:06 ` Hervé Poussineau
2016-03-02 9:13 ` Paolo Bonzini
2016-03-02 14:06 ` Paolo Bonzini [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=56D6F356.9060003@redhat.com \
--to=pbonzini@redhat.com \
--cc=hpoussin@reactos.org \
--cc=qemu-devel@nongnu.org \
--cc=rth@twiddle.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.