target/arm: only update pc after semihosting completes

Before we introduce blocking semihosting calls we need to ensure we
can restart the system on semi hosting exception. To be able to do
this the EXCP_SEMIHOST operation should be idempotent until it finally
completes. Practically this means ensureing we only update the pc
after the semihosting call has completed.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Keith Packard <keithp@keithp.com>
Tested-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
Alex Bennée 2019-12-17 15:08:57 +00:00
parent b906acbb3a
commit 4ff5ef9e91
6 changed files with 9 additions and 4 deletions

View File

@ -130,6 +130,7 @@ void cpu_loop(CPUARMState *env)
break; break;
case EXCP_SEMIHOST: case EXCP_SEMIHOST:
env->xregs[0] = do_arm_semihosting(env); env->xregs[0] = do_arm_semihosting(env);
env->pc += 4;
break; break;
case EXCP_YIELD: case EXCP_YIELD:
/* nothing to do here for user-mode, just resume guest code */ /* nothing to do here for user-mode, just resume guest code */

View File

@ -377,6 +377,7 @@ void cpu_loop(CPUARMState *env)
break; break;
case EXCP_SEMIHOST: case EXCP_SEMIHOST:
env->regs[0] = do_arm_semihosting(env); env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
break; break;
case EXCP_INTERRUPT: case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */ /* just indicate that signals should be handled asap */

View File

@ -8614,11 +8614,13 @@ static void handle_semihosting(CPUState *cs)
"...handling as semihosting call 0x%" PRIx64 "\n", "...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]); env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env); env->xregs[0] = do_arm_semihosting(env);
env->pc += 4;
} else { } else {
qemu_log_mask(CPU_LOG_INT, qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n", "...handling as semihosting call 0x%x\n",
env->regs[0]); env->regs[0]);
env->regs[0] = do_arm_semihosting(env); env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
} }
} }
#endif #endif

View File

@ -2185,6 +2185,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
"...handling as semihosting call 0x%x\n", "...handling as semihosting call 0x%x\n",
env->regs[0]); env->regs[0]);
env->regs[0] = do_arm_semihosting(env); env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
return; return;
case EXCP_BKPT: case EXCP_BKPT:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);

View File

@ -1937,7 +1937,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
break; break;
} }
#endif #endif
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else { } else {
unsupported_encoding(s, insn); unsupported_encoding(s, insn);
} }

View File

@ -1124,7 +1124,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
s->current_el != 0 && s->current_el != 0 &&
#endif #endif
(imm == (s->thumb ? 0x3c : 0xf000))) { (imm == (s->thumb ? 0x3c : 0xf000))) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
return; return;
} }
@ -8457,7 +8457,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
!IS_USER(s) && !IS_USER(s) &&
#endif #endif
(a->imm == 0xab)) { (a->imm == 0xab)) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else { } else {
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false)); gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
} }
@ -10266,7 +10266,7 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
!IS_USER(s) && !IS_USER(s) &&
#endif #endif
(a->imm == semihost_imm)) { (a->imm == semihost_imm)) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST); gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else { } else {
gen_set_pc_im(s, s->base.pc_next); gen_set_pc_im(s, s->base.pc_next);
s->svc_imm = a->imm; s->svc_imm = a->imm;