diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 59717fd14..89ceb345f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -3071,20 +3071,38 @@ static int riscv_read_phys_memory(struct target *target, target_addr_t phys_addr static int riscv_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { + uint32_t current_count = 0; + if (count == 0) { LOG_TARGET_WARNING(target, "0-length read from 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } - target_addr_t physical_addr; - int result = target->type->virt2phys(target, address, &physical_addr); - if (result != ERROR_OK) { - LOG_TARGET_ERROR(target, "Address translation failed."); - return result; + if (address % size) { + LOG_TARGET_ERROR(target, "Address 0x%" TARGET_PRIxADDR " not align to size %d", address, size); + return ERROR_FAIL; } - RISCV_INFO(r); - return r->read_memory(target, physical_addr, size, count, buffer, size); + while (current_count < count) { + uint32_t offset = address & (RISCV_PGSIZE - 1); + uint32_t chunk_count = MIN(count - current_count, (RISCV_PGSIZE - offset) / size); + + target_addr_t physical_addr; + int result = target->type->virt2phys(target, address, &physical_addr); + if (result != ERROR_OK) { + LOG_TARGET_ERROR(target, "Address translation failed."); + return result; + } + + RISCV_INFO(r); + result = r->read_memory(target, physical_addr, size, chunk_count, buffer + current_count * size, size); + if (result != ERROR_OK) + return result; + + current_count += chunk_count; + address += chunk_count * size; + } + return ERROR_OK; } static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, @@ -3099,22 +3117,41 @@ static int riscv_write_phys_memory(struct target *target, target_addr_t phys_add static int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { + uint32_t current_count = 0; + if (count == 0) { LOG_TARGET_WARNING(target, "0-length write to 0x%" TARGET_PRIxADDR, address); return ERROR_OK; } - target_addr_t physical_addr; - int result = target->type->virt2phys(target, address, &physical_addr); - if (result != ERROR_OK) { - LOG_TARGET_ERROR(target, "Address translation failed."); - return result; - } - struct target_type *tt = get_target_type(target); if (!tt) return ERROR_FAIL; - return tt->write_memory(target, physical_addr, size, count, buffer); + + if (address % size) { + LOG_TARGET_ERROR(target, "Address 0x%" TARGET_PRIxADDR " not align to size %d", address, size); + return ERROR_FAIL; + } + + while (current_count < count) { + uint32_t offset = address & (RISCV_PGSIZE - 1); + uint32_t chunk_count = MIN(count - current_count, (RISCV_PGSIZE - offset) / size); + + target_addr_t physical_addr; + int result = target->type->virt2phys(target, address, &physical_addr); + if (result != ERROR_OK) { + LOG_TARGET_ERROR(target, "Address translation failed."); + return result; + } + + result = tt->write_memory(target, physical_addr, size, chunk_count, buffer + current_count * size); + if (result != ERROR_OK) + return result; + + current_count += chunk_count; + address += chunk_count * size; + } + return ERROR_OK; } static const char *riscv_get_gdb_arch(const struct target *target) diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 4ac10fa76..d9a150c84 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -29,6 +29,7 @@ struct riscv_program; #define RISCV_HGATP_MODE(xlen) ((xlen) == 32 ? HGATP32_MODE : HGATP64_MODE) #define RISCV_HGATP_PPN(xlen) ((xlen) == 32 ? HGATP32_PPN : HGATP64_PPN) #define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE (1 << RISCV_PGSHIFT) #define PG_MAX_LEVEL 5