Record whether a hart has a Debug Module ROM entry point and keep the CPU in Debug Mode while that ROM is active, instead of always returning to dpc on the next exec loop entry.
This updates Debug Mode entry so dpc follows the architectural cause rules, switches ROM and Program Buffer execution to M-mode, and lets later DM patches hand control to the ROM park loop. Signed-off-by: Chao Liu <[email protected]> --- target/riscv/cpu.h | 4 +++- target/riscv/cpu_helper.c | 27 ++++++++++++++++++++++++++- target/riscv/tcg/tcg-cpu.c | 10 ++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6fb255c7c3..0bc14f6953 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -481,9 +481,11 @@ struct CPUArchState { target_ulong dpc; target_ulong dscratch[2]; - /* Pending Debug Module halt request from the board-level controller. */ + /* DM halt request (set by external Debug Module GPIO) */ bool dm_halt_request; uint8_t dm_halt_cause; + bool dm_rom_present; + uint64_t dm_halt_addr; uint64_t mstateen[SMSTATEEN_MAX_COUNT]; uint64_t hstateen[SMSTATEEN_MAX_COUNT]; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index a0874f4e23..714dcb446e 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -141,6 +141,24 @@ static bool riscv_sdext_enabled(CPURISCVState *env) { return riscv_cpu_cfg(env)->ext_sdext; } + +/* + * Debug Spec v1.0 Table 9: + * - ebreak: dpc = address of the ebreak instruction. + * - step/trigger/haltreq (and reset/group/other): dpc = next instruction + * to execute when Debug Mode was entered. + */ +static target_ulong riscv_debug_dpc_on_entry(CPURISCVState *env, + target_ulong trap_pc, + uint32_t cause) +{ + switch (cause & 0x7) { + case DCSR_CAUSE_EBREAK: + return trap_pc & get_xepc_mask(env); + default: + return env->pc & get_xepc_mask(env); + } +} #endif void riscv_cpu_enter_debug_mode(CPURISCVState *env, target_ulong pc, @@ -152,7 +170,7 @@ void riscv_cpu_enter_debug_mode(CPURISCVState *env, target_ulong pc, } env->debug_mode = true; - env->dpc = pc & get_xepc_mask(env); + env->dpc = riscv_debug_dpc_on_entry(env, pc, cause); env->dcsr &= ~(DCSR_CAUSE_MASK | DCSR_PRV_MASK | DCSR_V); env->dcsr |= ((target_ulong)(cause & 0x7)) << DCSR_CAUSE_SHIFT; env->dcsr |= env->priv & DCSR_PRV_MASK; @@ -168,6 +186,13 @@ void riscv_cpu_enter_debug_mode(CPURISCVState *env, target_ulong pc, } env->elp = false; } + + /* + * Per RISC-V Debug Spec v1.0 Section 4.1: + * "All operations are executed with machine mode privilege." + * Switch to M-mode so ROM/progbuf fetches use physical addressing. + */ + riscv_cpu_set_mode(env, PRV_M, false); #endif } diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 53d862080c..4674ff3e3c 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -280,6 +280,16 @@ static void riscv_cpu_exec_enter(CPUState *cs) if (!cpu->cfg.ext_sdext || !env->debug_mode) { return; } + + /* + * When a DM ROM is present, the CPU must stay in debug mode and + * execute ROM code. DRET will leave debug mode later. Without a DM + * ROM, leave debug mode immediately (legacy shortcut). + */ + if (env->dm_rom_present) { + return; + } + target_ulong pc = env->dpc; riscv_cpu_leave_debug_mode(env); env->pc = pc; -- 2.53.0
