diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a55653853..7d523fcbc 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -778,7 +778,7 @@ static int read_by_given_size(struct target *target, target_addr_t address, * Write one memory item using any memory access size that will work. * Utilize read-modify-write, if needed. * */ -static int write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { assert(size == 1 || size == 2 || size == 4 || size == 8); @@ -810,7 +810,7 @@ static int write_by_any_size(struct target *target, target_addr_t address, uint3 * Read one memory item using any memory access size that will work. * Read larger section of memory and pick out the required portion, if needed. * */ -static int read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) +int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { assert(size == 1 || size == 2 || size == 4 || size == 8); @@ -855,7 +855,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) } /* Read the original instruction. */ - if (read_by_any_size( + if (riscv_read_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to read original instruction at 0x%" TARGET_PRIxADDR, breakpoint->address); @@ -865,7 +865,7 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) uint8_t buff[4] = { 0 }; buf_set_u32(buff, 0, breakpoint->length * CHAR_BIT, breakpoint->length == 4 ? ebreak() : ebreak_c()); /* Write the ebreak instruction. */ - if (write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) { + if (riscv_write_by_any_size(target, breakpoint->address, breakpoint->length, buff) != ERROR_OK) { LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); return ERROR_FAIL; @@ -937,7 +937,7 @@ int riscv_remove_breakpoint(struct target *target, { if (breakpoint->type == BKPT_SOFT) { /* Write the original instruction. */ - if (write_by_any_size( + if (riscv_write_by_any_size( target, breakpoint->address, breakpoint->length, breakpoint->orig_instr) != ERROR_OK) { LOG_ERROR("Failed to restore instruction for %d-byte breakpoint at " "0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 9940cfb51..fb0af87de 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -414,4 +414,7 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval); void riscv_add_bscan_tunneled_scan(struct target *target, struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt); +int riscv_read_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); +int riscv_write_by_any_size(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer); + #endif diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 99d6c7713..3048709af 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -85,12 +85,15 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) if (result != ERROR_OK) return SEMI_ERROR; - uint8_t tmp[12]; + uint8_t tmp_buf[12]; - /* Read the current instruction, including the bracketing */ - *retval = target_read_memory(target, pc - 4, 2, 6, tmp); - if (*retval != ERROR_OK) - return SEMI_ERROR; + /* Read three uncompressed instructions: The previous, the current one (pointed to by PC) and the next one */ + for (int i = 0; i < 3; i++) { + /* Instruction memories may not support arbitrary read size. Use any size that will work. */ + *retval = riscv_read_by_any_size(target, (pc - 4) + 4 * i, 4, tmp_buf + 4 * i); + if (*retval != ERROR_OK) + return SEMI_ERROR; + } /* * The instructions that trigger a semihosting call, @@ -100,9 +103,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval) * 00100073 ebreak * 40705013 srai zero,zero,0x7 */ - uint32_t pre = target_buffer_get_u32(target, tmp); - uint32_t ebreak = target_buffer_get_u32(target, tmp + 4); - uint32_t post = target_buffer_get_u32(target, tmp + 8); + uint32_t pre = target_buffer_get_u32(target, tmp_buf); + uint32_t ebreak = target_buffer_get_u32(target, tmp_buf + 4); + uint32_t post = target_buffer_get_u32(target, tmp_buf + 8); LOG_DEBUG("check %08x %08x %08x from 0x%" PRIx64 "-4", pre, ebreak, post, pc); if (pre != 0x01f01013 || ebreak != 0x00100073 || post != 0x40705013) {