diff options
author | Palmer Dabbelt <palmer@dabbelt.com> | 2017-08-10 18:13:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-10 18:13:13 -0700 |
commit | 96eb73c83e24e1a448392a52236811f3711437e3 (patch) | |
tree | e29c1e3c15e4139b509ca61d2b82216d02d09e04 | |
parent | b132fac804d45589e80a08bba0a08c9a82bd986b (diff) | |
parent | 39b01259fa04634e714d7c1a2803ef64ba68644e (diff) | |
download | riscv-openocd-96eb73c83e24e1a448392a52236811f3711437e3.zip riscv-openocd-96eb73c83e24e1a448392a52236811f3711437e3.tar.gz riscv-openocd-96eb73c83e24e1a448392a52236811f3711437e3.tar.bz2 |
Merge pull request #90 from riscv/FE_402_fix
Fix reads beyond requested memory range
-rw-r--r-- | src/target/riscv/riscv-013.c | 97 |
1 files changed, 60 insertions, 37 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 99a0280..747488e 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1354,8 +1354,9 @@ static int read_memory(struct target *target, target_addr_t address, riscv_addr_t fin_addr = address + (count * size); riscv_addr_t prev_addr = ((riscv_addr_t) address) - size; bool first = true; - LOG_DEBUG("writing until final address 0x%" PRIx64, fin_addr); - while (count > 1 && (cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { + bool this_is_last_read = false; + LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); + while (count > 1 && (cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr - size) { LOG_DEBUG("transferring burst starting at address 0x%" TARGET_PRIxADDR " (previous burst was 0x%" TARGET_PRIxADDR ")", cur_addr, prev_addr); @@ -1372,11 +1373,23 @@ static int read_memory(struct target *target, target_addr_t address, size_t reads = 0; size_t rereads = reads; for (riscv_addr_t i = start; i < count; ++i) { - size_t index = - riscv_batch_add_dmi_read( - batch, - riscv013_debug_buffer_register(target, r_data)); - assert(index == reads); + + if (i == count - 1) { + // don't do actual read in this batch, + // we will do it later after we disable autoexec + // + // this is done to avoid reading more memory than requested + // which in some special cases(like reading stack located + // at the very top of RAM) may cause an exception + this_is_last_read = true; + } else { + size_t const index = + riscv_batch_add_dmi_read( + batch, + riscv013_debug_buffer_register(target, r_data)); + assert(index == reads); + } + reads++; if (riscv_batch_full(batch)) break; @@ -1384,13 +1397,51 @@ static int read_memory(struct target *target, target_addr_t address, riscv_batch_run(batch); + // Note that if the scan resulted in a Busy DMI response, it + // is this read to abstractcs that will cause the dmi_busy_delay + // to be incremented if necessary. The loop condition above + // catches the case where no writes went through at all. + + bool retry_batch_transaction = false; + uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); + while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) + abstractcs = dmi_read(target, DMI_ABSTRACTCS); + info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + switch (info->cmderr) { + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory write"); + break; + case CMDERR_BUSY: + LOG_DEBUG("memory write resulted in busy response"); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + retry_batch_transaction = true; + riscv_batch_free(batch); + break; + default: + LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_set_autoexec(target, d_data, 0); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + return ERROR_FAIL; + } + if (retry_batch_transaction) continue; + for (size_t i = start; i < start + reads; ++i) { riscv_addr_t offset = size*i; riscv_addr_t t_addr = address + offset; uint8_t *t_buffer = buffer + offset; - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - value = get_field(dmi_out, DTM_DMI_DATA); + if (this_is_last_read && i == start + reads - 1) { + riscv013_set_autoexec(target, d_data, 0); + value = riscv_program_read_ram(&program, r_data); + } else { + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); + value = get_field(dmi_out, DTM_DMI_DATA); + } + rereads++; switch (size) { @@ -1414,35 +1465,7 @@ static int read_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08lx] reads 0x%08lx", (long)t_addr, (long)value); } - riscv_batch_free(batch); - - // Note that if the scan resulted in a Busy DMI response, it - // is this read to abstractcs that will cause the dmi_busy_delay - // to be incremented if necessary. The loop condition above - // catches the case where no writes went through at all. - - uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); - while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) - abstractcs = dmi_read(target, DMI_ABSTRACTCS); - info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory write"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory write resulted in busy response"); - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - break; - default: - LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - riscv013_clear_abstract_error(target); - return ERROR_FAIL; - } } riscv013_set_autoexec(target, d_data, 0); |