target/nios2: Implement Misaligned destination exception
Indirect branches, plus eret and bret optionally raise an exception when branching to a misaligned address. The exception is required when an mmu is enabled, but enable it always because the fallback behaviour is not documented (though presumably it discards low bits). For the purposes of the linux-user cpu loop, if EXCP_UNALIGN (misaligned data) were to arrive, it would be treated the same as EXCP_UNALIGND (misaligned destination). See the !defined(CONFIG_NIOS2_ALIGNMENT_TRAP) block in kernel/traps.c. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20220421151735.31996-53-richard.henderson@linaro.org>
This commit is contained in:
parent
0e6f22c561
commit
410c6aaa3b
@ -42,6 +42,12 @@ void cpu_loop(CPUNios2State *env)
|
||||
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
|
||||
break;
|
||||
|
||||
case EXCP_UNALIGN:
|
||||
case EXCP_UNALIGND:
|
||||
force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN,
|
||||
env->ctrl[CR_BADADDR]);
|
||||
break;
|
||||
|
||||
case EXCP_TRAP:
|
||||
/*
|
||||
* TODO: This advance should be done in the translator, as
|
||||
|
@ -64,6 +64,13 @@ uint32_t helper_divu(CPUNios2State *env, uint32_t num, uint32_t den)
|
||||
void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
|
||||
{
|
||||
Nios2CPU *cpu = env_archcpu(env);
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
if (unlikely(new_pc & 3)) {
|
||||
env->ctrl[CR_BADADDR] = new_pc;
|
||||
cs->exception_index = EXCP_UNALIGND;
|
||||
cpu_loop_exit_restore(cs, GETPC());
|
||||
}
|
||||
|
||||
/*
|
||||
* Both estatus and bstatus have no constraints on write;
|
||||
@ -74,6 +81,6 @@ void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
|
||||
|
||||
env->ctrl[CR_STATUS] = new_status;
|
||||
env->pc = new_pc;
|
||||
cpu_loop_exit(env_cpu(env));
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -197,11 +197,24 @@ static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
|
||||
|
||||
static void gen_jumpr(DisasContext *dc, int regno, bool is_call)
|
||||
{
|
||||
tcg_gen_mov_tl(cpu_pc, load_gpr(dc, regno));
|
||||
TCGLabel *l = gen_new_label();
|
||||
TCGv test = tcg_temp_new();
|
||||
TCGv dest = load_gpr(dc, regno);
|
||||
|
||||
tcg_gen_andi_tl(test, dest, 3);
|
||||
tcg_gen_brcondi_tl(TCG_COND_NE, test, 0, l);
|
||||
tcg_temp_free(test);
|
||||
|
||||
tcg_gen_mov_tl(cpu_pc, dest);
|
||||
if (is_call) {
|
||||
tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
|
||||
}
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
|
||||
gen_set_label(l);
|
||||
tcg_gen_st_tl(dest, cpu_env, offsetof(CPUNios2State, ctrl[CR_BADADDR]));
|
||||
t_gen_helper_raise_exception(dc, EXCP_UNALIGND);
|
||||
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user