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/+/9224
-- gerrit commit 59a4e60b86d912821b390c424a6b4ee349b9629b Author: liangzhen <[email protected]> Date: Mon Mar 31 15:18:52 2025 +0800 target/riscv: Introduce `riscv set_group` command Add support for associating a halt/resume group with current target or an external trigger via a newly exposed configuration option "riscv set_group". Change-Id: I343dbbfa5c6c1043cf6a939b4d6352adaee3703c Signed-off-by: liangzhen <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index 63d07533e6..531c00d752 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11874,6 +11874,22 @@ The second argument configures how OpenOCD should use the selected trigger featu With no parameters, prints current trigger features configuration. @end deffn +@deffn {Command} {riscv set_group} <@option{halt_group}|@option{resume_group}> group ['trigger' triggernum] +OpenOCD assigns a hart or a given external trigger into a RISC-V halt/resume group. +This command associates current target or supplied external trigger(s) with this halt/resume group. + +@option{trigger} and @var{triggernum} Specify the index of the external trigger. +When an external input trigger fires, the harts in the halt/resume group will get halted/resume. +Similarly, all external output triggers will be notified when a hart in the halt/resume group halts/resumes. + +The only supported value of @var{grouptype} is @option{halt_group}. RISC-V resume groups +are not allowed because the concept of a target resuming due to a different reason than +user's resume request is not supported by OpenOCD and GDB. Allowing @var{grouptype} to +be set to @option{resume_group} might be useful for hardware testing, but OpenOCD will +report a warning. +@end deffn + + @subsection RISC-V Authentication Commands The following commands can be used to authenticate to a RISC-V system. Eg. a diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6fa5e025be..3d6a404de8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -68,12 +68,8 @@ static int riscv013_access_memory(struct target *target, const struct riscv_mem_ static bool riscv013_get_impebreak(const struct target *target); static unsigned int riscv013_get_progbufsize(const struct target *target); -enum grouptype { - HALT_GROUP, - RESUME_GROUP -}; static int set_group(struct target *target, bool *supported, unsigned int group, - enum grouptype grouptype); + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -138,6 +134,8 @@ typedef struct { * abstractcs.busy may have remained set. In that case we may need to * re-check the busy state before executing these operations. */ bool abstract_cmd_maybe_busy; + + struct riscv_ext_trigger external_triggers[RISCV_MAX_EXTTRIGGERS]; } dm013_info_t; typedef struct { @@ -1739,7 +1737,7 @@ static int halt_set_dcsr_ebreak(struct target *target) if (info->haltgroup_supported) { bool supported; - if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK) + if (set_group(target, &supported, 0, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; if (!supported) LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. " @@ -1761,7 +1759,7 @@ static int halt_set_dcsr_ebreak(struct target *target) /* Add it back to the halt group. */ if (info->haltgroup_supported) { bool supported; - if (set_group(target, &supported, target->smp, HALT_GROUP) != ERROR_OK) + if (set_group(target, &supported, target->smp, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; if (!supported) LOG_TARGET_ERROR(target, "Couldn't place hart back in halt group %d. " @@ -1792,19 +1790,54 @@ static void deinit_target(struct target *target) } static int set_group(struct target *target, bool *supported, unsigned int group, - enum grouptype grouptype) + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num) { - uint32_t write_val = DM_DMCS2_HGWRITE; assert(group <= 31); + assert(trigger_num < 16); + + if (!is_trigger && dm013_select_target(target) != ERROR_OK) + return ERROR_FAIL; + + dm013_info_t *dm = get_dm(target); + if (!dm) + return ERROR_FAIL; + if (is_trigger && ((dm->external_triggers[trigger_num].haltgroup_was_set && + dm->external_triggers[trigger_num].haltgroup_num == group) || + (dm->external_triggers[trigger_num].resumegroup_was_set && + dm->external_triggers[trigger_num].resumegroup_num == group))) { + LOG_TARGET_WARNING(target, "External trigger %d (at address dbgbase=0x%" PRIx32 ") " + "for %s group %d has been set.", trigger_num, dm->base, + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + return ERROR_OK; + } + + uint32_t write_val = DM_DMCS2_HGWRITE; write_val = set_field(write_val, DM_DMCS2_GROUP, group); write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, (grouptype == HALT_GROUP) ? 0 : 1); + write_val = set_field(write_val, DM_DMCS2_DMEXTTRIGGER, trigger_num); + write_val = set_field(write_val, DM_DMCS2_HGSELECT, + is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : DM_DMCS2_HGSELECT_HARTS); if (dm_write(target, DM_DMCS2, write_val) != ERROR_OK) return ERROR_FAIL; uint32_t read_val; if (dm_read(target, &read_val, DM_DMCS2) != ERROR_OK) return ERROR_FAIL; if (supported) - *supported = (get_field(read_val, DM_DMCS2_GROUP) == group); + *supported = (get_field(read_val, DM_DMCS2_GROUP) == group && + get_field(read_val, DM_DMCS2_GROUPTYPE) == ((grouptype == HALT_GROUP) ? 0 : 1) && + get_field(read_val, DM_DMCS2_HGSELECT) == + (is_trigger ? DM_DMCS2_HGSELECT_TRIGGERS : DM_DMCS2_HGSELECT_HARTS) && + get_field(read_val, DM_DMCS2_DMEXTTRIGGER) == trigger_num); + if (is_trigger && *supported) { + if (grouptype == HALT_GROUP) { + dm->external_triggers[trigger_num].haltgroup_was_set = true; + dm->external_triggers[trigger_num].haltgroup_num = group; + } else { + dm->external_triggers[trigger_num].resumegroup_was_set = true; + dm->external_triggers[trigger_num].resumegroup_num = group; + } + } + return ERROR_OK; } @@ -2152,8 +2185,9 @@ static int examine(struct target *target) } if (target->smp) { - if (set_group(target, &info->haltgroup_supported, target->smp, HALT_GROUP) != ERROR_OK) + if (set_group(target, &info->haltgroup_supported, target->smp, HALT_GROUP, false, 0) != ERROR_OK) return ERROR_FAIL; + if (info->haltgroup_supported) LOG_TARGET_INFO(target, "Core %d made part of halt group %d.", info->index, target->smp); @@ -2888,6 +2922,8 @@ static int init_target(struct command_context *cmd_ctx, generic_info->handle_became_unavailable = &handle_became_unavailable; generic_info->tick = &tick; + generic_info->set_group = &set_group; + if (!generic_info->version_specific) { generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); if (!generic_info->version_specific) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8054a1c9b7..6f272dd959 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -5576,6 +5576,80 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_group) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC < 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + enum grouptype grouptype; + if (!strcmp("halt_group", CMD_ARGV[0])) { + grouptype = HALT_GROUP; + } else if (!strcmp("resume_group", CMD_ARGV[0])) { + /* Ext. triggers for resume groups are not supported: neither OpenOCD nor GDB + * have a concept of hart resuming on its own due to an external reason, without + * an explicit resume request. */ + LOG_WARNING("triggers for resume groups are not supported, please use with caution."); + grouptype = RESUME_GROUP; + } else { + LOG_ERROR("%s is not a valid argument.", CMD_ARGV[1]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + unsigned int group; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], group); + if (group > 31) { + LOG_ERROR("%d is not a valid group number - expecting a number in range 0..31.", + group); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + if (!r->set_group) { + LOG_TARGET_ERROR(target, "set_group is not implemented for this target."); + return ERROR_FAIL; + } + + bool is_trigger = false; + unsigned int trigger_num = 0; + switch (CMD_ARGC) { + case 2: + break; + case 4: + if (strcmp("trigger", CMD_ARGV[2])) + return ERROR_COMMAND_SYNTAX_ERROR; + is_trigger = true; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], trigger_num); + if (trigger_num > 15) { + LOG_ERROR("%d is not a valid external trigger number - expecting a number in range 0..15.", + trigger_num); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + bool supported; + if (r->set_group(target, &supported, group, grouptype, is_trigger, trigger_num) != ERROR_OK) + return ERROR_FAIL; + + if (supported) + LOG_TARGET_INFO(target, "%s %d made part of %s group %d.", + (is_trigger ? "External trigger" : "Core"), + (is_trigger ? trigger_num : (unsigned int)target->coreid), + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + else + LOG_TARGET_WARNING(target, "%s %d could not be made part of %s group %d.", + (is_trigger ? "External trigger" : "Core"), + (is_trigger ? trigger_num : (unsigned int)target->coreid), + (grouptype == HALT_GROUP) ? "halt" : "resume", group); + + return ERROR_OK; +} + + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5838,6 +5912,13 @@ static const struct command_registration riscv_exec_command_handlers[] = { "When off, users need to take care of memory coherency themselves, for example by using " "`riscv exec_progbuf` to execute fence or CMO instructions." }, + { + .name = "set_group", + .handler = riscv_set_group, + .mode = COMMAND_ANY, + .usage = "<'halt_group'|'resume_group'> group ['trigger' triggernum]", + .help = "Set a hart or a given external trigger to the halt/resume group." + }, { .chain = smp_command_handlers }, diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2a0a9b95f0..91e62fc692 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -21,6 +21,7 @@ struct riscv_program; #define RISCV_MAX_TRIGGERS 32 #define RISCV_MAX_HWBPS 16 #define RISCV_MAX_DMS 100 +#define RISCV_MAX_EXTTRIGGERS 16 #define DEFAULT_COMMAND_TIMEOUT_SEC 5 @@ -122,6 +123,11 @@ typedef struct { char *name; } range_list_t; +enum grouptype { + HALT_GROUP, + RESUME_GROUP +}; + #define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) #define RISCV_TINFO_VERSION_UNKNOWN (-1) @@ -144,6 +150,13 @@ struct riscv_mem_access_args { uint32_t increment; }; +struct riscv_ext_trigger { + bool haltgroup_was_set; + unsigned int haltgroup_num; + bool resumegroup_was_set; + unsigned int resumegroup_num; +}; + static inline bool riscv_mem_access_is_valid(const struct riscv_mem_access_args args) { @@ -307,6 +320,9 @@ struct riscv_info { unsigned int (*data_bits)(struct target *target); + int (*set_group)(struct target *target, bool *supported, unsigned int group, + enum grouptype grouptype, bool is_trigger, unsigned int trigger_num); + COMMAND_HELPER((*print_info), struct target *target); /* Storage for arch_info of non-custom registers. */ --
