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
This commit is contained in:
Tim Newsome 2020-08-18 11:01:41 -07:00 committed by GitHub
parent c1c88dccee
commit 53ec10b61d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 188 additions and 86 deletions

View File

@ -9659,6 +9659,12 @@ indicates the first custom register, whose abstract command number is 0xc000.
This command must be executed before `init`. This command must be executed before `init`.
@end deffn @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] @deffn Command {riscv set_command_timeout_sec} [seconds]
Set the wall-clock timeout (in seconds) for individual commands. The default Set the wall-clock timeout (in seconds) for individual commands. The default
should work fine for all but the slowest targets (eg. simulators). should work fine for all but the slowest targets (eg. simulators).

View File

@ -681,7 +681,8 @@ COMMAND_HANDLER(handle_flash_md_command)
retval = flash_driver_read(bank, buffer, offset, sizebytes); retval = flash_driver_read(bank, buffer, offset, sizebytes);
if (retval == ERROR_OK) 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); free(buffer);

View File

@ -2148,7 +2148,8 @@ COMMAND_HANDLER(dsp563xx_mem_command)
err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t), err = dsp563xx_read_memory(target, mem_type, address, sizeof(uint32_t),
count, buffer); count, buffer);
if (err == ERROR_OK) 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 { } else {
b = buffer; b = buffer;

View File

@ -1386,25 +1386,6 @@ static int halt(struct target *target)
return ERROR_OK; 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) static void deinit_target(struct target *target)
{ {
LOG_DEBUG("riscv_deinit_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, 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); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
cache_set32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16)); 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; 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 = { struct target_type riscv011_target = {
.name = "riscv", .name = "riscv",
@ -2300,7 +2306,6 @@ struct target_type riscv011_target = {
.assert_reset = assert_reset, .assert_reset = assert_reset,
.deassert_reset = deassert_reset, .deassert_reset = deassert_reset,
.read_memory = read_memory,
.write_memory = write_memory, .write_memory = write_memory,
.arch_state = arch_state, .arch_state = arch_state,

View File

@ -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, static int register_write_direct(struct target *target, unsigned number,
uint64_t value); uint64_t value);
static int read_memory(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);
static int write_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count, const uint8_t *buffer); 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, 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: case SPACE_DMI_RAM:
{ {
uint8_t buffer[8] = {0}; 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; return ERROR_FAIL;
*value = buffer[0] | *value = buffer[0] |
(((uint64_t) buffer[1]) << 8) | (((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->authdata_write = &riscv013_authdata_write;
generic_info->dmi_read = &dmi_read; generic_info->dmi_read = &dmi_read;
generic_info->dmi_write = &dmi_write; 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_sba_config_reg = &riscv013_test_sba_config_reg;
generic_info->test_compliance = &riscv013_test_compliance; generic_info->test_compliance = &riscv013_test_compliance;
generic_info->hart_count = &riscv013_hart_count; 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, 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" LOG_DEBUG("System Bus Access: size: %d\tcount:%d\tstart address: 0x%08"
TARGET_PRIxADDR, size, count, address); TARGET_PRIxADDR, size, count, address);
uint8_t *t_buffer = buffer; 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. * Read the requested memory using the system bus interface.
*/ */
static int read_memory_bus_v1(struct target *target, target_addr_t address, 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); RISCV013_INFO(info);
target_addr_t next_address = address; target_addr_t next_address = address;
target_addr_t end_address = address + count * size; 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) { while (next_address < end_address) {
uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1); uint32_t sbcs_write = set_field(0, DMI_SBCS_SBREADONADDR, 1);
sbcs_write |= sb_sbaccess(size); 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) if (count > 1)
sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1); sbcs_write = set_field(sbcs_write, DMI_SBCS_SBREADONDATA, count > 1);
if (dmi_write(target, DMI_SBCS, sbcs_write) != ERROR_OK) 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. * aamsize fields in the memory access abstract command.
*/ */
static int read_memory_abstract(struct target *target, target_addr_t address, 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; int result = ERROR_OK;
LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, 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. * even if cmderr=busy is encountered.
*/ */
static int read_memory_progbuf_inner(struct target *target, target_addr_t address, 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); 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); result = register_write_direct(target, GDB_REGNO_S0, address);
if (result != ERROR_OK) if (result != ERROR_OK)
return result; 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, uint32_t command = access_register_command(target, GDB_REGNO_S1,
riscv_xlen(target), riscv_xlen(target),
AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); 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 /* read_addr is the next address that the hart will read from, which is the
* value in s0. */ * value in s0. */
riscv_addr_t read_addr = address + 2 * size; unsigned index = 2;
riscv_addr_t fin_addr = address + (count * size); while (index < count) {
while (read_addr < fin_addr) { riscv_addr_t read_addr = address + index * increment;
LOG_DEBUG("read_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr, LOG_DEBUG("i=%d, count=%d, read_addr=0x%" PRIx64, index, count, read_addr);
fin_addr);
/* The pipeline looks like this: /* The pipeline looks like this:
* memory -> s1 -> dm_data0 -> debugger * memory -> s1 -> dm_data0 -> debugger
* Right now: * 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] * 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, struct riscv_batch *batch = riscv_batch_alloc(target, 32,
info->dmi_busy_delay + info->ac_busy_delay); info->dmi_busy_delay + info->ac_busy_delay);
size_t reads = 0; unsigned reads = 0;
for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { for (unsigned j = index; j < count; j++) {
if (size > 4) if (size > 4)
riscv_batch_add_dmi_read(batch, DMI_DATA1); riscv_batch_add_dmi_read(batch, DMI_DATA1);
riscv_batch_add_dmi_read(batch, DMI_DATA0); 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; return ERROR_FAIL;
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
riscv_addr_t next_read_addr; unsigned next_index;
unsigned ignore_last = 0; unsigned ignore_last = 0;
switch (info->cmderr) { switch (info->cmderr) {
case CMDERR_NONE: case CMDERR_NONE:
LOG_DEBUG("successful (partial?) memory read"); LOG_DEBUG("successful (partial?) memory read");
next_read_addr = read_addr + reads * size; next_index = index + reads;
break; break;
case CMDERR_BUSY: case CMDERR_BUSY:
LOG_DEBUG("memory read resulted in busy response"); 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. */ /* See how far we got, clobbering dmi_data0. */
result = register_read_direct(target, &next_read_addr, if (increment == 0) {
GDB_REGNO_S0); 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) { if (result != ERROR_OK) {
riscv_batch_free(batch); riscv_batch_free(batch);
goto error; goto error;
} }
uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0; uint64_t value64 = (((uint64_t) dmi_data1) << 32) | dmi_data0;
write_to_buf(buffer + next_read_addr - 2 * size - address, value64, size); write_to_buf(buffer + (next_index - 2) * size, value64, size);
log_memory_access(next_read_addr - 2 * size, value64, size, true); log_memory_access(address + (next_index - 2) * size, value64, size, true);
/* Restore the command, and execute it. /* Restore the command, and execute it.
* Now DMI_DATA0 contains the next value just as it would if no * Now DMI_DATA0 contains the next value just as it would if no
* error had occurred. */ * error had occurred. */
dmi_write_exec(target, DMI_COMMAND, command, true); dmi_write_exec(target, DMI_COMMAND, command, true);
next_read_addr += size; next_index++;
dmi_write(target, DMI_ABSTRACTAUTO, dmi_write(target, DMI_ABSTRACTAUTO,
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); 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. */ /* Now read whatever we got out of the batch. */
dmi_status_t status = DMI_STATUS_SUCCESS; dmi_status_t status = DMI_STATUS_SUCCESS;
riscv_addr_t receive_addr = read_addr - size * 2;
unsigned read = 0; unsigned read = 0;
for (size_t i = 0; i < reads; i++) { assert(index >= 2);
assert(receive_addr < address + size * count); for (unsigned j = index - 2; j < index + reads; j++) {
if (receive_addr < address) assert(j < count);
continue; LOG_DEBUG("index=%d, reads=%d, next_index=%d, ignore_last=%d, j=%d",
if (receive_addr > next_read_addr - (3 + ignore_last) * size) index, reads, next_index, ignore_last, j);
if (j + 3 + ignore_last > next_index)
break; break;
status = riscv_batch_get_dmi_read_op(batch, read); 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); value |= riscv_batch_get_dmi_read_data(batch, read);
read++; read++;
} }
riscv_addr_t offset = receive_addr - address; riscv_addr_t offset = j * size;
write_to_buf(buffer + offset, value, size); write_to_buf(buffer + offset, value, size);
log_memory_access(receive_addr, value, size, true); log_memory_access(address + j * increment, value, size, true);
receive_addr += size;
} }
read_addr = next_read_addr; index = next_index;
riscv_batch_free(batch); 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. * Read the requested memory, silently handling memory access errors.
*/ */
static int read_memory_progbuf(struct target *target, target_addr_t address, 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) { if (riscv_xlen(target) < size * 8) {
LOG_ERROR("XLEN (%d) is too short for %d-bit memory read.", 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 /* s0 holds the next address to write to
* s1 holds the next data value to write * 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) if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (increment == 0 && register_read(target, &s2, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
/* Write the program (load, increment) */ /* Write the program (load, increment) */
struct riscv_program program; 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)) 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_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) if (riscv_program_ebreak(&program) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
if (riscv_program_write(&program) != ERROR_OK) if (riscv_program_write(&program) != ERROR_OK)
return ERROR_FAIL; 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) { if (result != ERROR_OK) {
/* The full read did not succeed, so we will try to read each word individually. */ /* 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. */ /* 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. */ /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */
target_addr_t address_i = address; target_addr_t address_i = address;
uint32_t size_i = size;
uint32_t count_i = 1; uint32_t count_i = 1;
uint8_t *buffer_i = buffer; 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 /* TODO: This is much slower than it needs to be because we end up
* writing the address to read for every word we read. */ * 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 */ /* The read of a single word failed, so we will just return 0 for that instead */
if (result != ERROR_OK) { if (result != ERROR_OK) {
LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, 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; 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; 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_S0, s0);
riscv_set_register(target, GDB_REGNO_S1, s1); riscv_set_register(target, GDB_REGNO_S1, s1);
if (increment == 0)
riscv_set_register(target, GDB_REGNO_S2, s2);
/* Restore MSTATUS */ /* Restore MSTATUS */
if (mstatus != mstatus_old) 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, 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) 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) || if ((get_field(info->sbcs, DMI_SBCS_SBACCESS8) && size == 1) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS16) && size == 2) || (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_SBACCESS64) && size == 8) ||
(get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) { (get_field(info->sbcs, DMI_SBCS_SBACCESS128) && size == 16)) {
if (get_field(info->sbcs, DMI_SBCS_SBVERSION) == 0) 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) 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)) 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, 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, .assert_reset = assert_reset,
.deassert_reset = deassert_reset, .deassert_reset = deassert_reset,
.read_memory = read_memory,
.write_memory = write_memory, .write_memory = write_memory,
.arch_state = arch_state, .arch_state = arch_state,

