aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2024-06-06 10:53:18 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2024-06-08 10:33:38 +0200
commitf1b8613da380af8931e34dfb4dd0a6cca392d43b (patch)
tree4d20f2bcbba428e9a9006962332fc7ebea7a0ae6
parentaea49fbb01a4a1191165af0b08b5e27994f22c35 (diff)
downloadqemu-f1b8613da380af8931e34dfb4dd0a6cca392d43b.zip
qemu-f1b8613da380af8931e34dfb4dd0a6cca392d43b.tar.gz
qemu-f1b8613da380af8931e34dfb4dd0a6cca392d43b.tar.bz2
target/i386: fix SP when taking a memory fault during POP
When OS/2 Warp configures its segment descriptors, many of them are configured with the P flag clear to allow for a fault-on-demand implementation. In the case where the stack value is POPped into the segment registers, the SP is incremented before calling gen_helper_load_seg() to validate the segment descriptor: IN: 0xffef2c0c: 66 07 popl %es OP: ld_i32 loc9,env,$0xfffffffffffffff8 sub_i32 loc9,loc9,$0x1 brcond_i32 loc9,$0x0,lt,$L0 st16_i32 loc9,env,$0xfffffffffffffff8 st8_i32 $0x1,env,$0xfffffffffffffffc ---- 0000000000000c0c 0000000000000000 ext16u_i64 loc0,rsp add_i64 loc0,loc0,ss_base ext32u_i64 loc0,loc0 qemu_ld_a64_i64 loc0,loc0,noat+un+leul,5 add_i64 loc3,rsp,$0x4 deposit_i64 rsp,rsp,loc3,$0x0,$0x10 extrl_i64_i32 loc5,loc0 call load_seg,$0x0,$0,env,$0x0,loc5 add_i64 rip,rip,$0x2 ext16u_i64 rip,rip exit_tb $0x0 set_label $L0 exit_tb $0x7fff58000043 If helper_load_seg() generates a fault when validating the segment descriptor then as the SP has already been incremented, the topmost word of the stack is overwritten by the arguments pushed onto the stack by the CPU before taking the fault handler. As a consequence things rapidly go wrong upon return from the fault handler due to the corrupted stack. Update the logic for the existing writeback condition so that a POP into the segment registers also calls helper_load_seg() first before incrementing the SP, so that if a fault occurs the SP remains unaltered. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2198 Message-ID: <20240606095319.229650-4-mark.cave-ayland@ilande.co.uk> Fixes: cc1d28bdbe0 ("target/i386: move 00-5F opcodes to new decoder", 2024-05-07) Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--target/i386/tcg/emit.c.inc2
1 files changed, 1 insertions, 1 deletions
diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc
index 6123235..4be3d9a 100644
--- a/target/i386/tcg/emit.c.inc
+++ b/target/i386/tcg/emit.c.inc
@@ -2578,7 +2578,7 @@ static void gen_POP(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
X86DecodedOp *op = &decode->op[0];
MemOp ot = gen_pop_T0(s);
- if (op->has_ea) {
+ if (op->has_ea || op->unit == X86_OP_SEG) {
/* NOTE: order is important for MMU exceptions */
gen_writeback(s, decode, 0, s->T0);
}