Skip to content

Commit

Permalink
target/riscv: added translation drivers
Browse files Browse the repository at this point in the history
Existing flags: 'enable_virtual' and 'enable_virt2phys' were
replaced with explicit translation drivers. Motivation:

(1) Having 'enable_virtual' and 'enable_virt2phys' flags set simultaneously
may cause double address translation which is unacceptable

(2) Flags were global for all targets which is wrong too

Signed-off-by: Farid Khaydari <[email protected]>
  • Loading branch information
fk-sc committed Oct 22, 2024
1 parent a4020f1 commit 662ff69
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 62 deletions.
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) {
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 driver)
{
assert(driver == RISCV_VIRT2PHYS_MODE_OFF
|| driver == RISCV_VIRT2PHYS_MODE_SW
|| driver == 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[driver];
}

/* 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 driver = info->virt2phys_mode;
command_print(CMD, "%s", riscv_virt2phys_mode_to_str(driver));
return ERROR_OK;
}

if (CMD_ARGC != 1)
return ERROR_COMMAND_SYNTAX_ERROR;

// TODO: add auto mode to allow OpenOCD choose translation driver
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 driver);

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

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 driver 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 driver is HW}
}
}
}
}
return {}
}

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

0 comments on commit 662ff69

Please sign in to comment.