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
This commit is contained in:
Sergey Fedorov 2018-02-23 23:12:07 -05:00 committed by Lioncash
parent 73c59faad5
commit ffdc9d6323
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
7 changed files with 78 additions and 32 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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);