Skip to content

Commit

Permalink
target/riscv: support disable auto fence
Browse files Browse the repository at this point in the history
Support disable automatic fence, it's useful for
debug some cache related issue.
  • Loading branch information
zqb-all committed Oct 29, 2024
1 parent 9ff272e commit 33de251
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 4 deletions.
8 changes: 8 additions & 0 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -11327,6 +11327,10 @@ allows to use it directly with TCL's `array set` function. In case obtaining an
info point failed, the corresponding value is displayed as "unavailable".
@end deffn

@deffn {Command} {riscv fence}
Execute fence.i and fence rw, rw.
@end deffn

@deffn {Command} {riscv reset_delays} [wait]
OpenOCD learns how many Run-Test/Idle cycles are required between scans to avoid
encountering the target being busy. This command resets those learned values
Expand Down Expand Up @@ -11440,6 +11444,10 @@ 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_auto_fence} [on|off]
When on (default), some situations, such as stepi, will automatically execute fence.
@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.
Expand Down
22 changes: 18 additions & 4 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer);
static bool riscv013_get_impebreak(const struct target *target);
static unsigned int riscv013_get_progbufsize(const struct target *target);
static int execute_fence(struct target *target, bool force);

typedef enum {
HALT_GROUP,
Expand Down Expand Up @@ -2175,6 +2176,11 @@ static COMMAND_HELPER(riscv013_print_info, struct target *target)
return 0;
}

static COMMAND_HELPER(riscv013_exec_fence, struct target *target)
{
return execute_fence(target, true);
}

static int try_set_vsew(struct target *target, unsigned int *debug_vsew)
{
RISCV_INFO(r);
Expand Down Expand Up @@ -2765,6 +2771,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->print_info = &riscv013_print_info;
generic_info->get_impebreak = &riscv013_get_impebreak;
generic_info->get_progbufsize = &riscv013_get_progbufsize;
generic_info->exec_fence = &riscv013_exec_fence;

generic_info->handle_became_unavailable = &handle_became_unavailable;
generic_info->tick = &tick;
Expand Down Expand Up @@ -2913,11 +2920,15 @@ static int deassert_reset(struct target *target)
return dm_write(target, DM_DMCONTROL, control);
}

static int execute_fence(struct target *target)
static int execute_fence(struct target *target, bool force)
{
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;

RISCV_INFO(r);
if (!r->auto_fence && !force)
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;
Expand All @@ -2941,6 +2952,7 @@ static int execute_fence(struct target *target)
}
LOG_TARGET_DEBUG(target, "Unable to execute fence");
}
LOG_TARGET_DEBUG(target, "Successfully executed fence");
return ERROR_OK;
}

Expand All @@ -2954,6 +2966,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);
Expand All @@ -2964,6 +2977,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;
}

Expand Down Expand Up @@ -4273,7 +4287,7 @@ read_memory_progbuf(struct target *target, target_addr_t address,

memset(buffer, 0, count*size);

if (execute_fence(target) != ERROR_OK)
if (execute_fence(target, false) != ERROR_OK)
return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED;

uint64_t mstatus = 0;
Expand Down Expand Up @@ -4864,7 +4878,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_fence(target, false) != ERROR_OK)
return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED;

return result == ERROR_OK ? MEM_ACCESS_OK : MEM_ACCESS_FAILED;
Expand Down Expand Up @@ -5354,7 +5368,7 @@ static int riscv013_get_dmi_scan_length(struct target *target)
static int maybe_execute_fence_i(struct target *target)
{
if (has_sufficient_progbuf(target, 2))
return execute_fence(target);
return execute_fence(target, false);
return ERROR_OK;
}

Expand Down
45 changes: 45 additions & 0 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -4521,6 +4521,23 @@ COMMAND_HANDLER(riscv_set_maskisr)
return ERROR_OK;
}

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

if (CMD_ARGC != 1) {
command_print(CMD, "auto_fence enabled: %s", r->auto_fence ? "on" : "off");
return ERROR_OK;
} else if (CMD_ARGC == 1) {
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->auto_fence);
return ERROR_OK;
}

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

COMMAND_HANDLER(riscv_set_ebreakm)
{
struct target *target = get_current_target(CMD_CTX);
Expand Down Expand Up @@ -4998,6 +5015,17 @@ COMMAND_HANDLER(handle_info)
return 0;
}

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

if (r->exec_fence)
return CALL_COMMAND_HANDLER(r->exec_fence, target);

return 0;
}

COMMAND_HANDLER(riscv_exec_progbuf)
{
if (CMD_ARGC < 1 || CMD_ARGC > 16) {
Expand Down Expand Up @@ -5190,6 +5218,13 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.usage = "",
.help = "Displays some information OpenOCD detected about the target."
},
{
.name = "fence",
.handler = handle_fence,
.mode = COMMAND_ANY,
.usage = "",
.help = "Execute fence.i and fence rw, rw."
},
{
.name = "memory_sample",
.handler = handle_memory_sample_command,
Expand Down Expand Up @@ -5350,6 +5385,14 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.help = "mask riscv interrupts",
.usage = "['off'|'steponly']",
},
{
.name = "set_auto_fence",
.handler = riscv_set_auto_fence,
.mode = COMMAND_ANY,
.usage = "[on|off]",
.help = "When on (default), some situations, such as stepi, will "
"automatically execute fence."
},
{
.name = "set_ebreakm",
.handler = riscv_set_ebreakm,
Expand Down Expand Up @@ -5569,6 +5612,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->auto_fence = true;
}

static int riscv_resume_go_all_harts(struct target *target)
Expand Down
3 changes: 3 additions & 0 deletions src/target/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ struct riscv_info {
unsigned int (*data_bits)(struct target *target);

COMMAND_HELPER((*print_info), struct target *target);
COMMAND_HELPER((*exec_fence), struct target *target);

/* Storage for arch_info of non-custom registers. */
riscv_reg_info_t shared_reg_info;
Expand Down Expand Up @@ -321,6 +322,8 @@ struct riscv_info {
bool wp_allow_equality_match_trigger;
bool wp_allow_napot_trigger;
bool wp_allow_ge_lt_trigger;

bool auto_fence;
};

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

0 comments on commit 33de251

Please sign in to comment.