@@ -3086,32 +3086,28 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
30863086 virtual , physical );
30873087}
30883088
3089+ static int check_virt_memory_access (struct target * target , target_addr_t address ,
3090+ uint32_t size , uint32_t count , bool is_write )
3091+ {
3092+ const bool is_misaligned = address % size != 0 ;
3093+ // TODO: This assumes that size of each page is 4 KiB, which is not necessarily the case.
3094+ const bool crosses_page_boundary = RISCV_PGBASE (address + size * count - 1 ) != RISCV_PGBASE (address );
3095+ if (is_misaligned && crosses_page_boundary ) {
3096+ LOG_TARGET_ERROR (target , "Mis-aligned memory %s (address=0x%" TARGET_PRIxADDR ", size=%d, count=%d)"
3097+ " would access an element across page boundary. This is not supported." ,
3098+ is_write ? "write" : "read" , address , size , count );
3099+ return ERROR_FAIL ;
3100+ }
3101+ return ERROR_OK ;
3102+ }
3103+
30893104static int riscv_read_phys_memory (struct target * target , target_addr_t phys_address ,
30903105 uint32_t size , uint32_t count , uint8_t * buffer )
30913106{
30923107 RISCV_INFO (r );
30933108 return r -> read_memory (target , phys_address , size , count , buffer , size );
30943109}
30953110
3096- static int riscv_read_memory (struct target * target , target_addr_t address ,
3097- uint32_t size , uint32_t count , uint8_t * buffer )
3098- {
3099- if (count == 0 ) {
3100- LOG_TARGET_WARNING (target , "0-length read from 0x%" TARGET_PRIxADDR , address );
3101- return ERROR_OK ;
3102- }
3103-
3104- target_addr_t physical_addr ;
3105- int result = target -> type -> virt2phys (target , address , & physical_addr );
3106- if (result != ERROR_OK ) {
3107- LOG_TARGET_ERROR (target , "Address translation failed." );
3108- return result ;
3109- }
3110-
3111- RISCV_INFO (r );
3112- return r -> read_memory (target , physical_addr , size , count , buffer , size );
3113- }
3114-
31153111static int riscv_write_phys_memory (struct target * target , target_addr_t phys_address ,
31163112 uint32_t size , uint32_t count , const uint8_t * buffer )
31173113{
@@ -3121,25 +3117,76 @@ static int riscv_write_phys_memory(struct target *target, target_addr_t phys_add
31213117 return tt -> write_memory (target , phys_address , size , count , buffer );
31223118}
31233119
3124- static int riscv_write_memory (struct target * target , target_addr_t address ,
3125- uint32_t size , uint32_t count , const uint8_t * buffer )
3120+ static int riscv_rw_memory (struct target * target , target_addr_t address , uint32_t size ,
3121+ uint32_t count , uint8_t * read_buffer , const uint8_t * write_buffer )
31263122{
3123+ /* Exactly one of the buffers must be set, the other must be NULL */
3124+ assert (!!read_buffer != !!write_buffer );
3125+
3126+ const bool is_write = write_buffer ? true : false;
31273127 if (count == 0 ) {
3128- LOG_TARGET_WARNING (target , "0-length write to 0x%" TARGET_PRIxADDR , address );
3128+ LOG_TARGET_WARNING (target , "0-length %s 0x%" TARGET_PRIxADDR ,
3129+ is_write ? "write to" : "read from" , address );
31293130 return ERROR_OK ;
31303131 }
31313132
3132- target_addr_t physical_addr ;
3133- int result = target -> type -> virt2phys (target , address , & physical_addr );
3134- if (result != ERROR_OK ) {
3135- LOG_TARGET_ERROR (target , "Address translation failed." );
3133+ int mmu_enabled ;
3134+ int result = riscv_mmu (target , & mmu_enabled );
3135+ if (result != ERROR_OK )
31363136 return result ;
3137- }
31383137
3138+ RISCV_INFO (r );
31393139 struct target_type * tt = get_target_type (target );
31403140 if (!tt )
31413141 return ERROR_FAIL ;
3142- return tt -> write_memory (target , physical_addr , size , count , buffer );
3142+
3143+ if (!mmu_enabled ) {
3144+ if (is_write )
3145+ return tt -> write_memory (target , address , size , count , write_buffer );
3146+ else
3147+ return r -> read_memory (target , address , size , count , read_buffer , size );
3148+ }
3149+
3150+ result = check_virt_memory_access (target , address , size , count , is_write );
3151+ if (result != ERROR_OK )
3152+ return result ;
3153+
3154+ uint32_t current_count = 0 ;
3155+ while (current_count < count ) {
3156+ target_addr_t physical_addr ;
3157+ result = target -> type -> virt2phys (target , address , & physical_addr );
3158+ if (result != ERROR_OK ) {
3159+ LOG_TARGET_ERROR (target , "Address translation failed." );
3160+ return result ;
3161+ }
3162+
3163+ /* TODO: For simplicity, this algorithm assumes the worst case - the smallest possible page size,
3164+ * which is 4 KiB. The algorithm can be improved to detect the real page size, and allow to use larger
3165+ * memory transfers and avoid extra unnecessary virt2phys address translations. */
3166+ uint32_t chunk_count = MIN (count - current_count , (RISCV_PGSIZE - RISCV_PGOFFSET (address )) / size );
3167+ if (is_write )
3168+ result = tt -> write_memory (target , physical_addr , size , chunk_count , write_buffer + current_count * size );
3169+ else
3170+ result = r -> read_memory (target , physical_addr , size , chunk_count , read_buffer + current_count * size , size );
3171+ if (result != ERROR_OK )
3172+ return result ;
3173+
3174+ current_count += chunk_count ;
3175+ address += chunk_count * size ;
3176+ }
3177+ return ERROR_OK ;
3178+ }
3179+
3180+ static int riscv_read_memory (struct target * target , target_addr_t address ,
3181+ uint32_t size , uint32_t count , uint8_t * buffer )
3182+ {
3183+ return riscv_rw_memory (target , address , size , count , buffer , NULL );
3184+ }
3185+
3186+ static int riscv_write_memory (struct target * target , target_addr_t address ,
3187+ uint32_t size , uint32_t count , const uint8_t * buffer )
3188+ {
3189+ return riscv_rw_memory (target , address , size , count , NULL , buffer );
31433190}
31443191
31453192static const char * riscv_get_gdb_arch (const struct target * target )
0 commit comments