diff options
author | Gleb Gagarin <gleb@sifive.com> | 2017-08-10 14:27:11 -0700 |
---|---|---|
committer | Gleb Gagarin <gleb@sifive.com> | 2017-08-10 14:27:11 -0700 |
commit | b5692585de669dc8562fd995fda5808625d6f7a8 (patch) | |
tree | f015df52e33b2729963078f4994018da94a09909 | |
parent | b132fac804d45589e80a08bba0a08c9a82bd986b (diff) | |
download | riscv-openocd-b5692585de669dc8562fd995fda5808625d6f7a8.zip riscv-openocd-b5692585de669dc8562fd995fda5808625d6f7a8.tar.gz riscv-openocd-b5692585de669dc8562fd995fda5808625d6f7a8.tar.bz2 |
Fix reads beyond requested memory range
-rw-r--r-- | src/target/riscv/riscv-013.c | 95 |
1 files changed, 58 insertions, 37 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 99a0280..b02473e 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,49 @@ 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; + 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); + 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 +1463,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); |