From ee2bc807eb64d876754114958ea538d61a4770a6 Mon Sep 17 00:00:00 2001 From: Kirill Radkin Date: Wed, 13 Sep 2023 12:48:32 +0300 Subject: [PATCH] openocd does not allow to query status of dcsr.ebreak{u,s,m} Extend riscv set_ebreak* commands. Now it can be called without args to print current value. riscv_ebreak* flags are moved to riscv_info struct. Change-Id: Ib46e6b6dfc0117599c7f6715c7aaf113e63bd7dc Signed-off-by: Kirill Radkin --- doc/openocd.texi | 6 ++-- src/target/riscv/riscv-011.c | 14 ++++---- src/target/riscv/riscv-013.c | 11 ++++--- src/target/riscv/riscv.c | 64 ++++++++++++++++++++++++------------ src/target/riscv/riscv.h | 7 ++-- 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index fb2eaa9b99..275c255240 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10856,17 +10856,17 @@ Keep in mind, disabling the option does not guarantee that single stepping will To make that happen, dcsr.stepie would have to be written to 1 as well. @end deffn -@deffn {Command} {riscv set_ebreakm} on|off +@deffn {Command} {riscv set_ebreakm} [on|off] Control dcsr.ebreakm. When on (default), M-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn -@deffn {Command} {riscv set_ebreaks} on|off +@deffn {Command} {riscv set_ebreaks} [on|off] Control dcsr.ebreaks. When on (default), S-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn -@deffn {Command} {riscv set_ebreaku} on|off +@deffn {Command} {riscv set_ebreaku} [on|off] Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to OpenOCD. When off, they generate a breakpoint exception handled internally. @end deffn diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index a007d377e0..fb94983529 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1104,6 +1104,7 @@ static int maybe_write_tselect(struct target *target) static int execute_resume(struct target *target, bool step) { + RISCV_INFO(r); riscv011_info_t *info = get_info(target); LOG_DEBUG("step=%d", step); @@ -1135,9 +1136,9 @@ static int execute_resume(struct target *target, bool step) } } - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr &= ~DCSR_HALT; @@ -1936,6 +1937,7 @@ static int riscv011_resume(struct target *target, int current, static int assert_reset(struct target *target) { + RISCV_INFO(r); riscv011_info_t *info = get_info(target); /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ @@ -1949,9 +1951,9 @@ static int assert_reset(struct target *target) /* Not sure what we should do when there are multiple cores. * Here just reset the single hart we're talking to. */ - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, riscv_ebreaku); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); + info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); info->dcsr |= DCSR_HALT; if (target->reset_halt) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9122d28460..93698f85a2 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1755,6 +1755,7 @@ static int set_dcsr_ebreak(struct target *target, bool step) if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; + RISCV_INFO(r); RISCV013_INFO(info); riscv_reg_t original_dcsr, dcsr; /* We want to twiddle some bits in the debug CSR so debugging works. */ @@ -1762,11 +1763,11 @@ static int set_dcsr_ebreak(struct target *target, bool step) return ERROR_FAIL; original_dcsr = dcsr; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks && riscv_supports_extension(target, 'S')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku && riscv_supports_extension(target, 'U')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, riscv_ebreaku && riscv_supports_extension(target, 'H')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, riscv_ebreaku && riscv_supports_extension(target, 'H')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); if (dcsr != original_dcsr && riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 4b33eb7607..6781920d93 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -135,9 +135,6 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; static bool riscv_enable_virt2phys = true; -bool riscv_ebreakm = true; -bool riscv_ebreaks = true; -bool riscv_ebreaku = true; bool riscv_enable_virtual; @@ -3748,32 +3745,53 @@ COMMAND_HANDLER(riscv_set_enable_virt2phys) COMMAND_HANDLER(riscv_set_ebreakm) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreakm enabled: %s", r->riscv_ebreakm ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreakm); + return ERROR_OK; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); - return ERROR_OK; + + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(riscv_set_ebreaks) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreaks enabled: %s", r->riscv_ebreaks ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaks); + return ERROR_OK; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); - return ERROR_OK; + + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(riscv_set_ebreaku) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "riscv_ebreaku enabled: %s", r->riscv_ebreaku ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaku); + return ERROR_OK; } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); - return ERROR_OK; + + LOG_ERROR("Command takes 0 or 1 parameters"); + return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HELPER(riscv_clear_trigger, int trigger_id, const char *name) @@ -4452,7 +4470,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreakm", .handler = riscv_set_ebreakm, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, @@ -4460,7 +4478,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreaks", .handler = riscv_set_ebreaks, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, @@ -4468,7 +4486,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ebreaku", .handler = riscv_set_ebreaku, .mode = COMMAND_ANY, - .usage = "on|off", + .usage = "[on|off]", .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " "don't trap to OpenOCD. Defaults to on." }, @@ -4632,6 +4650,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->riscv_ebreakm = true; + r->riscv_ebreaks = true; + r->riscv_ebreaku = true; } static int riscv_resume_go_all_harts(struct target *target) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index a9bfe339f2..3cf6aac262 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -297,6 +297,10 @@ struct riscv_info { yes_no_maybe_t vsew64_supported; bool range_trigger_fallback_encountered; + + bool riscv_ebreakm; + bool riscv_ebreaks; + bool riscv_ebreaku; }; COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, @@ -328,9 +332,6 @@ extern int riscv_command_timeout_sec; extern int riscv_reset_timeout_sec; extern bool riscv_enable_virtual; -extern bool riscv_ebreakm; -extern bool riscv_ebreaks; -extern bool riscv_ebreaku; /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */