This is an automated email from Gerrit. "liangzhen <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9223
-- gerrit commit 37a5fae1631b55525649c7bd2823576f06f4ae25 Author: liangzhen <[email protected]> Date: Tue May 13 13:49:22 2025 +0800 target/riscv: add `cetrig` control Introduce RISC-V-sepecific `configure` parameter `-cetrig` Change-Id: If490838b81cdd918fae0b29a8e5bf1508afafba2 Signed-off-by: liangzhen <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index 63d07533e6..49e75a44b0 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11638,6 +11638,15 @@ action pairs. @end itemize @end itemize +@itemize +@item @code{-cetrig} @option{disable}|@option{enable} -- determines how OpenOCD should +configure the @code{cetrig} in the dcsr register. Defaults to @option{disable}. + +@itemize +@item @code{cget} returns the currently configured state for @code{cetrig}. +@end itemize +@end itemize + @subsection RISC-V Debug Configuration Commands @deffn {Command} {riscv dump_sample_buf} [base64] diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6fa5e025be..9cbd6030fd 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -251,9 +251,9 @@ typedef struct { /* This target was selected using hasel. */ bool selected; - /* When false, we need to set dcsr.ebreak*, halting the target if that's - * necessary. */ - bool dcsr_ebreak_is_set; + /* When false, we need to configure certain bits in the dcsr register. + * To do that, we may momentarily halt the target, if necessary. */ + bool dcsr_register_is_set; /* This hart was placed into a halt group in examine(). */ bool haltgroup_supported; @@ -1681,9 +1681,9 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus) return ERROR_OK; } -static int set_dcsr_ebreak(struct target *target, bool step) +static int set_dcsr_config(struct target *target, bool step) { - LOG_TARGET_DEBUG(target, "Set dcsr.ebreak*"); + LOG_TARGET_DEBUG(target, "Set dcsr config"); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; @@ -1701,18 +1701,20 @@ static int set_dcsr_ebreak(struct target *target, bool step) dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]); dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, config->dcsr_ebreak_fields[RISCV_MODE_VS]); dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, config->dcsr_ebreak_fields[RISCV_MODE_VU]); + dcsr = set_field(dcsr, CSR_DCSR_CETRIG, config->dcsr_cetrig); if (dcsr != original_dcsr && riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; - info->dcsr_ebreak_is_set = true; + // TODO: Read back the DCSR and check if these WARL bits are set as the user intended. + info->dcsr_register_is_set = true; return ERROR_OK; } -static int halt_set_dcsr_ebreak(struct target *target) +static int halt_set_dcsr_config(struct target *target) { RISCV_INFO(r); RISCV013_INFO(info); - LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*"); + LOG_TARGET_DEBUG(target, "Halt to set dcsr config"); /* Remove this hart from the halt group. This won't work on all targets * because the debug spec allows halt groups to be hard-coded, but I @@ -1750,7 +1752,7 @@ static int halt_set_dcsr_ebreak(struct target *target) r->prepped = true; if (riscv013_halt_go(target) != ERROR_OK || - set_dcsr_ebreak(target, false) != ERROR_OK || + set_dcsr_config(target, false) != ERROR_OK || riscv013_step_or_resume_current_hart(target, false) != ERROR_OK) { result = ERROR_FAIL; } else { @@ -2139,7 +2141,7 @@ static int examine(struct target *target) if (result != ERROR_OK) return result; - if (set_dcsr_ebreak(target, false) != ERROR_OK) + if (set_dcsr_config(target, false) != ERROR_OK) return ERROR_FAIL; if (state_at_examine_start == RISCV_STATE_RUNNING) { @@ -2786,7 +2788,7 @@ static int riscv013_get_hart_state(struct target *target, enum riscv_hart_state return ERROR_FAIL; if (get_field(dmstatus, DM_DMSTATUS_ANYHAVERESET)) { LOG_TARGET_INFO(target, "Hart unexpectedly reset!"); - info->dcsr_ebreak_is_set = false; + info->dcsr_register_is_set = false; /* TODO: Can we make this more obvious to eg. a gdb user? */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_ACKHAVERESET; @@ -2837,17 +2839,17 @@ static int handle_became_unavailable(struct target *target, riscv_reg_cache_invalidate_all(target); - info->dcsr_ebreak_is_set = false; + info->dcsr_register_is_set = false; return ERROR_OK; } static int tick(struct target *target) { RISCV013_INFO(info); - if (!info->dcsr_ebreak_is_set && + if (!info->dcsr_register_is_set && target->state == TARGET_RUNNING && target_was_examined(target)) - return halt_set_dcsr_ebreak(target); + return halt_set_dcsr_config(target); return ERROR_OK; } @@ -2946,13 +2948,13 @@ static int assert_reset(struct target *target) return riscv013_invalidate_cached_progbuf(target); } -static bool dcsr_ebreak_config_equals_reset_value(const struct target *target) +static bool dcsr_config_equals_reset_value(const struct target *target) { const struct riscv_private_config * const config = riscv_private_config(target); for (int i = 0; i < N_RISCV_MODE; ++i) if (config->dcsr_ebreak_fields[i]) return false; - return true; + return !config->dcsr_cetrig; } static int deassert_reset(struct target *target) @@ -3030,7 +3032,7 @@ static int deassert_reset(struct target *target) target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } - info->dcsr_ebreak_is_set = dcsr_ebreak_config_equals_reset_value(target); + info->dcsr_register_is_set = dcsr_config_equals_reset_value(target); return ERROR_OK; } @@ -5381,6 +5383,16 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) return RISCV_HALT_INTERRUPT; case CSR_DCSR_CAUSE_GROUP: return RISCV_HALT_GROUP; + case CSR_DCSR_CAUSE_OTHER: + switch (get_field(dcsr, CSR_DCSR_EXTCAUSE)) { + case 0: + LOG_TARGET_WARNING(target, "halted because of hart in a critical error state."); + return RISCV_HALT_CRITICAL_ERROR; + default: + LOG_TARGET_ERROR(target, "Unknown DCSR extcause field: 0x%" + PRIx64, get_field(dcsr, CSR_DCSR_EXTCAUSE)); + return RISCV_HALT_UNKNOWN; + } } LOG_TARGET_ERROR(target, "Unknown DCSR cause field: 0x%" PRIx64, get_field(dcsr, CSR_DCSR_CAUSE)); @@ -5476,7 +5488,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (execute_autofence(target) != ERROR_OK) return ERROR_FAIL; - if (set_dcsr_ebreak(target, step) != ERROR_OK) + if (set_dcsr_config(target, step) != ERROR_OK) return ERROR_FAIL; if (riscv_reg_flush_all(target) != ERROR_OK) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8054a1c9b7..bfa8addde0 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -486,6 +486,8 @@ static struct riscv_private_config *alloc_default_riscv_private_config(void) for (unsigned int i = 0; i < ARRAY_SIZE(config->dcsr_ebreak_fields); ++i) config->dcsr_ebreak_fields[i] = true; + config->dcsr_cetrig = true; + return config; } @@ -525,6 +527,15 @@ static struct jim_nvp nvp_ebreak_mode_opts[] = { { .name = NULL, .value = RISCV_EBREAK_MODE_INVALID } }; + +#define RISCV_CETRIG_INVALID -1 + +static struct jim_nvp nvp_cetrig_opts[] = { + { .name = "disable", .value = false }, + { .name = "enable", .value = true }, + { .name = NULL, .value = RISCV_CETRIG_INVALID } +}; + static int jim_configure_ebreak(struct riscv_private_config *config, struct jim_getopt_info *goi) { if (goi->argc == 0) { @@ -611,13 +622,42 @@ static int jim_report_ebreak_config(const struct riscv_private_config *config, return JIM_OK; } +static int jim_configure_cetrig(struct riscv_private_config *config, + struct jim_getopt_info *goi) +{ + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv - 1, + "?disable|enable?"); + return JIM_ERR; + } + + struct jim_nvp *opt_nvp; + if (jim_getopt_nvp(goi, nvp_cetrig_opts, &opt_nvp) != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_cetrig_opts, /*hadprefix*/ true); + return JIM_ERR; + } + config->dcsr_cetrig = opt_nvp->value; + return JIM_OK; +} + +static int jim_report_cetrig_config(const struct riscv_private_config *config, + Jim_Interp *interp) +{ + const char *cetrig_opt = jim_nvp_value2name_simple(nvp_cetrig_opts, + config->dcsr_cetrig)->name; + Jim_SetResultString(interp, cetrig_opt, strlen(cetrig_opt)); + return JIM_OK; +} + enum riscv_cfg_opts { RISCV_CFG_EBREAK, + RISCV_CFG_CETRIG, RISCV_CFG_INVALID = -1 }; static struct jim_nvp nvp_config_opts[] = { { .name = "-ebreak", .value = RISCV_CFG_EBREAK }, + { .name = "-cetrig", .value = RISCV_CFG_CETRIG }, { .name = NULL, .value = RISCV_CFG_INVALID } }; @@ -654,6 +694,10 @@ static int riscv_jim_configure(struct target *target, return goi->is_configure ? jim_configure_ebreak(config, goi) : jim_report_ebreak_config(config, goi->interp); + case RISCV_CFG_CETRIG: + return goi->is_configure + ? jim_configure_cetrig(config, goi) + : jim_report_cetrig_config(config, goi->interp); default: assert(false && "'jim_getopt_nvp' should have returned an error."); } @@ -2617,6 +2661,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r break; case RISCV_HALT_INTERRUPT: case RISCV_HALT_GROUP: + case RISCV_HALT_CRITICAL_ERROR: target->debug_reason = DBG_REASON_DBGRQ; break; case RISCV_HALT_SINGLESTEP: diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2a0a9b95f0..d1a72c88e5 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -75,6 +75,7 @@ enum riscv_halt_reason { RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN, RISCV_HALT_GROUP, + RISCV_HALT_CRITICAL_ERROR, RISCV_HALT_ERROR }; @@ -378,6 +379,7 @@ enum riscv_priv_mode { struct riscv_private_config { bool dcsr_ebreak_fields[N_RISCV_MODE]; + bool dcsr_cetrig; }; static inline struct riscv_private_config --
