diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 0660de453..2fd63b9c1 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -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 -+ - #include - - #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);