aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2020-08-18 11:01:41 -0700
committerGitHub <noreply@github.com>2020-08-18 11:01:41 -0700
commit53ec10b61da5de553c01f92bddf80c076bd49331 (patch)
tree119b65e595cde3eab560f8181de2ec8a1118cd61
parentc1c88dcceeb94657971fd577878af0a4f8a39d69 (diff)
downloadriscv-openocd-53ec10b61da5de553c01f92bddf80c076bd49331.zip
riscv-openocd-53ec10b61da5de553c01f92bddf80c076bd49331.tar.gz
riscv-openocd-53ec10b61da5de553c01f92bddf80c076bd49331.tar.bz2
Create `riscv repeat_read` command (#510)
* WIP, apply stash with conflicts. Change-Id: Ia794bde419aa29161c68898d20e30527e69f5a31 * Fix conflict resolution problems. Change-Id: I4cedc348cf613f98cc5a36886f37c568ca644238 * Add repeat_read command. Only implemented for sba v1 right now, and poorly tested at that. Change-Id: I1d9ff63e1dea14b3f6a9f8ba4dad53668bf8038b * Hide bogus address in repeat_read Change-Id: Ib66c1fa60df9c7fc7cc87880b0fddc52825b48aa * WIP make repeat read work with progbuf. Change-Id: I555f8b880c8bf0d1ed0f3f90c7987a5b516a7a79 * WIP Change-Id: Ic567cea68355ae907e94bd25185a2c9be6fd798d * Fix error handling when increment is non-zero. Change-Id: I5a2f3f2ee948fd4e12c0443a542e85b7b5c5791a * Correctly(?) handle failures when increment is 0. I'm not 100% convinced that this ensures every read value shows up in the output, but it ought to work. Change-Id: I1af3e7174cf9d5e6f293456fb5ead629e17faaaa * Don't crash when asked to read no data. Change-Id: I4061b5c720a43a4f828384ab9eacc89557adfa05 * Remove unnecessary comment. Change-Id: I1be3d699b86299339b3a830ca1ef13c9f5b9fe0f * Document `riscv repeat_read`. Change-Id: I4a0f071f38784b2de034f8c1b0ce75d6d2d326b2
-rw-r--r--doc/openocd.texi6
-rw-r--r--src/flash/nor/tcl.c3
-rw-r--r--src/target/dsp563xx.c3
-rw-r--r--src/target/riscv/riscv-011.c47
-rw-r--r--src/target/riscv/riscv-013.c143
-rw-r--r--src/target/riscv/riscv.c60
-rw-r--r--src/target/riscv/riscv.h3
-rw-r--r--src/target/target.c7
-rw-r--r--src/target/target.h2
9 files changed, 188 insertions, 86 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index a80f6a4..9a278b4 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -9659,6 +9659,12 @@ indicates the first custom register, whose abstract command number is 0xc000.
This command must be executed before `init`.
@end deffn
+@deffn Command {riscv repeat_read} count address [size=4]
+Quickly read count words of the given size from address. This can be useful
+to read out a buffer that's memory-mapped to be accessed through a single
+address, or to sample a changing value in a memory-mapped device.
+@end deffn
+
@deffn Command {riscv set_command_timeout_sec} [seconds]
Set the wall-clock timeout (in seconds) for individual commands. The default
should work fine for all but the slowest targets (eg. simulators).
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index fb2053b..741bb5e 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -681,7 +681,8 @@ COMMAND_HANDLER(handle_flash_md_command)
retval = flash_driver_read(bank, buffer, offset, sizebytes);
if (retval == ERROR_OK)
- target_handle_md_output(CMD, target, address, wordsize, count, buffer);
+ target_handle_md_output(CMD, target, address, wordsize, count,
+ buffer, true);
free(buffer);
diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c
index 6a5c868..67c1538 100644
--- a/src/target/dsp563xx.c
+++ b/src/target/dsp563xx.c
@@ -2148,7 +2148,8 @@ COMMAND_HANDLER(dsp563xx_mem_command)
err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t),
count, buffer);
if (err == ERROR_OK)
- target_handle_md_output(CMD, target, address, sizeof(uint32_t), count, buffer);
+ target_handle_md_output(CMD, target, address, sizeof(uint32_t),
+ count, buffer, true);
} else {
b = buffer;
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index f1b3c66..8bd8828 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -1386,25 +1386,6 @@ static int halt(struct target *target)
return ERROR_OK;
}
-static int init_target(struct command_context *cmd_ctx,
- struct target *target)
-{
- LOG_DEBUG("init");
- riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
- generic_info->get_register = get_register;
- generic_info->set_register = set_register;
-
- generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
- if (!generic_info->version_specific)
- return ERROR_FAIL;
-
- /* Assume 32-bit until we discover the real value in examine(). */
- generic_info->xlen[0] = 32;
- riscv_init_registers(target);
-
- return ERROR_OK;
-}
-
static void deinit_target(struct target *target)
{
LOG_DEBUG("riscv_deinit_target()");
@@ -1980,8 +1961,13 @@ static int deassert_reset(struct target *target)
}
static int read_memory(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
+ if (increment != size) {
+ LOG_ERROR("read_memory with custom increment not implemented");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16));
@@ -2283,6 +2269,26 @@ static int arch_state(struct target *target)
return ERROR_OK;
}
+static int init_target(struct command_context *cmd_ctx,
+ struct target *target)
+{
+ LOG_DEBUG("init");
+ riscv_info_t *generic_info = (riscv_info_t *) target->arch_info;
+ generic_info->get_register = get_register;
+ generic_info->set_register = set_register;
+ generic_info->read_memory = read_memory;
+
+ generic_info->version_specific = calloc(1, sizeof(riscv011_info_t));
+ if (!generic_info->version_specific)
+ return ERROR_FAIL;
+
+ /* Assume 32-bit until we discover the real value in examine(). */
+ generic_info->xlen[0] = 32;
+ riscv_init_registers(target);
+
+ return ERROR_OK;
+}
+
struct target_type riscv011_target = {
.name = "riscv",
@@ -2300,7 +2306,6 @@ struct target_type riscv011_target = {
.assert_reset = assert_reset,
.deassert_reset = deassert_reset,
- .read_memory = read_memory,
.write_memory = write_memory,
.arch_state = arch_state,
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 6a25282..8025496 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -64,7 +64,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t
static int register_write_direct(struct target *target, unsigned number,
uint64_t value);
static int read_memory(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer);
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer);
static int riscv013_test_sba_config_reg(struct target *target, target_addr_t legal_address,
@@ -1226,7 +1226,7 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch,
case SPACE_DMI_RAM:
{
uint8_t buffer[8] = {0};
- if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK)
+ if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK)
return ERROR_FAIL;
*value = buffer[0] |
(((uint64_t) buffer[1]) << 8) |
@@ -2030,6 +2030,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->authdata_write = &riscv013_authdata_write;
generic_info->dmi_read = &dmi_read;
generic_info->dmi_write = &dmi_write;
+ generic_info->read_memory = read_memory;
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
generic_info->test_compliance = &riscv013_test_compliance;
generic_info->hart_count = &riscv013_hart_count;
@@ -2424,8 +2425,13 @@ static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *
}
static int read_memory_bus_v0(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
+ if (size != increment) {
+ LOG_ERROR("sba v0 reads only support size==increment");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+
LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08"
TARGET_PRIxADDR, size, count, address);
uint8_t *t_buffer = buffer;
@@ -2504,8 +2510,13 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address,
* Read the requested memory using the system bus interface.
*/
static int read_memory_bus_v1(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
+ if (increment != size && increment != 0) {
+ LOG_ERROR("sba v1 reads only support increment of size or 0");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+
RISCV013_INFO(info);
target_addr_t next_address = address;
target_addr_t end_address = address + count * size;
@@ -2513,7 +2524,8 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
while (next_address < end_address) {
uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1);
sbcs_write |= sb_sbaccess(size);
- sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1);
+ if (increment == size)
+ sbcs_write = set_field(sbcs_write, DMI_SBCS_SBAUTOINCREMENT, 1);
if (count > 1)
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1);
if (dmi_write(target, DMI_SBCS, sbcs_write) != ERROR_OK)
@@ -2651,8 +2663,13 @@ static int batch_run(const struct target *target, struct riscv_batch *batch)
* aamsize fields in the memory access abstract command.
*/
static int read_memory_abstract(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
+ if (size != increment) {
+ LOG_ERROR("abstract command reads only support size==increment");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+
int result = ERROR_OK;
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count,
@@ -2771,7 +2788,7 @@ static int write_memory_abstract(struct target *target, target_addr_t address,
* even if cmderr=busy is encountered.
*/
static int read_memory_progbuf_inner(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
RISCV013_INFO(info);
@@ -2781,6 +2798,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
result = register_write_direct(target, GDB_REGNO_S0, address);
if (result != ERROR_OK)
return result;
+
+ if (increment == 0 &&
+ register_write_direct(target, GDB_REGNO_S2, 0) != ERROR_OK)
+ return ERROR_FAIL;
+
uint32_t command = access_register_command(target, GDB_REGNO_S1,
riscv_xlen(target),
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC);
@@ -2808,11 +2830,10 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
/* read_addr is the next address that the hart will read from, which is the
* value in s0. */
- riscv_addr_t read_addr = address + 2 * size;
- riscv_addr_t fin_addr = address + (count * size);
- while (read_addr < fin_addr) {
- LOG_DEBUG("read_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr,
- fin_addr);
+ unsigned index = 2;
+ while (index < count) {
+ riscv_addr_t read_addr = address + index * increment;
+ LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr);
/* The pipeline looks like this:
* memory -> s1 -> dm_data0 -> debugger
* Right now:
@@ -2821,14 +2842,11 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
* dm_data0 contains[read_addr-size*2]
*/
- LOG_DEBUG("creating burst to read from 0x%" PRIx64
- " up to 0x%" PRIx64, read_addr, fin_addr);
- assert(read_addr >= address && read_addr < fin_addr);
struct riscv_batch *batch = riscv_batch_alloc(target, 32,
info->dmi_busy_delay + info->ac_busy_delay);
- size_t reads = 0;
- for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) {
+ unsigned reads = 0;
+ for (unsigned j = index; j < count; j++) {
if (size > 4)
riscv_batch_add_dmi_read(batch, DMI_DATA1);
riscv_batch_add_dmi_read(batch, DMI_DATA0);
@@ -2851,12 +2869,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
return ERROR_FAIL;
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
- riscv_addr_t next_read_addr;
+ unsigned next_index;
unsigned ignore_last = 0;
switch (info->cmderr) {
case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory read");
- next_read_addr = read_addr + reads * size;
+ next_index = index + reads;
break;
case CMDERR_BUSY:
LOG_DEBUG("memory read resulted in busy response");
@@ -2880,21 +2898,30 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
}
/* See how far we got, clobbering dmi_data0. */
- result = register_read_direct(target, &next_read_addr,
- GDB_REGNO_S0);
+ if (increment == 0) {
+ uint64_t counter;
+ result = register_read_direct(target, &counter, GDB_REGNO_S2);
+ next_index = counter;
+ } else {
+ uint64_t next_read_addr;
+ result = register_read_direct(target, &next_read_addr,
+ GDB_REGNO_S0);
+ next_index = (next_read_addr - address) / increment;
+ }
if (result != ERROR_OK) {
riscv_batch_free(batch);
goto error;
}
+
uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0;
- write_to_buf(buffer + next_read_addr - 2 * size - address, value64, size);
- log_memory_access(next_read_addr - 2 * size, value64, size, true);
+ write_to_buf(buffer + (next_index - 2) * size, value64, size);
+ log_memory_access(address + (next_index - 2) * size, value64, size, true);
/* Restore the command, and execute it.
* Now DMI_DATA0 contains the next value just as it would if no
* error had occurred. */
dmi_write_exec(target, DMI_COMMAND, command, true);
- next_read_addr += size;
+ next_index++;
dmi_write(target, DMI_ABSTRACTAUTO,
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
@@ -2912,13 +2939,13 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
/* Now read whatever we got out of the batch. */
dmi_status_t status = DMI_STATUS_SUCCESS;
- riscv_addr_t receive_addr = read_addr - size * 2;
unsigned read = 0;
- for (size_t i = 0; i < reads; i++) {
- assert(receive_addr < address + size * count);
- if (receive_addr < address)
- continue;
- if (receive_addr > next_read_addr - (3 + ignore_last) * size)
+ assert(index >= 2);
+ for (unsigned j = index - 2; j < index + reads; j++) {
+ assert(j < count);
+ LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d",
+ index, reads, next_index, ignore_last, j);
+ if (j + 3 + ignore_last > next_index)
break;
status = riscv_batch_get_dmi_read_op(batch, read);
@@ -2952,14 +2979,12 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
value |= riscv_batch_get_dmi_read_data(batch, read);
read++;
}
- riscv_addr_t offset = receive_addr - address;
+ riscv_addr_t offset = j * size;
write_to_buf(buffer + offset, value, size);
- log_memory_access(receive_addr, value, size, true);
-
- receive_addr += size;
+ log_memory_access(address + j * increment, value, size, true);
}
- read_addr = next_read_addr;
+ index = next_index;
riscv_batch_free(batch);
}
@@ -3069,7 +3094,7 @@ static int read_memory_progbuf_one(struct target *target, target_addr_t address,
* Read the requested memory, silently handling memory access errors.
*/
static int read_memory_progbuf(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
if (riscv_xlen(target) < size * 8) {
LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.",
@@ -3099,12 +3124,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
/* s0 holds the next address to write to
* s1 holds the next data value to write
+ * s2 is a counter in case increment is 0
*/
- uint64_t s0, s1;
+ uint64_t s0, s1, s2;
if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
+ if (increment == 0 && register_read(target, &s2, GDB_REGNO_S1) != ERROR_OK)
+ return ERROR_FAIL;
/* Write the program (load, increment) */
struct riscv_program program;
@@ -3132,36 +3160,39 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
if (riscv_enable_virtual && has_sufficient_progbuf(target, 5) && get_field(mstatus, MSTATUS_MPRV))
riscv_program_csrrci(&program, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, GDB_REGNO_DCSR);
- riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size);
+ if (increment == 0)
+ riscv_program_addi(&program, GDB_REGNO_S2, GDB_REGNO_S2, 1);
+ else
+ riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, increment);
if (riscv_program_ebreak(&program) != ERROR_OK)
return ERROR_FAIL;
if (riscv_program_write(&program) != ERROR_OK)
return ERROR_FAIL;
- result = read_memory_progbuf_inner(target, address, size, count, buffer);
+ result = read_memory_progbuf_inner(target, address, size, count, buffer, increment);
if (result != ERROR_OK) {
/* The full read did not succeed, so we will try to read each word individually. */
/* This will not be fast, but reading outside actual memory is a special case anyway. */
/* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */
target_addr_t address_i = address;
- uint32_t size_i = size;
uint32_t count_i = 1;
uint8_t *buffer_i = buffer;
- for (uint32_t i = 0; i < count; i++, address_i += size_i, buffer_i += size_i) {
+ for (uint32_t i = 0; i < count; i++, address_i += increment, buffer_i += size) {
+ keep_alive();
/* TODO: This is much slower than it needs to be because we end up
* writing the address to read for every word we read. */
- result = read_memory_progbuf_inner(target, address_i, size_i, count_i, buffer_i);
+ result = read_memory_progbuf_inner(target, address_i, size, count_i, buffer_i, increment);
/* The read of a single word failed, so we will just return 0 for that instead */
if (result != ERROR_OK) {
LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR,
- size_i, address_i);
+ size, address_i);
uint64_t value_i = 0;
- write_to_buf(buffer_i, value_i, size_i);
+ write_to_buf(buffer_i, value_i, size);
}
}
result = ERROR_OK;
@@ -3169,6 +3200,8 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
riscv_set_register(target, GDB_REGNO_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1);
+ if (increment == 0)
+ riscv_set_register(target, GDB_REGNO_S2, s2);
/* Restore MSTATUS */
if (mstatus != mstatus_old)
@@ -3179,12 +3212,15 @@ static int read_memory_progbuf(struct target *target, target_addr_t address,
}
static int read_memory(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment)
{
- RISCV013_INFO(info);
+ if (count == 0)
+ return ERROR_OK;
+ RISCV013_INFO(info);
if (has_sufficient_progbuf(target, 3) && !riscv_prefer_sba)
- return read_memory_progbuf(target, address, size, count, buffer);
+ return read_memory_progbuf(target, address, size, count, buffer,
+ increment);
if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) ||
@@ -3192,15 +3228,19 @@ static int read_memory(struct target *target, target_addr_t address,
(get_field(info->sbcs, DMI_SBCS_SBACCESS64) && size == 8) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) {
if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0)
- return read_memory_bus_v0(target, address, size, count, buffer);
+ return read_memory_bus_v0(target, address, size, count, buffer,
+ increment);
else if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 1)
- return read_memory_bus_v1(target, address, size, count, buffer);
+ return read_memory_bus_v1(target, address, size, count, buffer,
+ increment);
}
if (has_sufficient_progbuf(target, 3))
- return read_memory_progbuf(target, address, size, count, buffer);
+ return read_memory_progbuf(target, address, size, count, buffer,
+ increment);
- return read_memory_abstract(target, address, size, count, buffer);
+ return read_memory_abstract(target, address, size, count, buffer,
+ increment);
}
static int write_memory_bus_v0(struct target *target, target_addr_t address,
@@ -3643,7 +3683,6 @@ struct target_type riscv013_target = {
.assert_reset = assert_reset,
.deassert_reset = deassert_reset,
- .read_memory = read_memory,
.write_memory = write_memory,
.arch_state = arch_state,
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index e213ffa..56c95f8 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -1487,12 +1487,12 @@ static int riscv_mmu(struct target *target, int *enabled)
static int riscv_address_translate(struct target *target,
target_addr_t virtual, target_addr_t *physical)
{
+ RISCV_INFO(r);
riscv_reg_t satp_value;
int mode;
uint64_t ppn_value;
target_addr_t table_address;
virt2phys_info_t *info;
- struct target_type *tt = get_target_type(target);
uint64_t pte;
int i;
@@ -1545,8 +1545,8 @@ static int riscv_address_translate(struct target *target,
(vpn << info->pte_shift);
uint8_t buffer[8];
assert(info->pte_shift <= 3);
- int retval = tt->read_memory(target, pte_address,
- 4, (1 << info->pte_shift) / 4, buffer);
+ int retval = r->read_memory(target, pte_address,
+ 4, (1 << info->pte_shift) / 4, buffer, 4);
if (retval != ERROR_OK)
return ERROR_FAIL;
@@ -1610,10 +1610,10 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
+ RISCV_INFO(r);
if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL;
- struct target_type *tt = get_target_type(target);
- return tt->read_memory(target, phys_address, size, count, buffer);
+ return r->read_memory(target, phys_address, size, count, buffer, size);
}
static int riscv_read_memory(struct target *target, target_addr_t address,
@@ -1631,8 +1631,8 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
address = physical_addr;
- struct target_type *tt = get_target_type(target);
- return tt->read_memory(target, address, size, count, buffer);
+ RISCV_INFO(r);
+ return r->read_memory(target, address, size, count, buffer, size);
}
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
@@ -2656,8 +2656,54 @@ COMMAND_HANDLER(riscv_set_ebreaku)
return ERROR_OK;
}
+COMMAND_HANDLER(handle_repeat_read)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ RISCV_INFO(r);
+
+ if (CMD_ARGC < 2) {
+ LOG_ERROR("Command requires at least count and address arguments.");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ if (CMD_ARGC > 3) {
+ LOG_ERROR("Command takes at most 3 arguments.");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ uint32_t count;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count);
+ target_addr_t address;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address);
+ uint32_t size = 4;
+ if (CMD_ARGC > 2)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size);
+
+ if (count == 0)
+ return ERROR_OK;
+
+ uint8_t *buffer = malloc(size * count);
+ if (!buffer) {
+ LOG_ERROR("malloc failed");
+ return ERROR_FAIL;
+ }
+ int result = r->read_memory(target, address, size, count, buffer, 0);
+ if (result == ERROR_OK) {
+ target_handle_md_output(cmd, target, address, size, count, buffer,
+ false);
+ }
+ free(buffer);
+ return result;
+}
+
static const struct command_registration riscv_exec_command_handlers[] = {
{
+ .name = "repeat_read",
+ .handler = handle_repeat_read,
+ .mode = COMMAND_ANY,
+ .usage = "riscv repeat_read count address [size=4]",
+ .help = "Repeatedly read the value at address."
+ },
+ {
.name = "test_compliance",
.handler = riscv_test_compliance,
.mode = COMMAND_EXEC,
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 2714d9b..87dc373 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -152,6 +152,9 @@ typedef struct {
int (*test_compliance)(struct target *target);
+ int (*read_memory)(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment);
+
/* How many harts are attached to the DM that this target is attached to? */
int (*hart_count)(struct target *target);
unsigned (*data_bits)(struct target *target);
diff --git a/src/target/target.c b/src/target/target.c
index ad33fa4..3395b2a 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -3184,7 +3184,7 @@ COMMAND_HANDLER(handle_step_command)
void target_handle_md_output(struct command_invocation *cmd,
struct target *target, target_addr_t address, unsigned size,
- unsigned count, const uint8_t *buffer)
+ unsigned count, const uint8_t *buffer, bool include_address)
{
const unsigned line_bytecnt = 32;
unsigned line_modulo = line_bytecnt / size;
@@ -3213,7 +3213,7 @@ void target_handle_md_output(struct command_invocation *cmd,
}
for (unsigned i = 0; i < count; i++) {
- if (i % line_modulo == 0) {
+ if (include_address && (i % line_modulo == 0)) {
output_len += snprintf(output + output_len,
sizeof(output) - output_len,
TARGET_ADDR_FMT ": ",
@@ -3297,7 +3297,8 @@ COMMAND_HANDLER(handle_md_command)
struct target *target = get_current_target(CMD_CTX);
int retval = fn(target, address, size, count, buffer);
if (ERROR_OK == retval)
- target_handle_md_output(CMD, target, address, size, count, buffer);
+ target_handle_md_output(CMD, target, address, size, count, buffer,
+ true);
free(buffer);
diff --git a/src/target/target.h b/src/target/target.h
index 5744000..b6f8d5d 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -753,7 +753,7 @@ void target_handle_event(struct target *t, enum target_event e);
void target_handle_md_output(struct command_invocation *cmd,
struct target *target, target_addr_t address, unsigned size,
- unsigned count, const uint8_t *buffer);
+ unsigned count, const uint8_t *buffer, bool include_address);
#define ERROR_TARGET_INVALID (-300)
#define ERROR_TARGET_INIT_FAILED (-301)