diff --git a/cpu-exec.c b/cpu-exec.c index debc65ca69..f984dc71cb 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -508,11 +508,8 @@ int cpu_exec(CPUState *cpu) next_tb = 0; tcg_ctx.tb_ctx.tb_invalidated_flag = 0; } - /* see if we can patch the calling TB. When the TB - spans two pages, we cannot safely do a direct - jump. */ - if (next_tb != 0 && tb->page_addr[1] == -1 - && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { + /* See if we can patch the calling TB. */ + if (next_tb != 0 && !qemu_loglevel_mask(CPU_LOG_TB_NOCHAIN)) { tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK), next_tb & TB_EXIT_MASK, tb); } diff --git a/target-arm/translate.c b/target-arm/translate.c index 940ec8d981..34196a8217 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -4054,7 +4054,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, target_ulong dest) TranslationBlock *tb; tb = s->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || + ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); gen_set_pc_im(s, dest); tcg_gen_exit_tb((uintptr_t)tb + n); diff --git a/target-cris/translate.c b/target-cris/translate.c index a73176c118..9c8ff8f230 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -524,7 +524,9 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) { TranslationBlock *tb; tb = dc->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || + (dc->ppc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_tl(env_pc, dest); tcg_gen_exit_tb((uintptr_t)tb + n); diff --git a/target-i386/translate.c b/target-i386/translate.c index 3a32f65f8d..058d85a1ab 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2094,7 +2094,7 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong 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 - 1) & TARGET_PAGE_MASK)) { + (pc & TARGET_PAGE_MASK) == (s->pc_start & TARGET_PAGE_MASK)) { /* jump to same page: we can use a direct jump */ tcg_gen_goto_tb(tb_num); gen_jmp_im(eip); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 7560c3a808..e2ce6c615e 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -861,7 +861,7 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest) if (unlikely(s->singlestep_enabled)) { gen_exception(s, dest, EXCP_DEBUG); } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) || - (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(QREG_PC, dest); tcg_gen_exit_tb((uintptr_t)tb + n); diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c871ef2bb3..c5179fe05d 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -610,7 +610,7 @@ static int use_goto_tb(DisasContext *s, uint64_t dest) { /* NOTE: we handle the case where the TB spans two pages here */ return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) - || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) + || (dest & TARGET_PAGE_MASK) == (s->pc & TARGET_PAGE_MASK)) && !s->singlestep_enabled && !(s->tb->cflags & CF_LAST_IO) && !(s->tb->flags & FLAG_MASK_PER)); diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index c446d3dc72..ace39619ef 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -753,6 +753,16 @@ static inline void tcg_gen_exit_tb(uintptr_t val) tcg_gen_op1i(INDEX_op_exit_tb, val); } +/** + * tcg_gen_goto_tb() - output goto_tb TCG operation + * @idx: Direct jump slot index (0 or 1) + * + * 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(). + */ void tcg_gen_goto_tb(unsigned idx); #if TARGET_LONG_BITS == 32