Skip to content

Commit

Permalink
target/riscv: move the dcsr modification out of program buffer
Browse files Browse the repository at this point in the history
when riscv virt2phys_mode is hw, reduce the use of
unnecessary program buffers.
  • Loading branch information
lz-bro committed Dec 25, 2024
1 parent f82c5a7 commit 67516c3
Showing 1 changed file with 60 additions and 91 deletions.
151 changes: 60 additions & 91 deletions src/target/riscv/riscv-013.c
Original file line number Diff line number Diff line change
Expand Up @@ -2005,13 +2005,6 @@ static int examine(struct target *target)
info->impebreak);
}

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
* cores and initialized registers. */

Expand Down Expand Up @@ -3109,29 +3102,23 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs)
}

/* TODO: return mem_access_result_t */
static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old)
static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old,
uint64_t *dcsr, uint64_t *dcsr_old)
{
assert(mstatus);
assert(mstatus_old);
assert(dcsr);
assert(dcsr_old);
if (!riscv_virt2phys_mode_is_hw(target))
return ERROR_OK;

/* TODO: handle error in this case
* modify_privilege function used only for program buffer memory access.
* Privilege modification requires progbuf size to be at least 5 */
if (!has_sufficient_progbuf(target, 5)) {
LOG_TARGET_WARNING(target, "Can't modify privilege to provide "
"hardware translation: program buffer too small.");
return ERROR_OK;
}

/* Read DCSR */
riscv_reg_t dcsr;
if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
/* Read and save DCSR */
if (riscv_reg_get(target, dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
*dcsr_old = *dcsr;

/* Read and save MSTATUS */
if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
if (riscv_reg_get(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL;
*mstatus_old = *mstatus;

Expand All @@ -3146,10 +3133,38 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *
*mstatus = set_field(*mstatus, MSTATUS_MPRV, 1);

/* Write MSTATUS */
if (*mstatus == *mstatus_old)
if (*mstatus != *mstatus_old &&
riscv_reg_set(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK)
return ERROR_FAIL;

/* dcsr.mprven <- 1 */
*dcsr = set_field(dcsr, CSR_DCSR_MPRVEN, CSR_DCSR_MPRVEN_ENABLED);

/* Write DCSR */
if (*dcsr != *dcsr_old &&
riscv_reg_set(target, GDB_REGNO_MSTATUS, *dcsr) != ERROR_OK)
return ERROR_FAIL;

return ERROR_OK;
}

static int restore_privilege(struct target *target, uint64_t mstatus, uint64_t mstatus_old,
uint64_t dcsr, uint64_t dcsr_old)
{
if (!riscv_virt2phys_mode_is_hw(target))
return ERROR_OK;

return register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus);
/* Restore MSTATUS */
if (mstatus != mstatus_old &&
riscv_reg_set(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK)
return ERROR_FAIL;

/* Restore DCSR */
if (dcsr != dcsr_old &&
riscv_reg_set(target, GDB_REGNO_MSTATUS, dcsr_old) != ERROR_OK)
return ERROR_FAIL;

return ERROR_OK;
}

static int read_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args)
Expand Down Expand Up @@ -4188,25 +4203,8 @@ static int read_word_from_s1(struct target *target,
return ERROR_OK;
}

static int riscv_program_load_mprv(struct riscv_program *p, enum gdb_regno d,
enum gdb_regno b, int offset, unsigned int size, bool mprven)
{
if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN,
GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;

if (riscv_program_load(p, d, b, offset, size) != ERROR_OK)
return ERROR_FAIL;

if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN,
GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;

return ERROR_OK;
}

static int read_memory_progbuf_inner_fill_progbuf(struct target *target,
uint32_t increment, uint32_t size, bool mprven)
uint32_t increment, uint32_t size)
{
const bool is_repeated_read = increment == 0;

Expand All @@ -4220,8 +4218,7 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target,
struct riscv_program program;

riscv_program_init(&program, target);
if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size,
mprven) != ERROR_OK)
if (riscv_program_load(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size) != ERROR_OK)
return ERROR_FAIL;
if (is_repeated_read) {
if (riscv_program_addi(&program, GDB_REGNO_A0, GDB_REGNO_A0, 1)
Expand All @@ -4246,14 +4243,12 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target,
* re-read the data only if `abstract command busy` or `DMI busy`
* is encountered in the process.
*/
static int read_memory_progbuf_inner(struct target *target,
const riscv_mem_access_args_t args, bool mprven)
static int read_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t args)
{
assert(riscv_mem_access_is_read(args));
assert(args.count > 1 && "If count == 1, read_memory_progbuf_inner_one must be called");

if (read_memory_progbuf_inner_fill_progbuf(target, args.increment,
args.size, mprven) != ERROR_OK)
if (read_memory_progbuf_inner_fill_progbuf(target, args.increment, args.size) != ERROR_OK)
return ERROR_FAIL;

if (read_memory_progbuf_inner_startup(target, args.address,
Expand Down Expand Up @@ -4305,8 +4300,7 @@ static int read_memory_progbuf_inner(struct target *target,
* Only need to save/restore one GPR to read a single word, and the progbuf
* program doesn't need to increment.
*/
static int read_memory_progbuf_inner_one(struct target *target,
const riscv_mem_access_args_t args, bool mprven)
static int read_memory_progbuf_inner_one(struct target *target, const riscv_mem_access_args_t args)
{
assert(riscv_mem_access_is_read(args));

Expand All @@ -4316,8 +4310,7 @@ static int read_memory_progbuf_inner_one(struct target *target,
struct riscv_program program;

riscv_program_init(&program, target);
if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S1, 0,
args.size, mprven) != ERROR_OK)
if (riscv_program_load(&program, GDB_REGNO_S1, GDB_REGNO_S1, 0, args.size) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_ebreak(&program) != ERROR_OK)
return ERROR_FAIL;
Expand Down Expand Up @@ -4365,17 +4358,16 @@ read_memory_progbuf(struct target *target, const riscv_mem_access_args_t args)

uint64_t mstatus = 0;
uint64_t mstatus_old = 0;
if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK)
uint64_t dcsr = 0;
uint64_t dcsr_old = 0;
if (modify_privilege(target, &mstatus, &mstatus_old, &dcsr, &dcsr_old) != ERROR_OK)
return MEM_ACCESS_FAILED_PRIV_MOD_FAILED;

const bool mprven = riscv_virt2phys_mode_is_hw(target)
&& get_field(mstatus, MSTATUS_MPRV);
int result = (args.count == 1) ?
read_memory_progbuf_inner_one(target, args, mprven) :
read_memory_progbuf_inner(target, args, mprven);
read_memory_progbuf_inner_one(target, args) :
read_memory_progbuf_inner(target, args);

if (mstatus != mstatus_old &&
register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK)
if (restore_privilege(target, mstatus, mstatus_old, dcsr, dcsr_old) != ERROR_OK)
return MEM_ACCESS_FAILED;

return (result == ERROR_OK) ? MEM_ACCESS_OK : MEM_ACCESS_FAILED;
Expand Down Expand Up @@ -4833,25 +4825,7 @@ static int write_memory_progbuf_try_to_write(struct target *target,
return result;
}

static int riscv_program_store_mprv(struct riscv_program *p, enum gdb_regno d,
enum gdb_regno b, int offset, unsigned int size, bool mprven)
{
if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN,
GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;

if (riscv_program_store(p, d, b, offset, size) != ERROR_OK)
return ERROR_FAIL;

if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN,
GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;

return ERROR_OK;
}

static int write_memory_progbuf_fill_progbuf(struct target *target,
uint32_t size, bool mprven)
static int write_memory_progbuf_fill_progbuf(struct target *target, uint32_t size)
{
if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
Expand All @@ -4861,8 +4835,7 @@ static int write_memory_progbuf_fill_progbuf(struct target *target,
struct riscv_program program;

riscv_program_init(&program, target);
if (riscv_program_store_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size,
mprven) != ERROR_OK)
if (riscv_program_store(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size) != ERROR_OK)
return ERROR_FAIL;

if (riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size) != ERROR_OK)
Expand All @@ -4874,12 +4847,11 @@ static int write_memory_progbuf_fill_progbuf(struct target *target,
return riscv_program_write(&program);
}

static int write_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t args, bool mprven)
static int write_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t args)
{
assert(riscv_mem_access_is_write(args));

if (write_memory_progbuf_fill_progbuf(target, args.size,
mprven) != ERROR_OK)
if (write_memory_progbuf_fill_progbuf(target, args.size) != ERROR_OK)
return ERROR_FAIL;

target_addr_t addr_on_target = args.address;
Expand Down Expand Up @@ -4923,18 +4895,15 @@ write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args)

uint64_t mstatus = 0;
uint64_t mstatus_old = 0;
if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK)
uint64_t dcsr = 0;
uint64_t dcsr_old = 0;
if (modify_privilege(target, &mstatus, &mstatus_old, &dcsr, &dcsr_old) != ERROR_OK)
return MEM_ACCESS_FAILED_PRIV_MOD_FAILED;

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

int result = write_memory_progbuf_inner(target, args, mprven);
int result = write_memory_progbuf_inner(target, args);

/* Restore MSTATUS */
if (mstatus != mstatus_old)
if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old))
return MEM_ACCESS_FAILED;
if (restore_privilege(target, mstatus, mstatus_old, dcsr, dcsr_old) != ERROR_OK)
return MEM_ACCESS_FAILED;

if (execute_autofence(target) != ERROR_OK)
return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED;
Expand Down

0 comments on commit 67516c3

Please sign in to comment.