diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index c399de7e4..2352e6e8f 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -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. */ @@ -3116,15 +3109,6 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t * 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) @@ -3146,10 +3130,33 @@ 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 && + register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) + return ERROR_FAIL; + + /* dcsr.mprven <- 1 */ + return register_write_direct(target, GDB_REGNO_DCSR, + set_field(dcsr, CSR_DCSR_MPRVEN, CSR_DCSR_MPRVEN_ENABLED)); +} + +static int restore_privilege(struct target *target, uint64_t mstatus, uint64_t mstatus_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 && + register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + /* Read DCSR */ + riscv_reg_t dcsr; + if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + + /* dcsr.mprven <- 0 */ + return register_write_direct(target, GDB_REGNO_DCSR, + set_field(dcsr, CSR_DCSR_MPRVEN, CSR_DCSR_MPRVEN_DISABLED)); } static int read_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args) @@ -4188,25 +4195,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; @@ -4220,8 +4210,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) @@ -4246,14 +4235,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, @@ -4305,8 +4292,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)); @@ -4316,8 +4302,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; @@ -4368,14 +4353,11 @@ read_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) if (modify_privilege(target, &mstatus, &mstatus_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) != ERROR_OK) return MEM_ACCESS_FAILED; return (result == ERROR_OK) ? MEM_ACCESS_OK : MEM_ACCESS_FAILED; @@ -4833,25 +4815,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; @@ -4861,8 +4825,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) @@ -4874,12 +4837,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; @@ -4926,15 +4888,10 @@ write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) if (modify_privilege(target, &mstatus, &mstatus_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) != ERROR_OK) + return MEM_ACCESS_FAILED; if (execute_autofence(target) != ERROR_OK) return MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED;