Skip to content

Commit 6c021da

Browse files
committed
target/riscv: check misa value before reporting
Currently, during register file examination: 1. A read of an XPR is attempted via 64-bit abstract access. 2. If such a read fails (e.g. connection unstable) XLEN is assumed to be 32. 3. Then `misa` is read. Since `misa` is a CSR and it may be only readable via program buffer, `s0` should be readable beforehand (at least some assumption about `xlen` should be made). 4. Before the commit, the `misa.mxl` field was not checked against `xlen`, therefore erroneous info may have been reported to the user. Moreover, the `examine()` would pass indicating no error at all. 5. After the commit, `misa.mxl` is checked against `xlen` value. Change-Id: I3fe5bd6742e564e6de782aad9ed10e65c0728923 Signed-off-by: Evgeniy Naydanov <[email protected]>
1 parent 909bbb8 commit 6c021da

File tree

1 file changed

+90
-8
lines changed

1 file changed

+90
-8
lines changed

src/target/riscv/riscv-013_reg.c

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#endif
66

77
#include "riscv-013_reg.h"
8+
#include "field_helpers.h"
89

910
#include "riscv_reg.h"
1011
#include "riscv_reg_impl.h"
@@ -173,6 +174,94 @@ static int examine_vlenb(struct target *target)
173174
return ERROR_OK;
174175
}
175176

177+
enum misa_mxl {
178+
MISA_MXL_INVALID = 0,
179+
MISA_MXL_32 = 1,
180+
MISA_MXL_64 = 2,
181+
MISA_MXL_128 = 3
182+
};
183+
184+
unsigned int mxl_to_xlen(enum misa_mxl mxl)
185+
{
186+
switch (mxl) {
187+
case MISA_MXL_32:
188+
return 32;
189+
case MISA_MXL_64:
190+
return 64;
191+
case MISA_MXL_128:
192+
return 128;
193+
case MISA_MXL_INVALID:
194+
assert(0);
195+
}
196+
return 0;
197+
}
198+
199+
static int check_misa_mxl(const struct target *target)
200+
{
201+
RISCV_INFO(r);
202+
203+
if (r->misa == 0) {
204+
LOG_TARGET_WARNING(target, "'misa' register is read as zero."
205+
"OpenOCD will not be able to determine some hart's capabilities.");
206+
return ERROR_OK;
207+
}
208+
const unsigned int dxlen = riscv_xlen(target);
209+
assert(dxlen <= sizeof(riscv_reg_t) * CHAR_BIT);
210+
assert(dxlen >= 2);
211+
const riscv_reg_t misa_mxl_mask = (riscv_reg_t)0x3 << (dxlen - 2);
212+
const unsigned int mxl = get_field(r->misa, misa_mxl_mask);
213+
if (mxl == MISA_MXL_INVALID) {
214+
/* This is not an error!
215+
* Imagine the platform that:
216+
* - Has no abstract access to CSRs, so that CSRs are read
217+
* through Program Buffer via "csrr" instruction.
218+
* - Complies to v1.10 of the Priveleged Spec, so that misa.mxl
219+
* is WARL and MXLEN may be chainged.
220+
* https://github.com/riscv/riscv-isa-manual/commit/9a7dd2fe29011587954560b5dcf1875477b27ad8
221+
* - DXLEN == MXLEN on reset == 64.
222+
* In a following scenario:
223+
* - misa.mxl was written, so that MXLEN is 32.
224+
* - Debugger connects to the target.
225+
* - Debugger observes DXLEN == 64.
226+
* - Debugger reads misa:
227+
* - Abstract access fails with "cmderr == not supported".
228+
* - Access via Program Buffer involves reading "misa" to an
229+
* "xreg" via "csrr", so that the "xreg" is filled with
230+
* zero-extended value of "misa" (since "misa" is
231+
* MXLEN-wide).
232+
* - Debugger derives "misa.mxl" assumig "misa" is DXLEN-bit
233+
* wide (64) while MXLEN is 32 and therefore erroneously
234+
* assumes "misa.mxl" to be zero (invalid).
235+
*/
236+
LOG_TARGET_WARNING(target, "Detected DXLEN (%u) does not match "
237+
"MXLEN: misa.mxl == 0, misa == 0x%" PRIx64 ".",
238+
dxlen, r->misa);
239+
return ERROR_OK;
240+
}
241+
const unsigned int mxlen = mxl_to_xlen(mxl);
242+
if (dxlen < mxlen) {
243+
LOG_TARGET_ERROR(target,
244+
"MXLEN (%u) reported in misa.mxl field exceeds "
245+
"the detected DXLEN (%u)",
246+
mxlen, dxlen);
247+
return ERROR_FAIL;
248+
}
249+
/* NOTE:
250+
* The value of "misa.mxl" may stil not coincide with "xlen".
251+
* "misa[26:XLEN-3]" bits are marked as WIRI in at least version 1.10
252+
* of RISC-V Priveleged Spec. Therefore, if "xlen" is erroneously
253+
* assumed to be 32 when it actually is 64, "mxl" will be read from
254+
* this WIRI field and may be equal to "MISA_MXL_32" by coincidence.
255+
* This is not an issue though from the version 1.11 onward, since
256+
* "misa[26:XLEN-3]" became WARL and equal to 0.
257+
*/
258+
259+
/* Display this as early as possible to help people who are using
260+
* really slow simulators. */
261+
LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa);
262+
return ERROR_OK;
263+
}
264+
176265
static int examine_misa(struct target *target)
177266
{
178267
RISCV_INFO(r);
@@ -184,8 +273,7 @@ static int examine_misa(struct target *target)
184273
res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA);
185274
if (res != ERROR_OK)
186275
return res;
187-
188-
return ERROR_OK;
276+
return check_misa_mxl(target);
189277
}
190278

191279
static int examine_mtopi(struct target *target)
@@ -226,8 +314,6 @@ static int examine_mtopi(struct target *target)
226314
*/
227315
int riscv013_reg_examine_all(struct target *target)
228316
{
229-
RISCV_INFO(r);
230-
231317
int res = riscv_reg_impl_init_cache(target);
232318
if (res != ERROR_OK)
233319
return res;
@@ -253,10 +339,6 @@ int riscv013_reg_examine_all(struct target *target)
253339
if (res != ERROR_OK)
254340
return res;
255341

256-
/* Display this as early as possible to help people who are using
257-
* really slow simulators. */
258-
LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa);
259-
260342
res = examine_vlenb(target);
261343
if (res != ERROR_OK)
262344
return res;

0 commit comments

Comments
 (0)