mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-28 10:10:29 -07:00
target/i386: do not trigger IRQ shadow for LSS
Because LSS need not trigger an IRQ shadow, gen_movl_seg can't just use
the destination register to decide whether to inhibit IRQs. Add an
argument.
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit e54ef98c8a)
(back-ported to 10.0)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
This commit is contained in:
parent
9e13cd7232
commit
4ba45dffde
2 changed files with 22 additions and 15 deletions
|
|
@ -355,7 +355,7 @@ static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv
|
|||
break;
|
||||
case X86_OP_SEG:
|
||||
/* Note that gen_movl_seg takes care of interrupt shadow and TF. */
|
||||
gen_movl_seg(s, op->n, s->T0);
|
||||
gen_movl_seg(s, op->n, v, op->n == R_SS);
|
||||
break;
|
||||
case X86_OP_INT:
|
||||
if (op->has_ea) {
|
||||
|
|
@ -2360,7 +2360,7 @@ static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg)
|
|||
gen_op_ld_v(s, MO_16, s->T1, s->A0);
|
||||
|
||||
/* load the segment here to handle exceptions properly */
|
||||
gen_movl_seg(s, seg, s->T1);
|
||||
gen_movl_seg(s, seg, s->T1, false);
|
||||
}
|
||||
|
||||
static void gen_LDS(DisasContext *s, X86DecodedInsn *decode)
|
||||
|
|
|
|||
|
|
@ -1876,25 +1876,32 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg)
|
|||
|
||||
/* move SRC to seg_reg and compute if the CPU state may change. Never
|
||||
call this function with seg_reg == R_CS */
|
||||
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src)
|
||||
static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit_irq)
|
||||
{
|
||||
if (PE(s) && !VM86(s)) {
|
||||
tcg_gen_trunc_tl_i32(s->tmp2_i32, src);
|
||||
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32);
|
||||
/* abort translation because the addseg value may change or
|
||||
because ss32 may change. For R_SS, translation must always
|
||||
stop as a special handling must be done to disable hardware
|
||||
interrupts for the next instruction */
|
||||
if (seg_reg == R_SS) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
} else if (CODE32(s) && seg_reg < R_FS) {
|
||||
TCGv_i32 sel = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_trunc_tl_i32(sel, src);
|
||||
gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel);
|
||||
|
||||
/* For move to DS/ES/SS, the addseg or ss32 flags may change. */
|
||||
if (CODE32(s) && seg_reg < R_FS) {
|
||||
s->base.is_jmp = DISAS_EOB_NEXT;
|
||||
}
|
||||
} else {
|
||||
gen_op_movl_seg_real(s, seg_reg, src);
|
||||
if (seg_reg == R_SS) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For MOV or POP to SS (but not LSS) translation must always
|
||||
* stop as a special handling must be done to disable hardware
|
||||
* interrupts for the next instruction.
|
||||
*
|
||||
* DISAS_EOB_INHIBIT_IRQ is a superset of DISAS_EOB_NEXT which
|
||||
* might have been set above.
|
||||
*/
|
||||
if (inhibit_irq) {
|
||||
s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue