aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-04-21 08:17:28 -0700
committerRichard Henderson <richard.henderson@linaro.org>2022-04-26 08:17:05 -0700
commite84f1768449330a5b4c62a8aaa68f102ba6ec573 (patch)
treeaf6ca0b49c5612a35ac77da507974dba9ee71713
parenta25c4eff32ba6192cff648ccaf0316bd829c80af (diff)
downloadqemu-e84f1768449330a5b4c62a8aaa68f102ba6ec573.zip
qemu-e84f1768449330a5b4c62a8aaa68f102ba6ec573.tar.gz
qemu-e84f1768449330a5b4c62a8aaa68f102ba6ec573.tar.bz2
target/nios2: Advance pc when raising exceptions
The exception return address for nios2 is the instruction after the one that was executing at the time of the exception. We have so far implemented this by advancing the pc during the process of raising the exception. It is perhaps a little less confusing to do this advance in the translator (and helpers) when raising the exception in the first place, so that we may more closely match kernel sources. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-Id: <20220421151735.31996-58-richard.henderson@linaro.org>
-rw-r--r--linux-user/nios2/cpu_loop.c8
-rw-r--r--target/nios2/cpu.h2
-rw-r--r--target/nios2/helper.c13
-rw-r--r--target/nios2/op_helper.c18
-rw-r--r--target/nios2/translate.c6
5 files changed, 30 insertions, 17 deletions
diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
index 30a27f2..a5e8699 100644
--- a/linux-user/nios2/cpu_loop.c
+++ b/linux-user/nios2/cpu_loop.c
@@ -39,6 +39,8 @@ void cpu_loop(CPUNios2State *env)
break;
case EXCP_DIV:
+ /* Match kernel's handle_diverror_c(). */
+ env->pc -= 4;
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
@@ -49,12 +51,6 @@ void cpu_loop(CPUNios2State *env)
break;
case EXCP_TRAP:
- /*
- * TODO: This advance should be done in the translator, as
- * hardware produces an advanced pc as part of all exceptions.
- */
- env->pc += 4;
-
switch (env->error_code) {
case 0:
qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 5474b1c..f85581e 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -266,6 +266,8 @@ hwaddr nios2_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
G_NORETURN void nios2_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
MMUAccessType access_type, int mmu_idx,
uintptr_t retaddr);
+G_NORETURN void nios2_cpu_loop_exit_advance(CPUNios2State *env,
+ uintptr_t retaddr);
void do_nios2_semihosting(CPUNios2State *env);
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index e256d15..bb3b09e 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -49,7 +49,7 @@ static void do_exception(Nios2CPU *cpu, uint32_t exception_addr,
cr_es = CR_BSTATUS;
}
env->ctrl[cr_es] = old_status;
- env->regs[r_ea] = env->pc + 4;
+ env->regs[r_ea] = env->pc;
if (cpu->mmu_present) {
new_status |= CR_STATUS_EH;
@@ -113,7 +113,7 @@ static void do_eic_irq(Nios2CPU *cpu)
}
env->shadow_regs[new_rs][R_SSTATUS] = old_status;
}
- env->shadow_regs[new_rs][R_EA] = env->pc + 4;
+ env->shadow_regs[new_rs][R_EA] = env->pc;
}
env->ctrl[CR_STATUS] = new_status;
@@ -187,6 +187,8 @@ void nios2_cpu_do_interrupt(CPUState *cs)
switch (cs->exception_index) {
case EXCP_IRQ:
+ /* Note that PC is advanced for interrupts as well. */
+ env->pc += 4;
if (cpu->eic_present) {
do_eic_irq(cpu);
} else {
@@ -249,7 +251,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
break;
case EXCP_SEMIHOST:
- env->pc += 4;
do_nios2_semihosting(env);
break;
@@ -291,7 +292,7 @@ void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
env->ctrl[CR_BADADDR] = addr;
cs->exception_index = EXCP_UNALIGN;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
@@ -330,7 +331,7 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
cs->exception_index = (access_type == MMU_INST_FETCH
? EXCP_SUPERA_X : EXCP_SUPERA_D);
env->ctrl[CR_BADADDR] = address;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
}
@@ -367,5 +368,5 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
cs->exception_index = excp;
env->ctrl[CR_BADADDR] = address;
- cpu_loop_exit_restore(cs, retaddr);
+ nios2_cpu_loop_exit_advance(env, retaddr);
}
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index 9404010..2e30d0a 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -31,6 +31,20 @@ void helper_raise_exception(CPUNios2State *env, uint32_t index)
cpu_loop_exit(cs);
}
+void nios2_cpu_loop_exit_advance(CPUNios2State *env, uintptr_t retaddr)
+{
+ CPUState *cs = env_cpu(env);
+
+ /*
+ * Note that PC is advanced for all hardware exceptions.
+ * Do this here, rather than in restore_state_to_opc(),
+ * lest we affect QEMU internal exceptions, like EXCP_DEBUG.
+ */
+ cpu_restore_state(cs, retaddr, true);
+ env->pc += 4;
+ cpu_loop_exit(cs);
+}
+
static void maybe_raise_div(CPUNios2State *env, uintptr_t ra)
{
Nios2CPU *cpu = env_archcpu(env);
@@ -38,7 +52,7 @@ static void maybe_raise_div(CPUNios2State *env, uintptr_t ra)
if (cpu->diverr_present) {
cs->exception_index = EXCP_DIV;
- cpu_loop_exit_restore(cs, ra);
+ nios2_cpu_loop_exit_advance(env, ra);
}
}
@@ -69,7 +83,7 @@ void helper_eret(CPUNios2State *env, uint32_t new_status, uint32_t new_pc)
if (unlikely(new_pc & 3)) {
env->ctrl[CR_BADADDR] = new_pc;
cs->exception_index = EXCP_UNALIGND;
- cpu_loop_exit_restore(cs, GETPC());
+ nios2_cpu_loop_exit_advance(env, GETPC());
}
/*
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index b52f981..3a037a6 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -202,10 +202,10 @@ static TCGv dest_gpr(DisasContext *dc, unsigned reg)
#endif
}
-static void t_gen_helper_raise_exception(DisasContext *dc,
- uint32_t index)
+static void t_gen_helper_raise_exception(DisasContext *dc, uint32_t index)
{
- tcg_gen_movi_tl(cpu_pc, dc->pc);
+ /* Note that PC is advanced for all hardware exceptions. */
+ tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
dc->base.is_jmp = DISAS_NORETURN;
}