qemu-s390x
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 3/4] target/i386: Make translator stop before the end of a pag


From: Ilya Leoshkevich
Subject: [PATCH v2 3/4] target/i386: Make translator stop before the end of a page
Date: Fri, 5 Aug 2022 18:09:13 +0200

Right now translator stops right *after* the end of a page, which
breaks reporting of fault locations when the last instruction of a
multi-insn translation block crosses a page boundary.

We may find out that we crossed page boundary after some ops were
emitted and cc_op was updated. In theory it might be possible to
rearrange the code to disassemble first, but this is too error-prone.
Simply snapshot and restore the disassembly state instead.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 target/i386/tcg/translate.c | 42 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index b7972f0ff5..ea749b0a04 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -2008,6 +2008,12 @@ static uint64_t advance_pc(CPUX86State *env, 
DisasContext *s, int num_bytes)
 {
     uint64_t pc = s->pc;
 
+    /* This is a subsequent insn that crosses a page boundary.  */
+    if (s->base.num_insns > 1 &&
+        !is_same_page(&s->base, s->pc + num_bytes - 1)) {
+        siglongjmp(s->jmpbuf, 2);
+    }
+
     s->pc += num_bytes;
     if (unlikely(s->pc - s->pc_start > X86_MAX_INSN_LENGTH)) {
         /* If the instruction's 16th byte is on a different page than the 1st, 
a
@@ -4545,6 +4551,29 @@ static void gen_sse(CPUX86State *env, DisasContext *s, 
int b,
     }
 }
 
+/* Disassembly state that may affect the next instruction. */
+typedef struct {
+    TCGOp *last_op;
+    bool cc_op_dirty;
+    CCOp cc_op;
+} DisasSnapshot;
+
+/* Save disassembly state. */
+static void disas_save(DisasSnapshot *snapshot, const DisasContext *s)
+{
+    snapshot->last_op = tcg_last_op();
+    snapshot->cc_op_dirty = s->cc_op_dirty;
+    snapshot->cc_op = s->cc_op;
+}
+
+/* Restore disassembly state. */
+static void disas_restore(const DisasSnapshot *snapshot, DisasContext *s)
+{
+    tcg_remove_ops_after(snapshot->last_op);
+    s->cc_op_dirty = snapshot->cc_op_dirty;
+    s->cc_op = snapshot->cc_op;
+}
+
 /* convert one instruction. s->base.is_jmp is set if the translation must
    be stopped. Return the next pc value */
 static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
@@ -4556,6 +4585,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
     int modrm, reg, rm, mod, op, opreg, val;
     target_ulong next_eip, tval;
     target_ulong pc_start = s->base.pc_next;
+    DisasSnapshot snapshot;
 
     s->pc_start = s->pc = pc_start;
     s->override = -1;
@@ -4568,9 +4598,19 @@ static target_ulong disas_insn(DisasContext *s, CPUState 
*cpu)
     s->rip_offset = 0; /* for relative ip address */
     s->vex_l = 0;
     s->vex_v = 0;
-    if (sigsetjmp(s->jmpbuf, 0) != 0) {
+    disas_save(&snapshot, s);
+    switch (sigsetjmp(s->jmpbuf, 0)) {
+    case 0:
+        break;
+    case 1:
         gen_exception_gpf(s);
         return s->pc;
+    case 2:
+        disas_restore(&snapshot, s);
+        s->base.is_jmp = DISAS_TOO_MANY;
+        return pc_start;
+    default:
+        g_assert_not_reached();
     }
 
     prefixes = 0;
-- 
2.35.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]