From 96b7d46c45a556a3fdb0d8c0a3c9c9ecfcbc0eea Mon Sep 17 00:00:00 2001 From: Evgeniy Naydanov Date: Wed, 26 Feb 2025 15:53:06 +0300 Subject: [PATCH] target/riscv: warn about truncating register values When reading a register via Program Buffer the actual value is read from a GPR. The GPR size (XLEN) can be greater than the length of the target register (e.g. `dcsr` is always 32-bit wide). Due to some HW issue GPR read may return a value that needs to be truncated to fit into the target register. Warn the user about it. Moreover, the value in cache was and is truncated, but the `riscv_reg_t` that is filled by `riscv_reg_get()` didn't use to be. This may lead to an assertion failure in `abstract_data_write_fill_batch()`: Link: https://github.com/riscv-collab/riscv-openocd/blob/fa7e2351c834d63016db65923f25ec599bb7ceac/src/target/riscv/riscv-013.c#L757 Change-Id: I4d8a5ba2451fc5a60f51b9143b6b140dfe3b73b8 Signed-off-by: Evgeniy Naydanov --- src/target/riscv/riscv-013.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 23c0aa62c..f779ce6a2 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1370,14 +1370,31 @@ static int register_read_progbuf(struct target *target, uint64_t *value, { assert(target->state == TARGET_HALTED); - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) - return fpr_read_progbuf(target, value, number); - else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) - return csr_read_progbuf(target, value, number); + int res; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + res = fpr_read_progbuf(target, value, number); + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + res = csr_read_progbuf(target, value, number); + } else { + LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", + riscv_reg_gdb_regno_name(target, number)); + return ERROR_FAIL; + } + if (res != ERROR_OK) + return res; - LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", - riscv_reg_gdb_regno_name(target, number)); - return ERROR_FAIL; + unsigned int size_bits = register_size(target, number); + unsigned int value_bits = sizeof(*value) * CHAR_BIT; + assert(size_bits <= value_bits); + if (size_bits == value_bits || *value >> size_bits == 0) + return ERROR_OK; + + LOG_TARGET_WARNING(target, "Value read for register %s of %" PRIx64 + " does not fit into the size of the register (%u bits)." + " This is a HW bug. Truncating the value to fit into the register.", + riscv_reg_gdb_regno_name(target, number), *value, size_bits); + *value &= GENMASK_ULL(size_bits - 1U, 0U); + return ERROR_OK; } /**