target-i386: Fix inhibit irq mask handling

The patch in 7f0b714 was too simplistic, in that we wound up setting
the flag and then resetting it immediately in gen_eob.

Fixes the reported boot problem with Windows XP.

Backports commit f083d92c03e7a0741d2a9eba774a60d5a3ca772f from qemu
This commit is contained in:
Richard Henderson 2018-02-21 21:24:48 -05:00 committed by Lioncash
parent c7d5d85979
commit 1c096b8fa2
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -2766,14 +2766,21 @@ static void gen_bnd_jmp(DisasContext *s)
} }
} }
/* generate a generic end of block. Trace exception is also generated /* Generate an end of block. Trace exception is also generated if needed.
if needed */ If IIM, set HF_INHIBIT_IRQ_MASK if it isn't already set. */
static void gen_eob(DisasContext *s) static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit)
{ {
TCGContext *tcg_ctx = s->uc->tcg_ctx; TCGContext *tcg_ctx = s->uc->tcg_ctx;
gen_update_cc_op(s); gen_update_cc_op(s);
/* If several instructions disable interrupts, only the first does it. */
if (inhibit && !(s->flags & HF_INHIBIT_IRQ_MASK)) {
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
} else {
gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK); gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
}
if (s->tb->flags & HF_RF_MASK) { if (s->tb->flags & HF_RF_MASK) {
gen_helper_reset_rf(tcg_ctx, tcg_ctx->cpu_env); gen_helper_reset_rf(tcg_ctx, tcg_ctx->cpu_env);
} }
@ -2787,6 +2794,12 @@ static void gen_eob(DisasContext *s)
s->is_jmp = DISAS_TB_JUMP; s->is_jmp = DISAS_TB_JUMP;
} }
/* End of block, resetting the inhibit irq flag. */
static void gen_eob(DisasContext *s)
{
gen_eob_inhibit_irq(s, false);
}
/* generate a jump to eip. No segment change must happen before as a /* generate a jump to eip. No segment change must happen before as a
direct call to the next block may occur */ direct call to the next block may occur */
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
@ -5831,17 +5844,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
ot = gen_pop_T0(s); ot = gen_pop_T0(s);
gen_movl_seg_T0(s, reg); gen_movl_seg_T0(s, reg);
gen_pop_update(s, ot); gen_pop_update(s, ot);
if (reg == R_SS) { /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
/* if reg == SS, inhibit interrupts/trace. */
/* If several instructions disable interrupts, only the
_first_ does it */
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) { if (s->is_jmp) {
gen_jmp_im(s, s->pc - s->cs_base); gen_jmp_im(s, s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s); gen_eob(s);
} }
}
break; break;
case 0x1a1: /* pop fs */ case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */ case 0x1a9: /* pop gs */
@ -5904,17 +5916,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
goto illegal_op; goto illegal_op;
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_movl_seg_T0(s, reg); gen_movl_seg_T0(s, reg);
if (reg == R_SS) { /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
/* if reg == SS, inhibit interrupts/trace */
/* If several instructions disable interrupts, only the
_first_ does it */
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) { if (s->is_jmp) {
gen_jmp_im(s, s->pc - s->cs_base); gen_jmp_im(s, s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s); gen_eob(s);
} }
}
break; break;
case 0x8c: /* mov Gv, seg */ case 0x8c: /* mov Gv, seg */
modrm = cpu_ldub_code(env, s->pc++); modrm = cpu_ldub_code(env, s->pc++);