diff --git a/doc/openocd.texi b/doc/openocd.texi index 4a6b0c126..127887365 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -11625,6 +11625,19 @@ riscv exec_progbuf 0x0330000f 0x0000100f riscv exec_progbuf 0x94a20405 @end example +@deffn {Command} {riscv autofence} [on|off] +When on (default), OpenOCD will automatically execute RISC-V fence instructions +(@var{fence.i} and @var{fence rw, rw}) in these cases: +@itemize @bullet +@item before step or resume, +@item before memory read via the Program Buffer, +@item after memory write via the Program Buffer. +@end itemize +When off, users need to take care of memory coherency themselves, for example +using the @var{riscv exec_progbuf} command to execute fences or CMO instructions +(RISC-V Cache Management Operations). +@end deffn + @section ARC Architecture @cindex ARC diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6ed700750..ead32f67e 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2925,11 +2925,15 @@ static int deassert_reset(struct target *target) return ERROR_OK; } -static int execute_fence(struct target *target) +static int execute_autofence(struct target *target) { if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; + RISCV_INFO(r); + if (!r->autofence) + return ERROR_OK; + /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ struct riscv_program program; @@ -2951,8 +2955,9 @@ static int execute_fence(struct target *target) LOG_TARGET_ERROR(target, "Unexpected error during fence execution"); return ERROR_FAIL; } - LOG_TARGET_DEBUG(target, "Unable to execute fence"); + LOG_TARGET_DEBUG(target, "Unable to execute fence.i and fence rw, rw"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence.i and fence rw, rw"); return ERROR_OK; } @@ -2966,6 +2971,7 @@ static int execute_fence(struct target *target) } LOG_TARGET_DEBUG(target, "Unable to execute fence.i"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence.i"); riscv_program_init(&program, target); riscv_program_fence_rw_rw(&program); @@ -2976,6 +2982,7 @@ static int execute_fence(struct target *target) } LOG_TARGET_DEBUG(target, "Unable to execute fence rw, rw"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence rw, rw"); return ERROR_OK; } @@ -4285,7 +4292,7 @@ read_memory_progbuf(struct target *target, target_addr_t address, memset(buffer, 0, count*size); - if (execute_fence(target) != ERROR_OK) + if (execute_autofence(target) != ERROR_OK) return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED; uint64_t mstatus = 0; @@ -4876,7 +4883,7 @@ write_memory_progbuf(struct target *target, target_addr_t address, if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) return MEM_ACCESS_FAILED; - if (execute_fence(target) != ERROR_OK) + if (execute_autofence(target) != ERROR_OK) return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED; return result == ERROR_OK ? MEM_ACCESS_OK : MEM_ACCESS_FAILED; @@ -5363,18 +5370,12 @@ static int riscv013_get_dmi_scan_length(struct target *target) return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; } -static int maybe_execute_fence_i(struct target *target) -{ - if (has_sufficient_progbuf(target, 2)) - return execute_fence(target); - return ERROR_OK; -} - /* Helper Functions. */ static int riscv013_on_step_or_resume(struct target *target, bool step) { - if (maybe_execute_fence_i(target) != ERROR_OK) - return ERROR_FAIL; + if (has_sufficient_progbuf(target, 2)) + if (execute_autofence(target) != ERROR_OK) + return ERROR_FAIL; if (set_dcsr_ebreak(target, step) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 7a4d54387..9e8890054 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -4504,6 +4504,22 @@ COMMAND_HANDLER(riscv_set_maskisr) return ERROR_OK; } +COMMAND_HANDLER(riscv_set_autofence) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC == 0) { + command_print(CMD, "autofence: %s", r->autofence ? "on" : "off"); + return ERROR_OK; + } else if (CMD_ARGC == 1) { + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->autofence); + return ERROR_OK; + } + + return ERROR_COMMAND_SYNTAX_ERROR; +} + COMMAND_HANDLER(riscv_set_ebreakm) { struct target *target = get_current_target(CMD_CTX); @@ -5390,6 +5406,15 @@ static const struct command_registration riscv_exec_command_handlers[] = { "hw - translate vaddr to paddr by hardware, " "off - no address translation." }, + { + .name = "autofence", + .handler = riscv_set_autofence, + .mode = COMMAND_ANY, + .usage = "[on|off]", + .help = "When on (default), OpenOCD will automatically execute fence instructions in some situations. " + "When off, users need to take care of memory coherency themselves, for example by using " + "`riscv exec_progbuf` to execute fence or CMO instructions." + }, COMMAND_REGISTRATION_DONE }; @@ -5531,6 +5556,8 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->wp_allow_equality_match_trigger = true; r->wp_allow_ge_lt_trigger = true; r->wp_allow_napot_trigger = true; + + r->autofence = 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 0b65f5f95..79d6ba847 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -321,6 +321,8 @@ struct riscv_info { bool wp_allow_equality_match_trigger; bool wp_allow_napot_trigger; bool wp_allow_ge_lt_trigger; + + bool autofence; }; COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,