@@ -3061,6 +3061,27 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
30613061 virtual , physical );
30623062}
30633063
3064+ static int check_access_request (struct target * target , target_addr_t address ,
3065+ uint32_t size , uint32_t count , bool is_write )
3066+ {
3067+ const bool is_misaligned = address % size != 0 ;
3068+ // TODO: This assumes that size of each page is 4 KiB, which is not necessarily the case.
3069+ const bool crosses_page_boundary = RISCV_PGBASE (address + size * count - 1 ) != RISCV_PGBASE (address );
3070+ if (is_misaligned && crosses_page_boundary ) {
3071+ int mmu_enabled ;
3072+ int result = riscv_mmu (target , & mmu_enabled );
3073+ if (result != ERROR_OK )
3074+ return result ;
3075+ if (mmu_enabled ) {
3076+ LOG_TARGET_ERROR (target , "Mis-aligned memory %s (address=0x%" TARGET_PRIxADDR ", size=%d, count=%d)"
3077+ " would access an element across page boundary. This is not supported." ,
3078+ is_write ? "write" : "read" , address , size , count );
3079+ return ERROR_FAIL ;
3080+ }
3081+ }
3082+ return ERROR_OK ;
3083+ }
3084+
30643085static int riscv_read_phys_memory (struct target * target , target_addr_t phys_address ,
30653086 uint32_t size , uint32_t count , uint8_t * buffer )
30663087{
@@ -3076,15 +3097,32 @@ static int riscv_read_memory(struct target *target, target_addr_t address,
30763097 return ERROR_OK ;
30773098 }
30783099
3079- target_addr_t physical_addr ;
3080- int result = target -> type -> virt2phys (target , address , & physical_addr );
3081- if (result != ERROR_OK ) {
3082- LOG_TARGET_ERROR (target , "Address translation failed." );
3100+ int result = check_access_request (target , address , size , count , false);
3101+ if (result != ERROR_OK )
30833102 return result ;
3084- }
30853103
30863104 RISCV_INFO (r );
3087- return r -> read_memory (target , physical_addr , size , count , buffer , size );
3105+ uint32_t current_count = 0 ;
3106+ while (current_count < count ) {
3107+ target_addr_t physical_addr ;
3108+ result = target -> type -> virt2phys (target , address , & physical_addr );
3109+ if (result != ERROR_OK ) {
3110+ LOG_TARGET_ERROR (target , "Address translation failed." );
3111+ return result ;
3112+ }
3113+
3114+ /* TODO: For simplicity, this algorithm assumes the worst case - the smallest possible page size,
3115+ * which is 4 KiB. The algorithm can be improved to detect the real page size, and allow to use larger
3116+ * memory transfers and avoid extra unnecessary virt2phys address translations. */
3117+ uint32_t chunk_count = MIN (count - current_count , (RISCV_PGSIZE - RISCV_PGOFFSET (address )) / size );
3118+ result = r -> read_memory (target , physical_addr , size , chunk_count , buffer + current_count * size , size );
3119+ if (result != ERROR_OK )
3120+ return result ;
3121+
3122+ current_count += chunk_count ;
3123+ address += chunk_count * size ;
3124+ }
3125+ return ERROR_OK ;
30883126}
30893127
30903128static int riscv_write_phys_memory (struct target * target , target_addr_t phys_address ,
@@ -3104,17 +3142,32 @@ static int riscv_write_memory(struct target *target, target_addr_t address,
31043142 return ERROR_OK ;
31053143 }
31063144
3107- target_addr_t physical_addr ;
3108- int result = target -> type -> virt2phys (target , address , & physical_addr );
3109- if (result != ERROR_OK ) {
3110- LOG_TARGET_ERROR (target , "Address translation failed." );
3145+ int result = check_access_request (target , address , size , count , true);
3146+ if (result != ERROR_OK )
31113147 return result ;
3112- }
31133148
31143149 struct target_type * tt = get_target_type (target );
31153150 if (!tt )
31163151 return ERROR_FAIL ;
3117- return tt -> write_memory (target , physical_addr , size , count , buffer );
3152+
3153+ uint32_t current_count = 0 ;
3154+ while (current_count < count ) {
3155+ target_addr_t physical_addr ;
3156+ result = target -> type -> virt2phys (target , address , & physical_addr );
3157+ if (result != ERROR_OK ) {
3158+ LOG_TARGET_ERROR (target , "Address translation failed." );
3159+ return result ;
3160+ }
3161+
3162+ uint32_t chunk_count = MIN (count - current_count , (RISCV_PGSIZE - RISCV_PGOFFSET (address )) / size );
3163+ result = tt -> write_memory (target , physical_addr , size , chunk_count , buffer + current_count * size );
3164+ if (result != ERROR_OK )
3165+ return result ;
3166+
3167+ current_count += chunk_count ;
3168+ address += chunk_count * size ;
3169+ }
3170+ return ERROR_OK ;
31183171}
31193172
31203173static const char * riscv_get_gdb_arch (const struct target * target )
0 commit comments