diff options
author | Antonio Borneo <borneo.antonio@gmail.com> | 2020-11-22 12:29:04 +0100 |
---|---|---|
committer | Antonio Borneo <borneo.antonio@gmail.com> | 2020-12-05 23:18:29 +0000 |
commit | a56b7291911b4f42718d406dd2de857db4c11e0f (patch) | |
tree | 7ae235715f4ab92a4f4a3f6ef3325874242bc3bd /src/target | |
parent | 62686ab161e9c46a620dd592b2767634e9483c20 (diff) | |
download | riscv-openocd-a56b7291911b4f42718d406dd2de857db4c11e0f.zip riscv-openocd-a56b7291911b4f42718d406dd2de857db4c11e0f.tar.gz riscv-openocd-a56b7291911b4f42718d406dd2de857db4c11e0f.tar.bz2 |
arm7_9_common: fix host endianness bug in arm7_9_full_context()
The original code passes to ->read_core_regs() and to
->read_xpsr() the pointer to the little-endian buffer reg.value.
This is incorrect because the two functions above require a
pointer to uint32_t, since they already run the conversion with
arm_le_to_h_u32() in the jtag callback.
This causes a mismatch on big-endian host and the registers get
read with the incorrect endianness.
Use an intermediate buffer to read the registers as uint32_t and
to track the destination reg.value pointer, then copy the value in
reg.value after the call to jtag_execute_queue().
Tested with qemu-armeb and an OpenOCD built through buildroot
configured for cortex-a7 big-endian.
Note that if jtag_execute_queue() fails, the openocd register
cache is not updated, so the already modified flags 'valid' and
'dirty' are incorrect. This part should be moved after the call to
jtag_execute_queue() too.
Change-Id: Iba70d964ffbb74bf0860bfd9d299f218e3bc65bf
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5943
Tested-by: jenkins
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/arm7_9_common.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index d70d273..d992aa7 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1391,6 +1391,11 @@ static int arm7_9_full_context(struct target *target) int retval; struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; + struct { + uint32_t value; + void *reg_p; + } read_cache[6 * (16 + 1)]; + int read_cache_idx = 0; LOG_DEBUG("-"); @@ -1433,10 +1438,12 @@ static int arm7_9_full_context(struct target *target) for (j = 0; j < 15; j++) { if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), j).valid) { - reg_p[j] = (uint32_t *)ARMV4_5_CORE_REG_MODE( + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE( arm->core_cache, armv4_5_number_to_mode(i), j).value; + reg_p[j] = &read_cache[read_cache_idx].value; + read_cache_idx++; mask |= 1 << j; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1454,9 +1461,10 @@ static int arm7_9_full_context(struct target *target) /* check if the PSR has to be read */ if (!ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid) { - arm7_9->read_xpsr(target, - (uint32_t *)ARMV4_5_CORE_REG_MODE(arm->core_cache, - armv4_5_number_to_mode(i), 16).value, 1); + read_cache[read_cache_idx].reg_p = ARMV4_5_CORE_REG_MODE(arm->core_cache, + armv4_5_number_to_mode(i), 16).value; + arm7_9->read_xpsr(target, &read_cache[read_cache_idx].value, 1); + read_cache_idx++; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), 16).valid = true; ARMV4_5_CORE_REG_MODE(arm->core_cache, armv4_5_number_to_mode(i), @@ -1472,6 +1480,14 @@ static int arm7_9_full_context(struct target *target) retval = jtag_execute_queue(); if (retval != ERROR_OK) return retval; + /* + * FIXME: regs in cache should be tagged as 'valid' only now, + * not before the jtag_execute_queue() + */ + while (read_cache_idx) { + read_cache_idx--; + buf_set_u32(read_cache[read_cache_idx].reg_p, 0, 32, read_cache[read_cache_idx].value); + } return ERROR_OK; } |