Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

target/riscv: added translation drivers #1152

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions doc/openocd.texi
Original file line number Diff line number Diff line change
Expand Up @@ -11356,16 +11356,18 @@ This command can be used to change the memory access methods if the default
behavior is not suitable for a particular target.
@end deffn

@deffn {Command} {riscv set_enable_virtual} on|off
When on, memory accesses are performed on physical or virtual memory depending
on the current system configuration. When off (default), all memory accessses are performed
on physical memory.
@end deffn

@deffn {Command} {riscv set_enable_virt2phys} on|off
When on (default), memory accesses are performed on physical or virtual memory
depending on the current satp configuration. When off, all memory accessses are
performed on physical memory.
@deffn {Command} {riscv virt2phys_mode} [@option{hw}|@option{sw}|@option{off}]
Configure how OpenOCD translates virtual addresses to physical:
@itemize @bullet
@item @option{sw} - OpenOCD translates virtual addresses explicitly by
traversing the page table entries (by performing physical memory accesses to
read the respective entries). This is the default mode.
@item @option{hw} - Virtual addresses are translated implicitly by hardware.
(Virtual memory access will fail with an error if the hardware doesn't
support the necessary functionality.)
@item @option{off} - Virtual addresses are not translated (identity mapping is assumed).
@end itemize
Returns current translation mode if called without arguments.
@end deffn

@deffn {Command} {riscv resume_order} normal|reversed
Expand Down
2 changes: 2 additions & 0 deletions src/target/riscv/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ noinst_LTLIBRARIES += %D%/libriscv.la
%D%/riscv_semihosting.c \
%D%/debug_defines.c \
%D%/debug_reg_printer.c

STARTUP_TCL_SRCS += %D%/startup.tcl
19 changes: 11 additions & 8 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,11 +1974,11 @@ static int examine(struct target *target)
info->impebreak);
}

if (info->progbufsize < 4 && riscv_enable_virtual) {
JanMatCodasip marked this conversation as resolved.
Show resolved Hide resolved
LOG_TARGET_ERROR(target, "set_enable_virtual is not available on this target. It "
"requires a program buffer size of at least 4. (progbufsize=%d) "
"Use `riscv set_enable_virtual off` to continue."
, info->progbufsize);
if (info->progbufsize < 4 && riscv_virt2phys_mode_is_hw(target)) {
LOG_TARGET_ERROR(target, "software address translation "
"is not available on this target. It requires a "
"program buffer size of at least 4. (progbufsize=%d) "
"Use `riscv set_enable_virtual off` to continue.", info->progbufsize);
}

/* Don't call any riscv_* functions until after we've counted the number of
Expand Down Expand Up @@ -3054,7 +3054,8 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs)

static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old)
{
if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) {
if (riscv_virt2phys_mode_is_hw(target)
&& has_sufficient_progbuf(target, 5)) {
/* Read DCSR */
uint64_t dcsr;
if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
Expand Down Expand Up @@ -4259,7 +4260,8 @@ read_memory_progbuf(struct target *target, target_addr_t address,
if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK)
return MEM_ACCESS_FAILED_PRIV_MOD_FAILED;

const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV);
const bool mprven = riscv_virt2phys_mode_is_hw(target)
&& get_field(mstatus, MSTATUS_MPRV);
const struct memory_access_info access = {
.target_address = address,
.increment = increment,
Expand Down Expand Up @@ -4831,7 +4833,8 @@ write_memory_progbuf(struct target *target, target_addr_t address,
if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK)
return MEM_ACCESS_FAILED_PRIV_MOD_FAILED;

const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV);
const bool mprven = riscv_virt2phys_mode_is_hw(target)
&& get_field(mstatus, MSTATUS_MPRV);

int result = write_memory_progbuf_inner(target, address, size, count, buffer, mprven);

Expand Down
114 changes: 72 additions & 42 deletions src/target/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,35 @@ struct tdata1_cache {
struct list_head elem_tdata1;
};

bool riscv_virt2phys_mode_is_hw(const struct target *target)
{
assert(target);
RISCV_INFO(r);
return r->virt2phys_mode == RISCV_VIRT2PHYS_MODE_HW;
}

