diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c index 7f2906423..04021e0da 100644 --- a/src/target/riscv/riscv-011_reg.c +++ b/src/target/riscv/riscv-011_reg.c @@ -38,7 +38,7 @@ static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno) static int riscv011_init_reg(struct target *target, uint32_t regno) { - return riscv_reg_impl_init_one(target, regno, riscv011_gdb_regno_reg_type(regno)); + return riscv_reg_impl_init_cache_entry(target, regno, riscv011_gdb_regno_reg_type(regno)); } int riscv011_reg_init_all(struct target *target) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ae36a063d..e294d685f 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -727,7 +727,7 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target, return res; } -static int execute_abstract_command(struct target *target, uint32_t command, +int riscv013_execute_abstract_command(struct target *target, uint32_t command, uint32_t *cmderr) { assert(cmderr); @@ -863,7 +863,7 @@ static int write_abstract_arg(struct target *target, unsigned index, /** * @par size in bits */ -static uint32_t access_register_command(struct target *target, uint32_t number, +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, unsigned size, uint32_t flags) { uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); @@ -920,11 +920,11 @@ static int register_read_abstract_with_size(struct target *target, if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) return ERROR_FAIL; - uint32_t command = access_register_command(target, number, size, + uint32_t command = riscv013_access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); uint32_t cmderr; - int result = execute_abstract_command(target, command, &cmderr); + int result = riscv013_execute_abstract_command(target, command, &cmderr); if (result != ERROR_OK) { if (cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { @@ -969,7 +969,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number, return ERROR_FAIL; const unsigned int size_bits = register_size(target, number); - const uint32_t command = access_register_command(target, number, size_bits, + const uint32_t command = riscv013_access_register_command(target, number, size_bits, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); @@ -2112,71 +2112,7 @@ static int examine(struct target *target) * program buffer. */ r->progbuf_size = info->progbufsize; - result = register_read_abstract_with_size(target, NULL, GDB_REGNO_S0, 64); - if (result == ERROR_OK) - r->xlen = 64; - else - r->xlen = 32; - - /* Save s0 and s1. The register cache hasn't be initialized yet so we - * need to take care of this manually. */ - uint64_t s0, s1; - if (register_read_abstract(target, &s0, GDB_REGNO_S0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); - return ERROR_FAIL; - } - if (register_read_abstract(target, &s1, GDB_REGNO_S1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); - return ERROR_FAIL; - } - - if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA."); - return ERROR_FAIL; - } - - uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_VLENB) != ERROR_OK) { - if (riscv_supports_extension(target, 'V')) - LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); - r->vlenb = 0; - } else { - r->vlenb = value; - LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb); - } - - if (register_read_direct(target, &value, GDB_REGNO_MTOPI) == ERROR_OK) { - r->mtopi_readable = true; - - if (register_read_direct(target, &value, GDB_REGNO_MTOPEI) == ERROR_OK) { - LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); - r->mtopei_readable = true; - } else { - r->mtopei_readable = false; - LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); - } - } else { - r->mtopi_readable = false; - } - - /* Display this as early as possible to help people who are using - * really slow simulators. */ - LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); - - /* Restore s0 and s1. */ - if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0."); - return ERROR_FAIL; - } - if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1."); - return ERROR_FAIL; - } - - /* Now init registers based on what we discovered. */ - if (riscv013_reg_init_all(target) != ERROR_OK) - return ERROR_FAIL; - + result = riscv013_reg_examine_all(target); if (set_dcsr_ebreak(target, false) != ERROR_OK) return ERROR_FAIL; @@ -3651,7 +3587,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -3673,7 +3609,7 @@ static int read_memory_abstract(struct target *target, target_addr_t address, } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, false); - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; @@ -3744,7 +3680,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -3766,7 +3702,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address, } else { /* Try the same access but with postincrement disabled. */ command = access_memory_command(target, false, width, false, true); - result = execute_abstract_command(target, command, &cmderr); + result = riscv013_execute_abstract_command(target, command, &cmderr); if (result == ERROR_OK) { LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); info->has_aampostincrement = YNM_NO; @@ -3812,11 +3748,11 @@ static int read_memory_progbuf_inner_startup(struct target *target, /* AC_ACCESS_REGISTER_POSTEXEC is used to trigger first stage of the * pipeline (memory -> s1) whenever this command is executed. */ - const uint32_t startup_command = access_register_command(target, + const uint32_t startup_command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) return ERROR_FAIL; /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -4299,11 +4235,11 @@ static int read_memory_progbuf_inner_one(struct target *target, if (write_abstract_arg(target, 0, access.target_address, riscv_xlen(target)) != ERROR_OK) return ERROR_FAIL; - uint32_t command = access_register_command(target, GDB_REGNO_S1, + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; return read_word_from_s1(target, access, 0); @@ -4642,14 +4578,14 @@ static int write_memory_progbuf_startup(struct target *target, target_addr_t *ad /* Write and execute command that moves the value from data0 [, data1] * into S1 and executes program buffer. */ - uint32_t command = access_register_command(target, + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; log_memory_access64(*address_p, value, size, /*is_read*/ false); @@ -5320,7 +5256,7 @@ static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr) run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); - return execute_abstract_command(target, run_program, cmderr); + return riscv013_execute_abstract_command(target, run_program, cmderr); } static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h index be508f75f..c0e96200e 100644 --- a/src/target/riscv/riscv-013.h +++ b/src/target/riscv/riscv-013.h @@ -19,5 +19,9 @@ int riscv013_set_register(struct target *target, enum gdb_regno rid, riscv_reg_t value); int riscv013_set_register_buf(struct target *target, enum gdb_regno regno, const uint8_t *value); +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, + unsigned int size, uint32_t flags); +int riscv013_execute_abstract_command(struct target *target, uint32_t command, + uint32_t *cmderr); #endif /*OPENOCD_TARGET_RISCV_RISCV_013_H*/ diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c index a71a01c7b..530008182 100644 --- a/src/target/riscv/riscv-013_reg.c +++ b/src/target/riscv/riscv-013_reg.c @@ -9,6 +9,7 @@ #include "riscv_reg.h" #include "riscv_reg_impl.h" #include "riscv-013.h" +#include "debug_defines.h" #include static int riscv013_reg_get(struct reg *reg) @@ -92,26 +93,165 @@ static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno) return &riscv011_reg_type; } -static int riscv013_init_reg(struct target *target, uint32_t regno) +static int init_cache_entry(struct target *target, uint32_t regno) { - return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno)); + return riscv_reg_impl_init_cache_entry(target, regno, riscv013_gdb_regno_reg_type(regno)); } -int riscv013_reg_init_all(struct target *target) +static int examine_xlen(struct target *target) { - if (riscv_reg_impl_init_cache(target) != ERROR_OK) + RISCV_INFO(r); + unsigned int cmderr; + const uint32_t command = riscv013_access_register_command(target, + GDB_REGNO_S0, /* size */ 64, AC_ACCESS_REGISTER_TRANSFER); + int res = riscv013_execute_abstract_command(target, command, &cmderr); + if (res == ERROR_OK) { + r->xlen = 64; + return ERROR_OK; + } + if (res == ERROR_TIMEOUT_REACHED) return ERROR_FAIL; + r->xlen = 32; + return ERROR_OK; +} + +/* As defined by RISC-V V extension specification: + * https://github.com/riscv/riscv-v-spec/blob/2f68ef7256d6ec53e4d2bd7cb12862f406d64e34/v-spec.adoc?plain=1#L67-L72 */ +#define VLEN_MAX 65536 + +static int examine_vlenb(struct target *target) +{ + RISCV_INFO(r); + /* Reading "vlenb" requires "mstatus.vs" to be set, so "mstatus" should + * be accessible.*/ + int res = init_cache_entry(target, GDB_REGNO_MSTATUS); + if (res != ERROR_OK) + return res; + + res = init_cache_entry(target, GDB_REGNO_VLENB); + if (res != ERROR_OK) + return res; + uint64_t vlenb_val; + if (riscv_reg_get(target, &vlenb_val, GDB_REGNO_VLENB) != ERROR_OK) { + if (riscv_supports_extension(target, 'V')) + 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); + } + const unsigned int vlenb_max = VLEN_MAX / 8; + if (vlenb_val > vlenb_max) { + LOG_TARGET_WARNING(target, "'vlenb == %" PRIu64 + "' is greater than maximum allowed by specification (%u); vector register access won't work.", + vlenb_val, vlenb_max); + r->vlenb = 0; + return ERROR_OK; + } + assert(vlenb_max <= UINT_MAX); + r->vlenb = (unsigned int)vlenb_val; + LOG_TARGET_INFO(target, "Vector support with vlenb=%u", r->vlenb); + return ERROR_OK; +} + +static int examine_misa(struct target *target) +{ + RISCV_INFO(r); + int res = init_cache_entry(target, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + + res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + return ERROR_OK; +} + +static int examine_mtopi(struct target *target) +{ + RISCV_INFO(r); + + /* Assume the registers exist */ + r->mtopi_readable = true; + r->mtopei_readable = true; + + int res = init_cache_entry(target, GDB_REGNO_MTOPI); + if (res != ERROR_OK) + return res; + res = init_cache_entry(target, GDB_REGNO_MTOPEI); + if (res != ERROR_OK) + return res; + + riscv_reg_t value; + if (riscv_reg_get(target, &value, GDB_REGNO_MTOPI) != ERROR_OK) { + r->mtopi_readable = false; + r->mtopei_readable = false; + } else if (riscv_reg_get(target, &value, GDB_REGNO_MTOPEI) != ERROR_OK) { + LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); + r->mtopei_readable = false; + } else { + LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); + } + res = riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPI, r->mtopi_readable); + if (res != ERROR_OK) + return res; + return riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPEI, r->mtopei_readable); +} + +/** + * This function assumes target's DM to be initialized (target is able to + * access DMs registers, execute program buffer, etc.) + */ +int riscv013_reg_examine_all(struct target *target) +{ + RISCV_INFO(r); + + int res = riscv_reg_impl_init_cache(target); + if (res != ERROR_OK) + return res; init_shared_reg_info(target); + assert(target->state == TARGET_HALTED); + + res = examine_xlen(target); + if (res != ERROR_OK) + return res; + + /* Reading CSRs may clobber "s0", "s1", so it should be possible to + * save them in cache. */ + res = init_cache_entry(target, GDB_REGNO_S0); + if (res != ERROR_OK) + return res; + res = init_cache_entry(target, GDB_REGNO_S1); + if (res != ERROR_OK) + return res; + + res = examine_misa(target); + if (res != ERROR_OK) + return res; + + /* 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); + + res = examine_vlenb(target); + if (res != ERROR_OK) + return res; + riscv_reg_impl_init_vector_reg_type(target); - for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) - if (riscv013_init_reg(target, regno) != ERROR_OK) - return ERROR_FAIL; + res = examine_mtopi(target); + if (res != ERROR_OK) + return res; - if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) - return ERROR_FAIL; + for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) { + res = init_cache_entry(target, regno); + if (res != ERROR_OK) + return res; + } + + res = riscv_reg_impl_expose_csrs(target); + if (res != ERROR_OK) + return res; riscv_reg_impl_hide_csrs(target); diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h index 2bdaaa036..b75a25887 100644 --- a/src/target/riscv/riscv-013_reg.h +++ b/src/target/riscv/riscv-013_reg.h @@ -13,10 +13,11 @@ */ /** - * Init initialize register cache. After this function all registers can be - * safely accessed via functions described here and in `riscv_reg.h`. + * This function assumes target is halted. + * After this function all registers can be safely accessed via functions + * described here and in `riscv_reg.h`. */ -int riscv013_reg_init_all(struct target *target); +int riscv013_reg_examine_all(struct target *target); /** * This function is used to save the value of a register in cache. The register diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index 6cf67dded..6319a62e1 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -599,14 +599,14 @@ static int resize_reg(const struct target *target, uint32_t regno, bool exist, return ERROR_OK; } -static int set_reg_exist(const struct target *target, uint32_t regno, bool exist) +int riscv_reg_impl_set_exist(const struct target *target, uint32_t regno, bool exist) { const struct reg *reg = riscv_reg_impl_cache_entry(target, regno); assert(riscv_reg_impl_is_initialized(reg)); return resize_reg(target, regno, exist, reg->size); } -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type) +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type) { struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); if (riscv_reg_impl_is_initialized(reg)) @@ -725,7 +725,7 @@ int riscv_reg_impl_expose_csrs(const struct target *target) csr_number); continue; } - if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK) + if (riscv_reg_impl_set_exist(target, regno, /*exist*/ true) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", csr_number, reg->name); @@ -834,15 +834,8 @@ static int riscv_set_or_write_register(struct target *target, return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through); } - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, - "No cache, writing to target: %s <- 0x%" PRIx64, - riscv_reg_gdb_regno_name(target, regid), value); - return riscv013_set_register(target, regid, value); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); @@ -935,21 +928,15 @@ int riscv_reg_get(struct target *target, riscv_reg_t *value, RISCV_INFO(r); assert(r); if (r->dtm_version == DTM_DTMCS_VERSION_0_11) - return riscv013_get_register(target, value, regid); + return riscv011_get_register(target, value, regid); keep_alive(); if (regid == GDB_REGNO_PC) return riscv_reg_get(target, value, GDB_REGNO_DPC); - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, "No cache, reading %s from target", - riscv_reg_gdb_regno_name(target, regid)); - return riscv013_get_register(target, value, regid); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); return ERROR_FAIL; diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 906a5b6d5..219af0a9b 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -13,7 +13,7 @@ * This file describes the helpers to use during register cache initialization * of a RISC-V target. Each cache entry proceedes through the following stages: * - not allocated before `riscv_reg_impl_init_cache()` - * - not initialized before the call to `riscv_reg_impl_init_one()` with appropriate regno. + * - not initialized before the call to `riscv_reg_impl_init_cache_entry()` with appropriate regno. * - initialized until `riscv_reg_free_all()` is called. */ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) @@ -37,9 +37,13 @@ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) int riscv_reg_impl_init_cache(struct target *target); /** Initialize register. */ -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type); +/** Mark register as existing or not. */ +int riscv_reg_impl_set_exist(const struct target *target, + uint32_t regno, bool exist); + /** Return the entry in the register cache of the target. */ struct reg *riscv_reg_impl_cache_entry(const struct target *target, uint32_t number);