Skip to content

Commit

Permalink
provide riscv-specific controls to disable triggers from beeing used …
Browse files Browse the repository at this point in the history
…for watchpoints

Add a new riscv specific commands to disable triggers

Change-Id: Ic1842085aa66851c740e0abcbfbe0adbe930920e
Signed-off-by: Kirill Radkin <[email protected]>
  • Loading branch information
kr-sc committed Sep 25, 2023
1 parent 67c2835 commit fb9486a
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 44 deletions.
14 changes: 14 additions & 0 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -10871,6 +10871,20 @@ Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to
OpenOCD. When off, they generate a breakpoint exception handled internally.
@end deffn

The commands below can be used to prevent OpenOCD from using certain RISC-V trigger features, for example in cases when there are known issues in the target hardware.

@deffn {Command} {riscv eq_match_trigger_enable} [on|off]
When on (default), allow OpenOCD to use exact-match triggers in watchpoints.
@end deffn

@deffn {Command} {riscv napot_trigger_enable} [on|off]
When on (default), allow OpenOCD to use NAPOT trigger in watchpoints.
@end deffn

@deffn {Command} {riscv ge_lt_trigger_enable} [on|off]
When on (default), allow OpenOCD to use a pair of chained less-than & greater-than triggers in watchpoints.
@end deffn

@subsection RISC-V Authentication Commands

The following commands can be used to authenticate to a RISC-V system. Eg. a
Expand Down
198 changes: 154 additions & 44 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -860,15 +860,16 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6(
return result;
}