bool riscv_virt2phys_mode_is_sw(const struct target *target)
{
assert(target);
RISCV_INFO(r);
return r->virt2phys_mode == RISCV_VIRT2PHYS_MODE_SW;
}

const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode)
{
assert(mode == RISCV_VIRT2PHYS_MODE_OFF
|| mode == RISCV_VIRT2PHYS_MODE_SW
|| mode == RISCV_VIRT2PHYS_MODE_HW);

static const char *const names[] = {
[RISCV_VIRT2PHYS_MODE_HW] = "hw",
[RISCV_VIRT2PHYS_MODE_SW] = "sw",
[RISCV_VIRT2PHYS_MODE_OFF] = "off",
};

return names[mode];
}

/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC;

Expand All @@ -150,10 +179,6 @@ int riscv_get_command_timeout_sec(void)
return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec);
}

static bool riscv_enable_virt2phys = true;

bool riscv_enable_virtual;

static enum {
RO_NORMAL,
RO_REVERSED
Expand Down Expand Up @@ -2714,7 +2739,7 @@ static int riscv_mmu(struct target *target, int *enabled)
{
*enabled = 0;

if (!riscv_enable_virt2phys)
if (!riscv_virt2phys_mode_is_sw(target))
return ERROR_OK;

/* Don't use MMU in explicit or effective M (machine) mode */
Expand Down Expand Up @@ -3938,16 +3963,6 @@ COMMAND_HANDLER(riscv_set_mem_access)
return ERROR_OK;
}

COMMAND_HANDLER(riscv_set_enable_virtual)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual);
return ERROR_OK;
}

static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val)
{
char *args = strdup(tcl_arg);
Expand Down Expand Up @@ -4459,16 +4474,6 @@ COMMAND_HANDLER(riscv_set_maskisr)
return ERROR_OK;
}

COMMAND_HANDLER(riscv_set_enable_virt2phys)
{
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter");
return ERROR_COMMAND_SYNTAX_ERROR;
}
COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys);
return ERROR_OK;
}

COMMAND_HANDLER(riscv_set_ebreakm)
{
struct target *target = get_current_target(CMD_CTX);
Expand Down Expand Up @@ -5093,6 +5098,36 @@ COMMAND_HANDLER(handle_reserve_trigger)
return ERROR_OK;
}

COMMAND_HANDLER(handle_riscv_virt2phys_mode)
{
struct riscv_info *info = riscv_info(get_current_target(CMD_CTX));
if (CMD_ARGC == 0) {
riscv_virt2phys_mode_t mode = info->virt2phys_mode;
command_print(CMD, "%s", riscv_virt2phys_mode_to_str(mode));
return ERROR_OK;
}

if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;

// TODO: add auto mode to allow OpenOCD choose translation mode
if (!strcmp(CMD_ARGV[0],
riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_SW))) {
info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_SW;
} else if (!strcmp(CMD_ARGV[0],
riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_HW))) {
info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_HW;
} else if (!strcmp(CMD_ARGV[0],
riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_OFF))) {
info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_OFF;
} else {
command_print(CMD, "Unsupported address translation mode: %s", CMD_ARGV[0]);
return ERROR_COMMAND_ARGUMENT_INVALID;
}

return ERROR_OK;
}

static const struct command_registration riscv_exec_command_handlers[] = {
{
.name = "dump_sample_buf",
Expand Down Expand Up @@ -5144,15 +5179,6 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.help = "Set which memory access methods shall be used and in which order "
"of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'."
},
{
.name = "set_enable_virtual",
.handler = riscv_set_enable_virtual,
.mode = COMMAND_ANY,
.usage = "on|off",
.help = "When on, memory accesses are performed on physical or virtual "
"memory depending on the current system configuration. "
"When off (default), all memory accessses are performed on physical memory."
},
{
.name = "expose_csrs",
.handler = riscv_set_expose_csrs,
Expand Down Expand Up @@ -5277,14 +5303,6 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.help = "mask riscv interrupts",
.usage = "['off'|'steponly']",
},
{
.name = "set_enable_virt2phys",
.handler = riscv_set_enable_virt2phys,
.mode = COMMAND_ANY,
.usage = "on|off",
.help = "When on (default), enable translation from virtual address to "
"physical address."
},
{
.name = "set_ebreakm",
.handler = riscv_set_ebreakm,
Expand Down Expand Up @@ -5353,6 +5371,16 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.usage = "[index ('on'|'off')]",
.help = "Controls which RISC-V triggers shall not be touched by OpenOCD.",
},
{
.name = "virt2phys_mode",
.handler = handle_riscv_virt2phys_mode,
.mode = COMMAND_ANY,
.usage = "['sw'|'hw'|'off']",
.help = "Configure the virtual address translation mode: "
"sw - translate vaddr to paddr by manually traversing page tables, "
"hw - translate vaddr to paddr by hardware, "
"off - no address translation."
},
COMMAND_REGISTRATION_DONE
};

