From 1449af5bdb99052c2f3bf92747f8438544cd8f3f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 20 Feb 2020 13:58:15 -0800 Subject: [PATCH] Give control over dcsr.ebreak[msu] bits. (#451) This allows a user to debug code that uses software breakpoints itself. Change-Id: If40cb626354e11703017cdf8c5919a31e83ebc3f --- doc/openocd.texi | 15 ++++++++++ src/target/riscv/riscv-011.c | 12 ++++++-- src/target/riscv/riscv-013.c | 6 ++-- src/target/riscv/riscv.c | 57 ++++++++++++++++++++++++++++++++++++ src/target/riscv/riscv.h | 3 ++ 5 files changed, 87 insertions(+), 6 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 504ffeb07..0e92a9dee 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9511,6 +9511,21 @@ Enable or disable use of a BSCAN tunnel to reach DM. Supply the width of the DM transport TAP's instruction register to enable. Supply a value of 0 to disable. @end deffn +@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 +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 +Control dcsr.ebreaku. When on (default), U-mode ebreak instructions trap to +OpenOCD. When off, they generate a breakpoint exception handled internally. +@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-011.c b/src/target/riscv/riscv-011.c index aad5b8bfb..dc09c9686 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1114,7 +1114,10 @@ static int execute_resume(struct target *target, bool step) } } - info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU; + 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_EBREAKH, 1); info->dcsr &= ~DCSR_HALT; if (step) @@ -1946,8 +1949,11 @@ 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 |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | - DCSR_EBREAKU | DCSR_HALT; + 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_EBREAKH, 1); + info->dcsr |= DCSR_HALT; if (target->reset_halt) info->dcsr |= DCSR_NDRESET; else diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 4381f41f3..487ed50e9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -4310,9 +4310,9 @@ static int riscv013_on_step_or_resume(struct target *target, bool step) if (result != ERROR_OK) return result; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, riscv_ebreakm); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, riscv_ebreaks); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, riscv_ebreaku); return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 35dbe77a0..ae0489768 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -252,6 +252,9 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; bool riscv_prefer_sba; bool riscv_enable_virt2phys = true; +bool riscv_ebreakm = true; +bool riscv_ebreaks = true; +bool riscv_ebreaku = true; bool riscv_enable_virtual; @@ -2465,6 +2468,36 @@ COMMAND_HANDLER(riscv_set_enable_virt2phys) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_ebreakm) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreakm); + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_ebreaks) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaks); + return ERROR_OK; +} + +COMMAND_HANDLER(riscv_set_ebreaku) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_ebreaku); + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "test_compliance", @@ -2607,6 +2640,30 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "riscv set_enable_virt2phys on|off", .help = "Enable translation from virtual address to physical address." }, + { + .name = "set_ebreakm", + .handler = riscv_set_ebreakm, + .mode = COMMAND_ANY, + .usage = "riscv set_ebreakm on|off", + .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaks", + .handler = riscv_set_ebreaks, + .mode = COMMAND_ANY, + .usage = "riscv set_ebreaks on|off", + .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, + { + .name = "set_ebreaku", + .handler = riscv_set_ebreaku, + .mode = COMMAND_ANY, + .usage = "riscv set_ebreaku on|off", + .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " + "don't trap to OpenOCD. Defaults to on." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 9fa21388a..928e460ec 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -195,6 +195,9 @@ extern int riscv_reset_timeout_sec; extern bool riscv_prefer_sba; 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. */