Message ID | 20220811095534.241224-5-iii@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | linux-user: Fix siginfo_t contents when jumping to non-readable pages | expand |
On 8/11/22 02:55, Ilya Leoshkevich wrote: > 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. > > An implementation, like the one arm and s390x have, would require an > i386 length disassembler, which is burdensome to maintain. Another > alternative would be to single-step at the end of a guest page, but > this may come with a performance impact. > > Fix by snapshotting disassembly state and restoring it after we figured > out we crossed a page boundary. This includes rolling back cc_op > updates and emitted ops. > > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> > --- > target/i386/tcg/translate.c | 25 ++++++++++++++++++++++++- > 1 file changed, 24 insertions(+), 1 deletion(-) Reviewed-by: Richard Henderson <richard.henderson@linaro.org> r~
On 8/11/22 09:58, Richard Henderson wrote: > On 8/11/22 02:55, Ilya Leoshkevich wrote: >> 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. >> >> An implementation, like the one arm and s390x have, would require an >> i386 length disassembler, which is burdensome to maintain. Another >> alternative would be to single-step at the end of a guest page, but >> this may come with a performance impact. >> >> Fix by snapshotting disassembly state and restoring it after we figured >> out we crossed a page boundary. This includes rolling back cc_op >> updates and emitted ops. >> >> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> >> --- >> target/i386/tcg/translate.c | 25 ++++++++++++++++++++++++- >> 1 file changed, 24 insertions(+), 1 deletion(-) > > Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Also, Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1143 r~
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index b7972f0ff5..2287d22c3a 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -130,6 +130,7 @@ typedef struct DisasContext { TCGv_i64 tmp1_i64; sigjmp_buf jmpbuf; + TCGOp *prev_insn_end; } DisasContext; /* The environment in which user-only runs is constrained. */ @@ -2008,6 +2009,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 @@ -4556,6 +4563,8 @@ 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; + bool orig_cc_op_dirty = s->cc_op_dirty; + CCOp orig_cc_op = s->cc_op; s->pc_start = s->pc = pc_start; s->override = -1; @@ -4568,9 +4577,22 @@ 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) { + switch (sigsetjmp(s->jmpbuf, 0)) { + case 0: + break; + case 1: gen_exception_gpf(s); return s->pc; + case 2: + /* Restore state that may affect the next instruction. */ + s->cc_op_dirty = orig_cc_op_dirty; + s->cc_op = orig_cc_op; + s->base.num_insns--; + tcg_remove_ops_after(s->prev_insn_end); + s->base.is_jmp = DISAS_TOO_MANY; + return pc_start; + default: + g_assert_not_reached(); } prefixes = 0; @@ -8632,6 +8654,7 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); + dc->prev_insn_end = tcg_last_op(); tcg_gen_insn_start(dc->base.pc_next, dc->cc_op); }
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. An implementation, like the one arm and s390x have, would require an i386 length disassembler, which is burdensome to maintain. Another alternative would be to single-step at the end of a guest page, but this may come with a performance impact. Fix by snapshotting disassembly state and restoring it after we figured out we crossed a page boundary. This includes rolling back cc_op updates and emitted ops. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> --- target/i386/tcg/translate.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)