static int maybe_add_trigger_t2_t6(struct target *target,
static int maybe_add_trigger_t2_t6_for_wp(struct target *target,
struct trigger *trigger, struct match_triggers_tdata1_fields fields)
{
int ret = ERROR_OK;
RISCV_INFO(r);
int ret = ERROR_FAIL;

if (!trigger->is_execute && trigger->length > 1) {
if (trigger->length > 0) {
/* Setting a load/store trigger ("watchpoint") on a range of addresses */

if (can_use_napot_match(trigger)) {
if (r->enable_napot_trigger && can_use_napot_match(trigger)) {
LOG_TARGET_DEBUG(target, "trying to setup NAPOT match trigger");
struct trigger_request_info napot = {
.tdata1 = fields.common | fields.size.any |
Expand All @@ -880,52 +881,58 @@ static int maybe_add_trigger_t2_t6(struct target *target,
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
LOG_TARGET_DEBUG(target, "trying to setup GE+LT chained match trigger pair");
struct trigger_request_info ge_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info lt_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;

LOG_TARGET_DEBUG(target, "trying to setup LT+GE chained match trigger pair");
struct trigger_request_info lt_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info ge_2 = {
if (r->enable_ge_lt_trigger) {
LOG_TARGET_DEBUG(target, "trying to setup GE+LT chained match trigger pair");
struct trigger_request_info ge_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info lt_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;

LOG_TARGET_DEBUG(target, "trying to setup LT+GE chained match trigger pair");
struct trigger_request_info lt_1 = {
.tdata1 = fields.common | fields.size.any | fields.chain.enable |
fields.match.lt,
.tdata2 = trigger->address + trigger->length,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
struct trigger_request_info ge_2 = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.ge,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
}
}

if (r->enable_equality_match_trigger) {
LOG_TARGET_DEBUG(target, "trying to setup equality match trigger");
struct trigger_request_info eq = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.ge,
fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2);
if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
return ret;
ret = try_setup_single_match_trigger(target, trigger, eq);
if (ret != ERROR_OK)
return ERROR_FAIL;
}
LOG_TARGET_DEBUG(target, "trying to setup equality match trigger");
struct trigger_request_info eq = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};
ret = try_setup_single_match_trigger(target, trigger, eq);
if (ret != ERROR_OK)
return ret;

if (trigger->length > 1) {
if (ret == ERROR_OK && trigger->length > 1) {
LOG_TARGET_DEBUG(target, "Trigger will match accesses at address 0x%" TARGET_PRIxADDR
", but may not match accesses at addresses in the inclusive range from 0x%"
TARGET_PRIxADDR " to 0x%" TARGET_PRIxADDR ".", trigger->address,
Expand All @@ -941,7 +948,34 @@ static int maybe_add_trigger_t2_t6(struct target *target,
"against the first address of the range.");
info->range_trigger_fallback_encountered = true;
}
return ERROR_OK;

return ret;
}

static int maybe_add_trigger_t2_t6_for_bp(struct target *target,
struct trigger *trigger, struct match_triggers_tdata1_fields fields)
{
LOG_TARGET_DEBUG(target, "trying to setup equality match trigger");
struct trigger_request_info eq = {
.tdata1 = fields.common | fields.size.any | fields.chain.disable |
fields.match.eq,
.tdata2 = trigger->address,
.tdata1_ignore_mask = fields.tdata1_ignore_mask
};

return try_setup_single_match_trigger(target, trigger, eq);
}

static int maybe_add_trigger_t2_t6(struct target *target,
struct trigger *trigger, struct match_triggers_tdata1_fields fields)
{
if (trigger->is_execute) {
assert(!trigger->is_read && !trigger->is_write);
return maybe_add_trigger_t2_t6_for_bp(target, trigger, fields);
}

assert(trigger->is_read || trigger->is_write);
return maybe_add_trigger_t2_t6_for_wp(target, trigger, fields);
}

static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu,
Expand Down Expand Up @@ -4255,6 +4289,57 @@ COMMAND_HANDLER(riscv_exec_progbuf)
return ERROR_OK;
}

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

if (CMD_ARGC == 0) {
command_print(CMD, "equality match trigger enabled = %d", r->enable_equality_match_trigger);
return ERROR_OK;
} else if (CMD_ARGC == 1) {
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->enable_equality_match_trigger);
return ERROR_OK;
}

LOG_ERROR("Command takes 0 or 1 parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
}

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

if (CMD_ARGC == 0) {
command_print(CMD, "NAPOT trigger enabled = %d", r->enable_napot_trigger);
return ERROR_OK;
} else if (CMD_ARGC == 1) {
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->enable_napot_trigger);
return ERROR_OK;
}

LOG_ERROR("Command takes 0 or 1 parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
}

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

if (CMD_ARGC == 0) {
command_print(CMD, "ge-lt triggers enabled = %d", r->enable_ge_lt_trigger);
return ERROR_OK;
} else if (CMD_ARGC == 1) {
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->enable_ge_lt_trigger);
return ERROR_OK;
}

LOG_ERROR("Command takes 0 or 1 parameters");
return ERROR_COMMAND_SYNTAX_ERROR;
}

static const struct command_registration riscv_exec_command_handlers[] = {
{
.name = "dump_sample_buf",
Expand Down Expand Up @@ -4501,6 +4586,27 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.help = "Execute a sequence of 32-bit instructions using the program buffer. "
"The final ebreak instruction is added automatically, if needed."
},
{
.name = "eq_match_trigger_enable",
.handler = riscv_eq_match_trigger_enable,
.mode = COMMAND_CONFIG,
.usage = "[on|off]",
.help = "When on, allow OpenOCD to use equality match trigger in wp."
},
{
.name = "napot_trigger_enable",
.handler = riscv_napot_trigger_enable,
.mode = COMMAND_CONFIG,
.usage = "[on|off]",
.help = "When on, allow OpenOCD to use NAPOT trigger in wp."
},
{
.name = "ge_lt_trigger_enable",
.handler = riscv_ge_lt_trigger_enable,
.mode = COMMAND_CONFIG,
.usage = "[on|off]",
.help = "When on, allow OpenOCD to use GE/LT triggers in wp."
},
COMMAND_REGISTRATION_DONE
};

Expand Down Expand Up @@ -4632,6 +4738,10 @@ static void riscv_info_init(struct target *target, struct riscv_info *r)
INIT_LIST_HEAD(&r->hide_csr);

r->vsew64_supported = YNM_MAYBE;

r->enable_equality_match_trigger = true;
r->enable_ge_lt_trigger = true;
r->enable_napot_trigger = true;
}

static int riscv_resume_go_all_harts(struct target *target)
Expand Down
4 changes: 4 additions & 0 deletions src/target/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ struct riscv_info {
yes_no_maybe_t vsew64_supported;

bool range_trigger_fallback_encountered;

bool enable_equality_match_trigger;
bool enable_napot_trigger;
bool enable_ge_lt_trigger;
};

COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
Expand Down

0 comments on commit fb9486a

Please sign in to comment.