From ffdc9d6323effe14eb469c4ac96510ad66f8ae61 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 23 Feb 2018 23:12:07 -0500 Subject: [PATCH] tcg: Allow goto_tb to any target PC in user mode In user mode, there's only a static address translation, TBs are always invalidated properly and direct jumps are reset when mapping change. Thus the destination address is always valid for direct jumps and there's no need to restrict it to the pages the TB resides in. Backports commit 90aa39a1cc4837360889f0e033ca25cc82100308 from qemu --- qemu/target-arm/translate-a64.c | 2 ++ qemu/target-arm/translate.c | 17 ++++++++++++----- qemu/target-i386/translate.c | 21 +++++++++++++-------- qemu/target-m68k/translate.c | 17 ++++++++++++----- qemu/target-mips/translate.c | 21 ++++++++++++++++----- qemu/target-sparc/translate.c | 23 +++++++++++++++++------ qemu/tcg/tcg-op.h | 9 ++++++--- 7 files changed, 78 insertions(+), 32 deletions(-) diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index fbc23c12..8847c53c 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -289,10 +289,12 @@ static inline bool use_goto_tb(DisasContext *s, int n, uint64_t dest) return false; } +#ifndef CONFIG_USER_ONLY /* Only link tbs from inside the same guest page */ if ((s->tb->pc & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { return false; } +#endif return true; } diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index 14a7d0d6..b6de939d 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -4149,17 +4149,24 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) return 0; } +static inline bool use_goto_tb(DisasContext *s, target_ulong dest) +{ +#ifndef CONFIG_USER_ONLY + return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || + ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); +#else + return true; +#endif +} + static inline void gen_goto_tb(DisasContext *s, int n, target_ulong dest) { TCGContext *tcg_ctx = s->uc->tcg_ctx; - TranslationBlock *tb; - tb = s->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || - ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if (use_goto_tb(s, dest)) { tcg_gen_goto_tb(tcg_ctx, n); gen_set_pc_im(s, dest); - tcg_gen_exit_tb(tcg_ctx, (uintptr_t)tb + n); + tcg_gen_exit_tb(tcg_ctx, (uintptr_t)s->tb + n); } else { gen_set_pc_im(s, dest); tcg_gen_exit_tb(tcg_ctx, 0); diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 0cc4c0d7..9b82e3ad 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -2363,21 +2363,26 @@ static inline int insn_const_size(TCGMemOp ot) } } +static inline bool use_goto_tb(DisasContext *s, target_ulong pc) +{ +#ifndef CONFIG_USER_ONLY + return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) || + (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK); +#else + return true; +#endif +} + static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) { - TranslationBlock *tb; - target_ulong pc; TCGContext *tcg_ctx = s->uc->tcg_ctx; + target_ulong pc = s->cs_base + eip; - pc = s->cs_base + eip; - tb = s->tb; - /* NOTE: we handle the case where the TB spans two pages here */ - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || - (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK)) { + if (use_goto_tb(s, pc)) { /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tcg_ctx, tb_num); gen_jmp_im(s, eip); - tcg_gen_exit_tb(tcg_ctx, (uintptr_t)tb + tb_num); + tcg_gen_exit_tb(tcg_ctx, (uintptr_t)s->tb + tb_num); } else { /* jump to another page: currently not optimized */ gen_jmp_im(s, eip); diff --git a/qemu/target-m68k/translate.c b/qemu/target-m68k/translate.c index f29ec559..37bb8975 100644 --- a/qemu/target-m68k/translate.c +++ b/qemu/target-m68k/translate.c @@ -841,20 +841,27 @@ static inline void gen_addr_fault(DisasContext *s) } \ } while (0) +static inline bool use_goto_tb(DisasContext *s, uint32_t dest) +{ +#ifndef CONFIG_USER_ONLY + return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || + (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); +#else + return true; +#endif +} + /* Generate a jump to an immediate address. */ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) { TCGContext *tcg_ctx = s->uc->tcg_ctx; - TranslationBlock *tb; - tb = s->tb; if (unlikely(s->singlestep_enabled)) { gen_exception(s, dest, EXCP_DEBUG); - } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || - (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + } else if (use_goto_tb(s, dest)) { tcg_gen_goto_tb(tcg_ctx, n); tcg_gen_movi_i32(tcg_ctx, tcg_ctx->QREG_PC, dest); - tcg_gen_exit_tb(tcg_ctx, (uintptr_t)tb + n); + tcg_gen_exit_tb(tcg_ctx, (uintptr_t)s->tb + n); } else { gen_jmp_im(s, dest); tcg_gen_exit_tb(tcg_ctx, 0); diff --git a/qemu/target-mips/translate.c b/qemu/target-mips/translate.c index b220d055..2c8ad3d4 100644 --- a/qemu/target-mips/translate.c +++ b/qemu/target-mips/translate.c @@ -4248,16 +4248,27 @@ static void gen_trap (DisasContext *ctx, uint32_t opc, tcg_temp_free(tcg_ctx, t1); } +static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) +{ + if (unlikely(ctx->singlestep_enabled)) { + return false; + } + +#ifndef CONFIG_USER_ONLY + return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); +#else + return true; +#endif +} + static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TCGContext *tcg_ctx = ctx->uc->tcg_ctx; - TranslationBlock *tb; - tb = ctx->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && - likely(!ctx->singlestep_enabled)) { + + if (use_goto_tb(ctx, dest)) { tcg_gen_goto_tb(tcg_ctx, n); gen_save_pc(ctx, dest); - tcg_gen_exit_tb(tcg_ctx, (uintptr_t)tb + n); + tcg_gen_exit_tb(tcg_ctx, (uintptr_t)ctx->tb + n); } else { gen_save_pc(ctx, dest); if (ctx->singlestep_enabled) { diff --git a/qemu/target-sparc/translate.c b/qemu/target-sparc/translate.c index 32057c0c..3bbbc624 100644 --- a/qemu/target-sparc/translate.c +++ b/qemu/target-sparc/translate.c @@ -295,21 +295,32 @@ static inline TCGv gen_dest_gpr(DisasContext *dc, int reg) } } +static inline bool use_goto_tb(DisasContext *s, target_ulong pc, + target_ulong npc) +{ + if (unlikely(s->singlestep)) { + return false; + } + +#ifndef CONFIG_USER_ONLY + return (pc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) && + (npc & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK); +#else + return true; +#endif +} + static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong pc, target_ulong npc) { TCGContext *tcg_ctx = s->uc->tcg_ctx; - TranslationBlock *tb; - tb = s->tb; - if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) && - !s->singlestep) { + if (use_goto_tb(s, pc, npc)) { /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tcg_ctx, tb_num); tcg_gen_movi_tl(tcg_ctx, tcg_ctx->sparc_cpu_pc, pc); tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_npc, npc); - tcg_gen_exit_tb(tcg_ctx, (uintptr_t)tb + tb_num); + tcg_gen_exit_tb(tcg_ctx, (uintptr_t)s->tb + tb_num); } else { /* jump to another page: currently not optimized */ tcg_gen_movi_tl(tcg_ctx, tcg_ctx->sparc_cpu_pc, pc); diff --git a/qemu/tcg/tcg-op.h b/qemu/tcg/tcg-op.h index 3c834461..7beb1c7c 100644 --- a/qemu/tcg/tcg-op.h +++ b/qemu/tcg/tcg-op.h @@ -759,9 +759,12 @@ static inline void tcg_gen_exit_tb(TCGContext *s, uintptr_t val) * * See tcg/README for more info about this TCG operation. * - * NOTE: Direct jumps with goto_tb are only safe within the pages this TB - * resides in because we don't take care of direct jumps when address mapping - * changes, e.g. in tlb_flush(). + * NOTE: In softmmu emulation, direct jumps with goto_tb are only safe within + * the pages this TB resides in because we don't take care of direct jumps when + * address mapping changes, e.g. in tlb_flush(). In user mode, there's only a + * static address translation, so the destination address is always valid, TBs + * are always invalidated properly, and direct jumps are reset when mapping + * changes. */ void tcg_gen_goto_tb(TCGContext *s, unsigned idx);