Fix block read corner cases.
Change-Id: I841f264ca881078075beaa58023dd0e0a81f3ff3
This commit is contained in:
parent
41e5272adc
commit
d6a6699f15
|
@ -517,7 +517,7 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
|
|||
* caller whether DMI was every busy during this call. */
|
||||
static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
||||
bool *dmi_busy_encountered, int dmi_op, uint32_t address,
|
||||
uint32_t data_out, int timeout_sec)
|
||||
uint32_t data_out, int timeout_sec, bool exec)
|
||||
{
|
||||
select_dmi(target);
|
||||
|
||||
|
@ -548,7 +548,7 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
|||
* stays busy, it is actually due to the previous access. */
|
||||
while (1) {
|
||||
status = dmi_scan(target, NULL, NULL, dmi_op, address, data_out,
|
||||
false);
|
||||
exec);
|
||||
if (status == DMI_STATUS_BUSY) {
|
||||
increase_dmi_busy_delay(target);
|
||||
if (dmi_busy_encountered)
|
||||
|
@ -603,10 +603,10 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
|
|||
|
||||
static int dmi_op(struct target *target, uint32_t *data_in,
|
||||
bool *dmi_busy_encountered, int dmi_op, uint32_t address,
|
||||
uint32_t data_out)
|
||||
uint32_t data_out, bool exec)
|
||||
{
|
||||
int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, dmi_op,
|
||||
address, data_out, riscv_command_timeout_sec);
|
||||
address, data_out, riscv_command_timeout_sec, exec);
|
||||
if (result == ERROR_TIMEOUT_REACHED) {
|
||||
LOG_ERROR("DMI operation didn't complete in %d seconds. The target is "
|
||||
"either really slow or broken. You could increase the "
|
||||
|
@ -619,19 +619,29 @@ static int dmi_op(struct target *target, uint32_t *data_in,
|
|||
|
||||
static int dmi_read(struct target *target, uint32_t *value, uint32_t address)
|
||||
{
|
||||
return dmi_op(target, value, NULL, DMI_OP_READ, address, 0);
|
||||
return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false);
|
||||
}
|
||||
|
||||
static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address)
|
||||
{
|
||||
return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true);
|
||||
}
|
||||
|
||||
static int dmi_write(struct target *target, uint32_t address, uint32_t value)
|
||||
{
|
||||
return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value);
|
||||
return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false);
|
||||
}
|
||||
|
||||
static int dmi_write_exec(struct target *target, uint32_t address, uint32_t value)
|
||||
{
|
||||
return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, true);
|
||||
}
|
||||
|
||||
int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
|
||||
bool authenticated, unsigned timeout_sec)
|
||||
{
|
||||
int result = dmi_op_timeout(target, dmstatus, NULL, DMI_OP_READ,
|
||||
DMI_DMSTATUS, 0, timeout_sec);
|
||||
DMI_DMSTATUS, 0, timeout_sec, false);
|
||||
if (result != ERROR_OK)
|
||||
return result;
|
||||
if (authenticated && !get_field(*dmstatus, DMI_DMSTATUS_AUTHENTICATED)) {
|
||||
|
@ -734,7 +744,7 @@ static int execute_abstract_command(struct target *target, uint32_t command)
|
|||
}
|
||||
}
|
||||
|
||||
dmi_write(target, DMI_COMMAND, command);
|
||||
dmi_write_exec(target, DMI_COMMAND, command);
|
||||
|
||||
uint32_t abstractcs = 0;
|
||||
wait_for_idle(target, &abstractcs);
|
||||
|
@ -2156,7 +2166,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
/* Read garbage from dmi_data0, which triggers another execution of the
|
||||
* program. Now dmi_data0 contains the first good result, and s1 the next
|
||||
* memory value. */
|
||||
if (dmi_read(target, NULL, DMI_DATA0) != ERROR_OK)
|
||||
if (dmi_read_exec(target, NULL, DMI_DATA0) != ERROR_OK)
|
||||
goto error;
|
||||
|
||||
/* read_addr is the next address that the hart will read from, which is the
|
||||
|
@ -2203,6 +2213,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
|
||||
|
||||
riscv_addr_t next_read_addr;
|
||||
unsigned ignore_last = 0;
|
||||
switch (info->cmderr) {
|
||||
case CMDERR_NONE:
|
||||
LOG_DEBUG("successful (partial?) memory read");
|
||||
|
@ -2211,34 +2222,6 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
case CMDERR_BUSY:
|
||||
LOG_DEBUG("memory read resulted in busy response");
|
||||
|
||||
/*
|
||||
* If you want to exercise this code path, apply the following patch to spike:
|
||||
--- a/riscv/debug_module.cc
|
||||
+++ b/riscv/debug_module.cc
|
||||
@@ -1,3 +1,5 @@
|
||||
+#include <unistd.h>
|
||||
+
|
||||
#include <cassert>
|
||||
|
||||
#include "debug_module.h"
|
||||
@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command()
|
||||
// Since the next instruction is what we will use, just use nother NOP
|
||||
// to get there.
|
||||
write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
|
||||
+
|
||||
+ if (abstractauto.autoexecdata &&
|
||||
+ program_buffer[0] == 0x83 &&
|
||||
+ program_buffer[1] == 0x24 &&
|
||||
+ program_buffer[2] == 0x04 &&
|
||||
+ program_buffer[3] == 0 &&
|
||||
+ rand() < RAND_MAX / 10) {
|
||||
+ usleep(1000000);
|
||||
+ }
|
||||
} else {
|
||||
write32(debug_abstract, 1, ebreak());
|
||||
}
|
||||
*/
|
||||
|
||||
increase_ac_busy_delay(target);
|
||||
riscv013_clear_abstract_error(target);
|
||||
|
||||
|
@ -2252,8 +2235,6 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
riscv_batch_free(batch);
|
||||
goto error;
|
||||
}
|
||||
write_to_buf(buffer + next_read_addr - 2 * size - address, dmi_data0, size);
|
||||
log_memory_access(next_read_addr - 2 * size, dmi_data0, size, true);
|
||||
|
||||
/* See how far we got, clobbering dmi_data0. */
|
||||
result = register_read_direct(target, &next_read_addr,
|
||||
|
@ -2262,14 +2243,20 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
riscv_batch_free(batch);
|
||||
goto error;
|
||||
}
|
||||
write_to_buf(buffer + next_read_addr - 2 * size - address, dmi_data0, size);
|
||||
log_memory_access(next_read_addr - 2 * size, dmi_data0, 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(target, DMI_COMMAND, command);
|
||||
dmi_write_exec(target, DMI_COMMAND, command);
|
||||
next_read_addr += size;
|
||||
|
||||
dmi_write(target, DMI_ABSTRACTAUTO,
|
||||
1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
|
||||
|
||||
ignore_last = 1;
|
||||
|
||||
break;
|
||||
default:
|
||||
LOG_DEBUG("error when reading memory, abstractcs=0x%08lx", (long)abstractcs);
|
||||
|
@ -2286,7 +2273,7 @@ static int read_memory_progbuf_inner(struct target *target, target_addr_t addres
|
|||
assert(receive_addr < address + size * count);
|
||||
if (receive_addr < address)
|
||||
continue;
|
||||
if (receive_addr >= next_read_addr)
|
||||
if (receive_addr > next_read_addr - (3 + ignore_last) * size)
|
||||
break;
|
||||
|
||||
uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i);
|
||||
|
@ -2759,7 +2746,7 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
|
|||
uint32_t abstractcs;
|
||||
bool dmi_busy_encountered;
|
||||
if (dmi_op(target, &abstractcs, &dmi_busy_encountered, DMI_OP_READ,
|
||||
DMI_ABSTRACTCS, 0) != ERROR_OK)
|
||||
DMI_ABSTRACTCS, 0, false) != ERROR_OK)
|
||||
goto error;
|
||||
while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY))
|
||||
if (dmi_read(target, &abstractcs, DMI_ABSTRACTCS) != ERROR_OK)
|
||||
|
@ -2768,7 +2755,10 @@ static int write_memory_progbuf(struct target *target, target_addr_t address,
|
|||
if (info->cmderr == CMDERR_NONE && !dmi_busy_encountered) {
|
||||
LOG_DEBUG("successful (partial?) memory write");
|
||||
} else if (info->cmderr == CMDERR_BUSY || dmi_busy_encountered) {
|
||||
LOG_DEBUG("memory write resulted in busy response");
|
||||
if (info->cmderr == CMDERR_BUSY)
|
||||
LOG_DEBUG("Memory write resulted in abstract command busy response.");
|
||||
else if (dmi_busy_encountered)
|
||||
LOG_DEBUG("Memory write resulted in DMI busy response.");
|
||||
riscv013_clear_abstract_error(target);
|
||||
increase_ac_busy_delay(target);
|
||||
|
||||
|
|
Loading…
Reference in New Issue