Expand Down Expand Up @@ -5469,6 +5497,8 @@ static void riscv_info_init(struct target *target, struct riscv_info *r)

r->xlen = -1;

r->virt2phys_mode = RISCV_VIRT2PHYS_MODE_SW;

r->isrmask_mode = RISCV_ISRMASK_OFF;

r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF;
Expand Down
16 changes: 14 additions & 2 deletions src/target/riscv/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ typedef enum riscv_mem_access_method {
RISCV_MEM_ACCESS_MAX_METHODS_NUM
} riscv_mem_access_method_t;

typedef enum riscv_virt2phys_mode {
RISCV_VIRT2PHYS_MODE_HW,
RISCV_VIRT2PHYS_MODE_SW,
RISCV_VIRT2PHYS_MODE_OFF
} riscv_virt2phys_mode_t;

const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode);

enum riscv_halt_reason {
RISCV_HALT_INTERRUPT,
RISCV_HALT_EBREAK,
Expand Down Expand Up @@ -165,6 +173,9 @@ struct riscv_info {
* most recent halt was not caused by a trigger, then this is -1. */
int64_t trigger_hit;

/* The configured approach to translate virtual addresses to physical */
riscv_virt2phys_mode_t virt2phys_mode;

bool triggers_enumerated;

/* Decremented every scan, and when it reaches 0 we clear the learned
Expand Down Expand Up @@ -331,11 +342,12 @@ typedef struct {
unsigned pa_ppn_mask[PG_MAX_LEVEL];
} virt2phys_info_t;

bool riscv_virt2phys_mode_is_hw(const struct target *target);
bool riscv_virt2phys_mode_is_sw(const struct target *target);

/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
int riscv_get_command_timeout_sec(void);

extern bool riscv_enable_virtual;

/* Everything needs the RISC-V specific info structure, so here's a nice macro
* that provides that. */
static inline struct riscv_info *riscv_info(const struct target *target) __attribute__((unused));
Expand Down
51 changes: 51 additions & 0 deletions src/target/riscv/startup.tcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# SPDX-License-Identifier: GPL-2.0-or-later
JanMatCodasip marked this conversation as resolved.
Show resolved Hide resolved

lappend _telnet_autocomplete_skip "riscv set_enable_virtual"
proc {riscv set_enable_virtual} on_off {
echo {DEPRECATED! use 'riscv virt2phys_mode' not 'riscv set_enable_virtual'}
foreach t [target names] {
if {[$t cget -type] ne "riscv"} { continue }
switch -- [$t riscv virt2phys_mode] {
off -
hw {
switch -- $on_off {
on {$t riscv virt2phys_mode hw}
off {$t riscv virt2phys_mode off}
}
}
sw {
if {$on_off eq "on"} {
error {Can't enable virtual while translation mode is SW}
}
}
}
}
return {}
}

lappend _telnet_autocomplete_skip "riscv set_enable_virt2phys"
proc {riscv set_enable_virt2phys} on_off {
echo {DEPRECATED! use 'riscv virt2phys_mode' not 'riscv set_enable_virt2phys'}
foreach t [target names] {
if {[$t cget -type] ne "riscv"} { continue }
switch -- [riscv virt2phys_mode] {
off -
sw {
switch -- $on_off {
on {riscv virt2phys_mode sw}
off {riscv virt2phys_mode off}
}
}
hw {
if {$on_off eq "on"} {
error {Can't enable virt2phys while translation mode is HW}
}
}
}
}
return {}
}

proc riscv {cmd args} {
tailcall "riscv $cmd" {*}$args
}