Skip to content

Commit

Permalink
target-arm: Clean up DISAS_UPDATE usage in AArch32 translation code
Browse files Browse the repository at this point in the history
AArch32 translation code does not distinguish between DISAS_UPDATE and
DISAS_JUMP. Thus, we cannot use any of them without first updating PC in
CPU state. Furthermore, it is too complicated to update PC in CPU state
before PC gets updated in disas context. So it is hardly possible to
correctly end TB early if is is not likely to be executed before calling
disas_*_insn(), e.g. just after calling breakpoint check helper.

Modify DISAS_UPDATE and DISAS_JUMP usage in AArch32 translation and
apply to them the same semantic as AArch64 translation does:
 - DISAS_UPDATE: update PC in CPU state when finishing translation
 - DISAS_JUMP:   preserve current PC value in CPU state when finishing
                 translation

This patch fixes a bug in AArch32 breakpoint handling: when
check_breakpoints helper does not generate an exception, ending the TB
early with DISAS_UPDATE couldn't update PC in CPU state and execution
hangs.

Signed-off-by: Sergey Fedorov <serge.fdrv@gmail.com>
Message-id: 1447097859-586-1-git-send-email-serge.fdrv@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
sergefdrv authored and pm215 committed Nov 10, 2015
1 parent faa811f commit 577bf80
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions target-arm/translate.c
Expand Up @@ -870,7 +870,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
{
TCGv_i32 tmp;

s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
if (s->thumb != (addr & 1)) {
tmp = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp, addr & 1);
Expand All @@ -883,7 +883,7 @@ static inline void gen_bx_im(DisasContext *s, uint32_t addr)
/* Set PC and Thumb state from var. var is marked as dead. */
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
{
s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
tcg_gen_andi_i32(cpu_R[15], var, ~1);
tcg_gen_andi_i32(var, var, 1);
store_cpu_field(var, thumb);
Expand Down Expand Up @@ -1062,7 +1062,7 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
static inline void gen_lookup_tb(DisasContext *s)
{
tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
}

static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
Expand Down Expand Up @@ -4096,7 +4096,7 @@ static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
tmp = load_cpu_field(spsr);
gen_set_cpsr(tmp, CPSR_ERET_MASK);
tcg_temp_free_i32(tmp);
s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
}

/* Generate a v6 exception return. Marks both values as dead. */
Expand All @@ -4105,7 +4105,7 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
gen_set_cpsr(cpsr, CPSR_ERET_MASK);
tcg_temp_free_i32(cpsr);
store_reg(s, 15, pc);
s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
}

static void gen_nop_hint(DisasContext *s, int val)
Expand Down Expand Up @@ -9035,7 +9035,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
tmp = load_cpu_field(spsr);
gen_set_cpsr(tmp, CPSR_ERET_MASK);
tcg_temp_free_i32(tmp);
s->is_jmp = DISAS_UPDATE;
s->is_jmp = DISAS_JUMP;
}
}
break;
Expand Down Expand Up @@ -11355,15 +11355,15 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception_internal(EXCP_KERNEL_TRAP);
dc->is_jmp = DISAS_UPDATE;
dc->is_jmp = DISAS_EXC;
break;
}
#else
if (dc->pc >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception_internal(EXCP_EXCEPTION_EXIT);
dc->is_jmp = DISAS_UPDATE;
dc->is_jmp = DISAS_EXC;
break;
}
#endif
Expand Down Expand Up @@ -11497,7 +11497,8 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
}
gen_set_label(dc->condlabel);
}
if (dc->condjmp || !dc->is_jmp) {
if (dc->condjmp || dc->is_jmp == DISAS_NEXT ||
dc->is_jmp == DISAS_UPDATE) {
gen_set_pc_im(dc, dc->pc);
dc->condjmp = 0;
}
Expand Down Expand Up @@ -11533,9 +11534,11 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
case DISAS_NEXT:
gen_goto_tb(dc, 1, dc->pc);
break;
default:
case DISAS_JUMP:
case DISAS_UPDATE:
gen_set_pc_im(dc, dc->pc);
/* fall through */
case DISAS_JUMP:
default:
/* indicate that the hash table must be used to find the next TB */
tcg_gen_exit_tb(0);
break;
Expand Down

0 comments on commit 577bf80

Please sign in to comment.