diff options
author | cgsfv <cgsfv@users.noreply.github.com> | 2018-08-22 13:25:27 +0200 |
---|---|---|
committer | cgsfv <cgsfv@users.noreply.github.com> | 2018-09-17 13:53:35 -0700 |
commit | 10a2823191a96911c6f12def22703f01f392f2a5 (patch) | |
tree | cd7f8ba8456531fa3691cb0722be1131018411d9 | |
parent | 933cb875a8fb6243df52208c725b1c6ebc9662e3 (diff) | |
download | riscv-openocd-10a2823191a96911c6f12def22703f01f392f2a5.zip riscv-openocd-10a2823191a96911c6f12def22703f01f392f2a5.tar.gz riscv-openocd-10a2823191a96911c6f12def22703f01f392f2a5.tar.bz2 |
Read memory words individually if burst read fails
-rw-r--r-- | src/target/riscv/riscv-013.c | 123 |
1 files changed, 79 insertions, 44 deletions
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 34ec3c6..37206ea 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2036,53 +2036,13 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. */ -static int read_memory_progbuf(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) { RISCV013_INFO(info); int result = ERROR_OK; - LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, - size, address); - - select_dmi(target); - - /* s0 holds the next address to write to - * s1 holds the next data value to write - */ - uint64_t s0, s1; - if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; - if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; - - if (execute_fence(target) != ERROR_OK) - return ERROR_FAIL; - - /* Write the program (load, increment) */ - struct riscv_program program; - riscv_program_init(&program, target); - switch (size) { - case 1: - riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 2: - riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - case 4: - riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); - break; - default: - LOG_ERROR("Unsupported size: %d", size); - return ERROR_FAIL; - } - riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - - if (riscv_program_ebreak(&program) != ERROR_OK) - return ERROR_FAIL; - riscv_program_write(&program); - /* Write address to S0, and execute buffer. */ result = register_write_direct(target, GDB_REGNO_S0, address); if (result != ERROR_OK) @@ -2210,7 +2170,7 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); break; default: - LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + LOG_DEBUG("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); riscv013_clear_abstract_error(target); riscv_batch_free(batch); result = ERROR_FAIL; @@ -2268,13 +2228,88 @@ static int read_memory_progbuf(struct target *target, target_addr_t address, write_to_buf(buffer + receive_addr - address, value, size); log_memory_access(receive_addr, value, size, true); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; error: dmi_write(target, DMI_ABSTRACTAUTO, 0); + return result; +} + +/** + * Read the requested memory, silently handling memory access errors. + */ +static int read_memory_progbuf(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + int result = ERROR_OK; + + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, + size, address); + + select_dmi(target); + + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + uint64_t s0, s1; + if (register_read(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + + /* Write the program (load, increment) */ + struct riscv_program program; + riscv_program_init(&program, target); + switch (size) { + case 1: + riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 2: + riscv_program_lhr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + case 4: + riscv_program_lwr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); + break; + default: + LOG_ERROR("Unsupported size: %d", size); + return ERROR_FAIL; + } + riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); + + if (riscv_program_ebreak(&program) != ERROR_OK) + return ERROR_FAIL; + riscv_program_write(&program); + + result = read_memory_progbuf_inner(target, address, size, count, buffer); + + /* 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. */ + /* It will make the toolchain happier, especially Eclipse Memory View as it reads ahead. */ + if (result != ERROR_OK) { + target_addr_t address_i = address; + uint32_t size_i = size; + uint32_t count_i = 1; + uint8_t* buffer_i = buffer; + + for (uint32_t i = 0; i < count; i++, address_i += size_i, buffer_i += size_i) { + result = read_memory_progbuf_inner(target, address_i, size_i, count_i, buffer_i); + + /* The read of a single word failed, so we will just return 0 for that instead */ + if (result != ERROR_OK) { + LOG_DEBUG("error reading single word of %d bytes from 0x%" TARGET_PRIxADDR, + size_i, address_i); + + uint64_t value_i = 0; + write_to_buf(buffer_i, value_i, size_i); + } + } + result = ERROR_OK; + } + riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return result; |