View File

@ -1487,12 +1487,12 @@ static int riscv_mmu(struct target *target, int *enabled)
static int riscv_address_translate(struct target *target, static int riscv_address_translate(struct target *target,
target_addr_t virtual, target_addr_t *physical) target_addr_t virtual, target_addr_t *physical)
{ {
RISCV_INFO(r);
riscv_reg_t satp_value; riscv_reg_t satp_value;
int mode; int mode;
uint64_t ppn_value; uint64_t ppn_value;
target_addr_t table_address; target_addr_t table_address;
virt2phys_info_t *info; virt2phys_info_t *info;
struct target_type *tt = get_target_type(target);
uint64_t pte; uint64_t pte;
int i; int i;
@ -1545,8 +1545,8 @@ static int riscv_address_translate(struct target *target,
(vpn << info->pte_shift); (vpn << info->pte_shift);
uint8_t buffer[8]; uint8_t buffer[8];
assert(info->pte_shift <= 3); assert(info->pte_shift <= 3);
int retval = tt->read_memory(target, pte_address, int retval = r->read_memory(target, pte_address,
4, (1 << info->pte_shift) / 4, buffer); 4, (1 << info->pte_shift) / 4, buffer, 4);
if (retval != ERROR_OK) if (retval != ERROR_OK)
return ERROR_FAIL; 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, static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address,
uint32_t size, uint32_t count, uint8_t *buffer) uint32_t size, uint32_t count, uint8_t *buffer)
{ {
RISCV_INFO(r);
if (riscv_select_current_hart(target) != ERROR_OK) if (riscv_select_current_hart(target) != ERROR_OK)
return ERROR_FAIL; return ERROR_FAIL;
struct target_type *tt = get_target_type(target); return r->read_memory(target, phys_address, size, count, buffer, size);
return tt->read_memory(target, phys_address, size, count, buffer);
} }
static int riscv_read_memory(struct target *target, target_addr_t address, 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) if (target->type->virt2phys(target, address, &physical_addr) == ERROR_OK)
address = physical_addr; address = physical_addr;
struct target_type *tt = get_target_type(target); RISCV_INFO(r);
return tt->read_memory(target, address, size, count, buffer); return r->read_memory(target, address, size, count, buffer, size);
} }
static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address,
@ -2656,7 +2656,53 @@ COMMAND_HANDLER(riscv_set_ebreaku)
return ERROR_OK; 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[] = { 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", .name = "test_compliance",
.handler = riscv_test_compliance, .handler = riscv_test_compliance,

View File

@ -152,6 +152,9 @@ typedef struct {
int (*test_compliance)(struct target *target); 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? */ /* How many harts are attached to the DM that this target is attached to? */
int (*hart_count)(struct target *target); int (*hart_count)(struct target *target);
unsigned (*data_bits)(struct target *target); unsigned (*data_bits)(struct target *target);

View File

@ -3184,7 +3184,7 @@ COMMAND_HANDLER(handle_step_command)
void target_handle_md_output(struct command_invocation *cmd, void target_handle_md_output(struct command_invocation *cmd,
struct target *target, target_addr_t address, unsigned size, 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; const unsigned line_bytecnt = 32;
unsigned line_modulo = line_bytecnt / size; 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++) { 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, output_len += snprintf(output + output_len,
sizeof(output) - output_len, sizeof(output) - output_len,
TARGET_ADDR_FMT ": ", TARGET_ADDR_FMT ": ",
@ -3297,7 +3297,8 @@ COMMAND_HANDLER(handle_md_command)
struct target *target = get_current_target(CMD_CTX); struct target *target = get_current_target(CMD_CTX);
int retval = fn(target, address, size, count, buffer); int retval = fn(target, address, size, count, buffer);
if (ERROR_OK == retval) 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); free(buffer);

View File

@ -753,7 +753,7 @@ void target_handle_event(struct target *t, enum target_event e);
void target_handle_md_output(struct command_invocation *cmd, void target_handle_md_output(struct command_invocation *cmd,
struct target *target, target_addr_t address, unsigned size, 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_INVALID (-300)
#define ERROR_TARGET_INIT_FAILED (-301) #define ERROR_TARGET_INIT_FAILED (-301)