This is an automated email from Gerrit. "Zane Liang <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9225
-- gerrit commit 2defbdfdaa1d6f47a2e1c8efe2a81d468ffd4097 Author: liangzhen <[email protected]> Date: Thu Nov 27 15:59:17 2025 +0800 target/riscv: fix misa register extension usage Introduce the `riscv detect_misa` command, which temporarily enables all MISA extensions and transmits the target description. When accessing a register, if the register depends on a specific extension, its availability will be verified based on the current value of the misa register. Change-Id: I83d321046edb6df2c24711a8b47a6abd140f2947 Signed-off-by: liangzhen <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index 57f8703ad1..f124179a86 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -12037,6 +12037,11 @@ using the @var{riscv exec_progbuf} command to execute fences or CMO instructions (RISC-V Cache Management Operations). @end deffn +@deffn {Command} {riscv detect_misa} [on|off] +When on (default), during initialization, OpenOCD will reads the misa register, +sets it to all ones, and checks which extensions are supported. +@end deffn + @section ARC Architecture @cindex ARC diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6fa5e025be..baaf2d7ff1 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1394,7 +1394,7 @@ static int fpr_read_progbuf(struct target *target, uint64_t *value, struct riscv_program program; riscv_program_init(&program, target); - if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { + if (riscv_supports_extension(target, 'D', true) && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ @@ -1403,7 +1403,7 @@ static int fpr_read_progbuf(struct target *target, uint64_t *value, return internal_register_read64_progbuf_scratch(target, &program, value); } if (riscv_program_insert(&program, - riscv_supports_extension(target, 'D') ? + riscv_supports_extension(target, 'D', true) ? fmv_x_d(S0, freg) : fmv_x_w(S0, freg)) != ERROR_OK) return ERROR_FAIL; @@ -1493,7 +1493,7 @@ static int fpr_write_progbuf(struct target *target, enum gdb_regno number, struct riscv_program program; riscv_program_init(&program, target); - if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { + if (riscv_supports_extension(target, 'D', true) && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a register, * so we need to use some scratch RAM. */ @@ -1506,7 +1506,7 @@ static int fpr_write_progbuf(struct target *target, enum gdb_regno number, return ERROR_FAIL; if (riscv_program_insert(&program, - riscv_supports_extension(target, 'D') ? + riscv_supports_extension(target, 'D', true) ? fmv_d_x(freg, S0) : fmv_w_x(freg, S0)) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c index b2b1a921f2..ad23ca3e28 100644 --- a/src/target/riscv/riscv-013_reg.c +++ b/src/target/riscv/riscv-013_reg.c @@ -19,7 +19,7 @@ static int riscv013_reg_get(struct reg *reg) /* TODO: Hack to deal with gdb that thinks these registers still exist. */ if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && - riscv_supports_extension(target, 'E')) { + riscv_supports_extension(target, 'E', true)) { buf_set_u64(reg->value, 0, reg->size, 0); return ERROR_OK; } @@ -54,7 +54,7 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf) /* TODO: Hack to deal with gdb that thinks these registers still exist. */ if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 && - riscv_supports_extension(target, 'E') && + riscv_supports_extension(target, 'E', true) && buf_get_u64(buf, 0, reg->size) == 0) return ERROR_OK; @@ -139,7 +139,7 @@ static int examine_vlenb(struct target *target) riscv_reg_t vlenb_val; if (riscv_reg_get(target, &vlenb_val, GDB_REGNO_VLENB) != ERROR_OK) { - if (riscv_supports_extension(target, 'V')) + if (riscv_supports_extension(target, 'V', true)) LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); r->vlenb = 0; return riscv_reg_impl_set_exist(target, GDB_REGNO_VLENB, false); @@ -184,7 +184,7 @@ unsigned int mxl_to_xlen(enum misa_mxl mxl) return 0; } -static int check_misa_mxl(const struct target *target) +static int check_misa(struct target *target) { RISCV_INFO(r); @@ -247,6 +247,25 @@ static int check_misa_mxl(const struct target *target) /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa); + + if (r->detect_misa) { + const riscv_reg_t misa_extensions_mask = (riscv_reg_t)(0x1 << 25) - 1; + riscv_reg_t misa = set_field(r->misa, misa_extensions_mask, misa_extensions_mask); + if (riscv_reg_set(target, GDB_REGNO_MISA, misa) != ERROR_OK) + return ERROR_FAIL; + + if (riscv_reg_get(target, &misa, GDB_REGNO_MISA) != ERROR_OK) + return ERROR_FAIL; + + if (misa != r->misa) { + LOG_TARGET_DEBUG(target, "Detected misa=0x%" PRIx64 "does not " + "equal to origin misa=0x%" PRIx64, misa, r->misa); + if (riscv_reg_set(target, GDB_REGNO_MISA, r->misa) != ERROR_OK) + return ERROR_FAIL; + r->misa = misa; + } + } + return ERROR_OK; } @@ -261,7 +280,7 @@ static int examine_misa(struct target *target) res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA); if (res != ERROR_OK) return res; - return check_misa_mxl(target); + return check_misa(target); } static int examine_mtopi(struct target *target) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 8054a1c9b7..ba0b0df8e3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1165,7 +1165,8 @@ struct match_triggers_tdata1_fields { static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(struct target *target, struct trigger *trigger) { - RISCV_INFO(r); + bool misa_s = riscv_supports_extension(target, 'S', true); + bool misa_u = riscv_supports_extension(target, 'U', true); struct match_triggers_tdata1_fields result = { .common = @@ -1173,8 +1174,8 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2( field_value(CSR_MCONTROL_DMODE(riscv_xlen(target)), 1) | field_value(CSR_MCONTROL_ACTION, CSR_MCONTROL_ACTION_DEBUG_MODE) | field_value(CSR_MCONTROL_M, 1) | - field_value(CSR_MCONTROL_S, !!(r->misa & BIT('S' - 'A'))) | - field_value(CSR_MCONTROL_U, !!(r->misa & BIT('U' - 'A'))) | + field_value(CSR_MCONTROL_S, misa_s) | + field_value(CSR_MCONTROL_U, misa_u) | field_value(CSR_MCONTROL_EXECUTE, trigger->is_execute) | field_value(CSR_MCONTROL_LOAD, trigger->is_read) | field_value(CSR_MCONTROL_STORE, trigger->is_write), @@ -1200,9 +1201,9 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2( static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6(struct target *target, struct trigger *trigger) { - bool misa_s = riscv_supports_extension(target, 'S'); - bool misa_u = riscv_supports_extension(target, 'U'); - bool misa_h = riscv_supports_extension(target, 'H'); + bool misa_s = riscv_supports_extension(target, 'S', true); + bool misa_u = riscv_supports_extension(target, 'U', true); + bool misa_h = riscv_supports_extension(target, 'H', true); struct match_triggers_tdata1_fields result = { .common = @@ -2192,8 +2193,8 @@ static int verify_loadstore(struct target *target, const riscv_insn_t instruction, bool *is_read) { uint32_t opcode = get_opcode(instruction); - bool misa_f = riscv_supports_extension(target, 'F'); - bool misa_d = riscv_supports_extension(target, 'D'); + bool misa_f = riscv_supports_extension(target, 'F', true); + bool misa_d = riscv_supports_extension(target, 'D', true); enum watchpoint_rw rw; switch (opcode) { @@ -5576,6 +5577,18 @@ COMMAND_HANDLER(handle_riscv_virt2phys_mode) return ERROR_OK; } +COMMAND_HANDLER(riscv_detect_misa) +{ + struct target *target = get_current_target(CMD_CTX); + RISCV_INFO(r); + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->detect_misa); + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5838,6 +5851,14 @@ static const struct command_registration riscv_exec_command_handlers[] = { "When off, users need to take care of memory coherency themselves, for example by using " "`riscv exec_progbuf` to execute fence or CMO instructions." }, + { + .name = "detect_misa", + .handler = riscv_detect_misa, + .mode = COMMAND_CONFIG, + .usage = "[on|off]", + .help = "When on (default), during initialization, OpenOCD will reads the misa register, sets it to " + "all ones, and checks which extensions are supported." + }, { .chain = smp_command_handlers }, @@ -5978,6 +5999,8 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->wp_allow_napot_trigger = true; r->autofence = true; + + r->detect_misa = true; } static int riscv_resume_go_all_harts(struct target *target) @@ -6044,7 +6067,7 @@ static int riscv_step_rtos_hart(struct target *target) return ERROR_OK; } -bool riscv_supports_extension(const struct target *target, char letter) +bool riscv_supports_extension(struct target *target, char letter, bool current) { RISCV_INFO(r); unsigned int num; @@ -6054,6 +6077,14 @@ bool riscv_supports_extension(const struct target *target, char letter) num = letter - 'A'; else return false; + + if (current) { + riscv_reg_t misa; + if (riscv_reg_get(target, &misa, GDB_REGNO_MISA) != ERROR_OK) + return false; + return misa & BIT(num); + } + return r->misa & BIT(num); } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2a0a9b95f0..186fb68241 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -365,6 +365,8 @@ struct riscv_info { bool wp_allow_ge_lt_trigger; bool autofence; + + bool detect_misa; }; enum riscv_priv_mode { @@ -457,7 +459,7 @@ int riscv_openocd_step( /*** RISC-V Interface ***/ -bool riscv_supports_extension(const struct target *target, char letter); +bool riscv_supports_extension(struct target *target, char letter, bool current); /* Returns XLEN for the given (or current) hart. */ unsigned int riscv_xlen(const struct target *target); diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index ba1bc2a858..096bed52ca 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -259,7 +259,7 @@ static bool gdb_regno_caller_save(uint32_t regno) (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31); } -static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target, +static struct reg_data_type *gdb_regno_reg_data_type(struct target *target, uint32_t regno) { if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) { @@ -284,7 +284,7 @@ static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target .type_class = REG_TYPE_CLASS_UNION, {.reg_type_union = &single_double_union} }; - return riscv_supports_extension(target, 'D') ? + return riscv_supports_extension(target, 'D', false) ? &type_ieee_single_double : &type_ieee_single; } @@ -314,10 +314,10 @@ static const char *gdb_regno_group(uint32_t regno) return "custom"; } -uint32_t gdb_regno_size(const struct target *target, uint32_t regno) +uint32_t gdb_regno_size(struct target *target, uint32_t regno) { if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - return riscv_supports_extension(target, 'D') ? 64 : 32; + return riscv_supports_extension(target, 'D', false) ? 64 : 32; if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) return riscv_vlenb(target) * 8; if (regno == GDB_REGNO_PRIV) @@ -365,7 +365,7 @@ static bool is_known_standard_csr(unsigned int csr_num) return is_csr_in_buf[csr_num]; } -bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) +bool riscv_reg_impl_gdb_regno_exist(struct target *target, uint32_t regno) { switch (regno) { case GDB_REGNO_VLENB: @@ -383,9 +383,9 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) regno == GDB_REGNO_PRIV) return true; if (regno > GDB_REGNO_XPR15 && regno <= GDB_REGNO_XPR31) - return !riscv_supports_extension(target, 'E'); + return !riscv_supports_extension(target, 'E', false); if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - return riscv_supports_extension(target, 'F'); + return riscv_supports_extension(target, 'F', false); if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) return vlenb_exists(target); if (regno >= GDB_REGNO_COUNT) @@ -396,7 +396,7 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_FFLAGS: case CSR_FRM: case CSR_FCSR: - return riscv_supports_extension(target, 'F'); + return riscv_supports_extension(target, 'F', false); case CSR_VSTART: case CSR_VXSAT: case CSR_VXRM: @@ -414,14 +414,14 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_SCAUSE: case CSR_STVAL: case CSR_SATP: - return riscv_supports_extension(target, 'S'); + return riscv_supports_extension(target, 'S', false); case CSR_MEDELEG: case CSR_MIDELEG: /* "In systems with only M-mode, or with both M-mode and * U-mode but without U-mode trap support, the medeleg and * mideleg registers should not exist." */ - return riscv_supports_extension(target, 'S') || - riscv_supports_extension(target, 'N'); + return riscv_supports_extension(target, 'S', false) || + riscv_supports_extension(target, 'N', false); case CSR_PMPCFG1: case CSR_PMPCFG3: @@ -489,7 +489,7 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_MHPMCOUNTER31H: return riscv_xlen(target) == 32; case CSR_MCOUNTEREN: - return riscv_supports_extension(target, 'U'); + return riscv_supports_extension(target, 'U', false); /* Interrupts M-Mode CSRs. */ case CSR_MISELECT: case CSR_MIREG: @@ -503,21 +503,21 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_MVIPH: return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); + riscv_supports_extension(target, 'S', false); /* Interrupts S-Mode CSRs. */ case CSR_SISELECT: case CSR_SIREG: case CSR_STOPI: return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_supports_extension(target, 'S'); + riscv_supports_extension(target, 'S', false); case CSR_STOPEI: return reg_exists(target, GDB_REGNO_MTOPEI) && - riscv_supports_extension(target, 'S'); + riscv_supports_extension(target, 'S', false); case CSR_SIEH: case CSR_SIPH: return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'S'); + riscv_supports_extension(target, 'S', false); /* Interrupts Hypervisor and VS CSRs. */ case CSR_HVIEN: case CSR_HVICTL: @@ -527,10 +527,10 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_VSIREG: case CSR_VSTOPI: return reg_exists(target, GDB_REGNO_MTOPI) && - riscv_supports_extension(target, 'H'); + riscv_supports_extension(target, 'H', false); case CSR_VSTOPEI: return reg_exists(target, GDB_REGNO_MTOPEI) && - riscv_supports_extension(target, 'H'); + riscv_supports_extension(target, 'H', false); case CSR_HIDELEGH: case CSR_HVIENH: case CSR_HVIPH: @@ -540,7 +540,7 @@ bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_VSIPH: return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && - riscv_supports_extension(target, 'H'); + riscv_supports_extension(target, 'H', false); } return is_known_standard_csr(csr_number); } diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 17e66935be..76a7d03219 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -44,7 +44,7 @@ int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, * For most registers, returns whether they exist or not. * For some registers the "exist" bit should be set explicitly. */ -bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno); +bool riscv_reg_impl_gdb_regno_exist(struct target *target, uint32_t regno); /** Mark register as existing or not. */ int riscv_reg_impl_set_exist(const struct target *target, --
