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,

-- 

Reply via email to