Skip to content

target/riscv: Add support for external triggers #1243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: riscv
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -11616,6 +11616,11 @@ 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 smp_add_ext_triggers} grouptype1 num1 [grouptype2 num2] ...
Associate the supplied external trigger with the halt group for the harts. When
the external trigger fires the harts in the halt group will be halted.
@end deffn

@subsection RISC-V Authentication Commands

The following commands can be used to authenticate to a RISC-V system. Eg. a
Expand Down
49 changes: 45 additions & 4 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,6 @@ static int riscv013_access_memory(struct target *target, const riscv_mem_access_
static bool riscv013_get_impebreak(const struct target *target);
static unsigned int riscv013_get_progbufsize(const struct target *target);

typedef enum {
HALT_GROUP,
RESUME_GROUP
} grouptype_t;
static int set_group(struct target *target, bool *supported, unsigned int group,
grouptype_t grouptype);

Expand Down Expand Up @@ -1784,6 +1780,37 @@ static void deinit_target(struct target *target)
info->version_specific = NULL;
}

static int smp_add_ext_trigger(struct target *target, unsigned int group,
riscv_ext_trigger_t external_trigger)
{
uint32_t write_val = DM_DMCS2_HGSELECT;
assert(group <= 31);
assert(external_trigger.dmexttrigger < 16);
write_val = set_field(write_val, DM_DMCS2_GROUP, group);
write_val = set_field(write_val, DM_DMCS2_GROUPTYPE, external_trigger.grouptype);
write_val = set_field(write_val, DM_DMCS2_DMEXTTRIGGER, external_trigger.dmexttrigger);
if (dm_write(target, DM_DMCS2, write_val) != ERROR_OK)
return ERROR_FAIL;
write_val = set_field(write_val, DM_DMCS2_HGWRITE, 1);
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 (get_field(read_val, DM_DMCS2_GROUP) == group &&
get_field(read_val, DM_DMCS2_DMEXTTRIGGER) == external_trigger.dmexttrigger &&
get_field(read_val, DM_DMCS2_HGSELECT) == 1) {
LOG_TARGET_INFO(target, "External trigger %d added to %s group %d", external_trigger.dmexttrigger,
external_trigger.grouptype ? "resume" : "halt", group);
} else {
LOG_TARGET_ERROR(target, "External trigger %d not supported %s group %d", external_trigger.dmexttrigger,
external_trigger.grouptype ? "resume" : "halt", group);
}

return ERROR_OK;
}

static int set_group(struct target *target, bool *supported, unsigned int group,
grouptype_t grouptype)
{
Expand Down Expand Up @@ -2153,6 +2180,20 @@ static int examine(struct target *target)
else
LOG_TARGET_INFO(target, "Core %d could not be made part of halt group %d.",
info->index, target->smp);

/* TODO: Resume groups with external input triggers look to be very problematic.
* Neither OpenOCD nor GDB is ready for the case when a target suddenly
* resumes (due to the trigger), without an explicit resume request and
* at arbitrary moment in time. */

for (unsigned int i = 0; i < RISCV_MAX_EXTTRIGGERS; i++) {
if (r->external_triggers[i].is_set) {
if (smp_add_ext_trigger(target, target->smp, r->external_triggers[i]) != ERROR_OK)
return ERROR_FAIL;
} else {
break;
}
}
}

/* Some regression suites rely on seeing 'Examined RISC-V core' to know
Expand Down
47 changes: 47 additions & 0 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -5588,6 +5588,46 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode)
return ERROR_OK;
}

COMMAND_HANDLER(riscv_smp_add_ext_triggers)
{
struct target *target = get_current_target(CMD_CTX);
RISCV_INFO(r);

if (CMD_ARGC % 2) {
LOG_ERROR("Command takes an even number of parameters.");
return ERROR_COMMAND_SYNTAX_ERROR;
}

if (CMD_ARGC > 2 * RISCV_MAX_EXTTRIGGERS) {
LOG_ERROR("The number of parameters can not exceeds %d.", 2 * RISCV_MAX_EXTTRIGGERS);
return ERROR_COMMAND_SYNTAX_ERROR;
}

unsigned int index = 0;
for (unsigned int i = 0; i < CMD_ARGC - 1; i += 2) {
if (!strcmp("halt_group", CMD_ARGV[i])) {
r->external_triggers[index].grouptype = HALT_GROUP;
} else if (!strcmp("resume_group", CMD_ARGV[i])) {
r->external_triggers[index].grouptype = RESUME_GROUP;
} else {
LOG_ERROR("%s is not a valid argument for command,"
"should be halt_group or resume_group.", CMD_ARGV[0]);
return ERROR_COMMAND_SYNTAX_ERROR;
}
int value = atoi(CMD_ARGV[i + 1]);
if (value < 0 || value > 15) {
LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[i + 1]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came up in the previous review - 0 is a valid external trigger. Also 16 is not a valid - so should this be (value < 0 || value >= 16)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

return ERROR_FAIL;
}
r->external_triggers[index].dmexttrigger = value;
r->external_triggers[index].is_set = true;
index++;
}

return ERROR_OK;
}


static const struct command_registration riscv_exec_command_handlers[] = {
{
.name = "dump_sample_buf",
Expand Down Expand Up @@ -5850,6 +5890,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 = "smp_add_ext_triggers",
.handler = riscv_smp_add_ext_triggers,
.mode = COMMAND_CONFIG,
.usage = "grouptype1 num1 [grouptype2 num2]......",
.help = "Add the given external triggers to the halt/resume group"
},
COMMAND_REGISTRATION_DONE
};

Expand Down
14 changes: 14 additions & 0 deletions src/target/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 32

#define DEFAULT_COMMAND_TIMEOUT_SEC 5

Expand Down Expand Up @@ -144,6 +145,17 @@ typedef struct riscv_mem_access_args {
uint32_t increment;
} riscv_mem_access_args_t;

typedef enum {
HALT_GROUP,
RESUME_GROUP
} grouptype_t;

typedef struct {
grouptype_t grouptype;
uint32_t dmexttrigger;
bool is_set;
} riscv_ext_trigger_t;

static inline bool
riscv_mem_access_is_valid(const riscv_mem_access_args_t args)
{
Expand Down Expand Up @@ -365,6 +377,8 @@ struct riscv_info {
bool wp_allow_ge_lt_trigger;

bool autofence;

riscv_ext_trigger_t external_triggers[RISCV_MAX_EXTTRIGGERS];
};

enum riscv_priv_mode {
Expand Down
Loading