From 872ebb14ca160eff364bf61844c3a6098e9f8ecc Mon Sep 17 00:00:00 2001 From: Jan Matyas <50193733+JanMatCodasip@users.noreply.github.com> Date: Wed, 15 Feb 2023 18:53:03 +0100 Subject: [PATCH] Add command "exec_progbuf" (#795) * Add command "exec_progbuf" Command "exec_progbuf" allows to execute a user-specified sequence of instructions using the program buffer. Change-Id: If3b9614129d0b6fcbc33fade29d3d60b35e52f98 Signed-off-by: Jan Matyas * Updated the doc: - Minor reword and reorder of the sentences. - Added information about C-instructions in progbuf. - Fixed a typo (per the review). - Added examples. Change-Id: I88c9a3ff3c6b60614be7eafd3a6f21be722a77b7 Signed-off-by: Jan Matyas * Cosmetic changes Change-Id: I7135c9f435f640e189c7d7922a2702814dfd595f Signed-off-by: Jan Matyas --------- Signed-off-by: Jan Matyas Co-authored-by: Jan Matyas --- doc/openocd.texi | 33 ++++++++++++++++++++++ src/target/riscv/program.c | 17 +++++------ src/target/riscv/riscv-013.c | 2 +- src/target/riscv/riscv.c | 55 ++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 9 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index ab9dcaf33..76e697cc2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -10753,6 +10753,39 @@ For details on this trigger type, see the RISC-V Debug Specification. Clear the type 4 trigger that was set using @command{riscv itrigger set}. @end deffn +@subsection RISC-V Program Buffer Commands + +Program Buffer is an optional feature of RISC-V targets - it is a mechanism that debuggers +can use to execute sequences of arbitrary instructions (small programs) on the target. +For details on the Program Buffer, please refer to the RISC-V Debug Specification. + +@deffn {Command} {riscv exec_progbuf} inst1 [inst2 [... inst16]] +Execute the given sequence of instructions on the target using the Program Buffer. +The command can only be used on halted targets. + +The instructions @var{inst1} .. @var{inst16} shall be specified in their binary form +(as 32-bit integers). In case a pair of compressed (16-bit) instructions is used, +the first instruction should be placed to the lower 16-bits of the 32-bit value. +The terminating @var{ebreak} instruction needs not be specified - it is added +automatically if needed. +@end deffn + +Examples: + +@example +# Execute 32-bit instructions "fence rw,rw" (0x0330000f) +# and "fence.i" (0x0000100f) using the Program Buffer, +# in this order: + +riscv exec_progbuf 0x0330000f 0x0000100f + +# Execute 16-bit instructions "c.addi s0,s0,1" (0x0405) +# and "c.add s1,s1,s0" (0x94a2) using the Program Buffer, +# in this order: + +riscv exec_progbuf 0x94a20405 +@end example + @section ARC Architecture @cindex ARC diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index f14923a82..16baa4b92 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -32,7 +32,8 @@ int riscv_program_init(struct riscv_program *p, struct target *target) int riscv_program_write(struct riscv_program *program) { for (unsigned i = 0; i < program->instruction_count; ++i) { - LOG_DEBUG("debug_buffer[%02x] = DASM(0x%08x)", i, program->debug_buffer[i]); + LOG_TARGET_DEBUG(program->target, "debug_buffer[%02x] = DASM(0x%08x)", + i, program->debug_buffer[i]); if (riscv_write_debug_buffer(program->target, i, program->debug_buffer[i]) != ERROR_OK) return ERROR_FAIL; @@ -48,7 +49,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { - LOG_DEBUG("Saving register %d as used by program", (int)i); + LOG_TARGET_DEBUG(t, "Saving register %d as used by program", (int)i); int result = riscv_get_register(t, &saved_registers[i], i); if (result != ERROR_OK) return result; @@ -56,9 +57,9 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) } if (riscv_program_ebreak(p) != ERROR_OK) { - LOG_ERROR("Unable to write ebreak"); + LOG_TARGET_ERROR(t, "Unable to insert ebreak into program buffer"); for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - LOG_ERROR("ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", + LOG_TARGET_ERROR(t, "ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", (int)i, p->debug_buffer[i], p->debug_buffer[i]); return ERROR_FAIL; } @@ -67,7 +68,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_FAIL; if (riscv_execute_debug_buffer(t) != ERROR_OK) { - LOG_DEBUG("Unable to execute program %p", p); + LOG_TARGET_DEBUG(t, "Unable to execute program %p", p); return ERROR_FAIL; } @@ -175,9 +176,9 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { - LOG_ERROR("Unable to insert instruction:"); - LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); - LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); + LOG_TARGET_ERROR(p->target, "Unable to insert program into progbuf, " + "capacity would be exceeded (progbufsize=%d).", + (int)riscv_debug_buffer_size(p->target)); return ERROR_FAIL; } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f12d18520..28789bdad 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1700,7 +1700,7 @@ static int examine(struct target *target) } /* Without knowing anything else we can at least mess with the - * program buffer. */ + * program buffer. */ r->debug_buffer_size = info->progbufsize; int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 058a8106a..3c797bc0e 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -20,6 +20,7 @@ #include "helper/base64.h" #include "helper/time_support.h" #include "riscv.h" +#include "program.h" #include "gdb_regs.h" #include "rtos/rtos.h" #include "debug_defines.h" @@ -3589,6 +3590,52 @@ COMMAND_HANDLER(handle_info) return 0; } +COMMAND_HANDLER(riscv_exec_progbuf) +{ + if (CMD_ARGC < 1 || CMD_ARGC > 16) { + LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct target *target = get_current_target(CMD_CTX); + + RISCV_INFO(r); + if (r->dtm_version != 1) { + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer is " + "only supported on v0.13 or v1.0 targets."); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "exec_progbuf: Can't execute " + "program buffer, target not halted."); + return ERROR_FAIL; + } + + if (riscv_debug_buffer_size(target) == 0) { + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer not implemented " + "in the target."); + return ERROR_FAIL; + } + + struct riscv_program prog; + riscv_program_init(&prog, target); + + for (unsigned int i = 0; i < CMD_ARGC; i++) { + riscv_insn_t instr; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[i], instr); + if (riscv_program_insert(&prog, instr) != ERROR_OK) + return ERROR_FAIL; + } + + if (riscv_program_exec(&prog, target) == ERROR_OK) + LOG_TARGET_DEBUG(target, "exec_progbuf: Program buffer execution successful."); + else + LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed."); + + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -3804,6 +3851,14 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "set [vs] [vu] [nmi] [m] [s] [u] |clear", .help = "Set or clear a single interrupt trigger." }, + { + .name = "exec_progbuf", + .handler = riscv_exec_progbuf, + .mode = COMMAND_EXEC, + .usage = "instr1 [instr2 [... instr16]]", + .help = "Execute a sequence of 32-bit instructions using the program buffer. " + "The final ebreak instruction is added automatically, if needed." + }, COMMAND_REGISTRATION_DONE };