If the PC is in the last page of the address space, next_page_start overflows to 0. Fix it.
Cc: Peter Maydell <peter.mayd...@linaro.org> Signed-off-by: Emilio G. Cota <c...@braap.org> --- target/arm/translate.h | 2 +- target/arm/translate.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/target/arm/translate.h b/target/arm/translate.h index c47febf..2287894 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -9,7 +9,7 @@ typedef struct DisasContext { DisasContextBase base; target_ulong pc; - target_ulong next_page_start; + target_ulong page_start; uint32_t insn; /* Nonzero if this instruction has been conditionally skipped. */ int condjmp; diff --git a/target/arm/translate.c b/target/arm/translate.c index fc03b5b..ade8d2d 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9913,7 +9913,7 @@ static bool thumb_insn_is_16bit(DisasContext *s, uint32_t insn) return false; } - if ((insn >> 11) == 0x1e && (s->pc < s->next_page_start - 3)) { + if ((insn >> 11) == 0x1e && s->pc - s->page_start < TARGET_PAGE_SIZE - 3) { /* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix, and the suffix * is not on the next page; we merge this into a 32-bit * insn. @@ -12269,8 +12269,7 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase, dc->is_ldex = false; dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */ - dc->next_page_start = - (dc->base.pc_first & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + dc->page_start = dc->base.pc_first & TARGET_PAGE_MASK; /* If architectural single step active, limit to 1. */ if (is_singlestepping(dc)) { @@ -12280,7 +12279,7 @@ static int arm_tr_init_disas_context(DisasContextBase *dcbase, /* ARM is a fixed-length ISA. Bound the number of insns to execute to those left on the page. */ if (!dc->thumb) { - int bound = (dc->next_page_start - dc->base.pc_first) / 4; + int bound = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4; max_insns = MIN(max_insns, bound); } @@ -12552,8 +12551,8 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * but isn't very efficient). */ if (dc->base.is_jmp == DISAS_NEXT - && (dc->pc >= dc->next_page_start - || (dc->pc >= dc->next_page_start - 3 + && (dc->pc - dc->page_start >= TARGET_PAGE_SIZE + || (dc->pc - dc->page_start >= TARGET_PAGE_SIZE - 3 && insn_crosses_page(env, dc)))) { dc->base.is_jmp = DISAS_TOO_MANY; } -- 2.7.4