This is an automated email from Gerrit. Antonio Borneo (borneo.anto...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/4626
-- gerrit commit 9b06c5c78a144f510770f06e113cfb7eab86e761 Author: Antonio Borneo <borneo.anto...@gmail.com> Date: Tue Jul 31 18:26:49 2018 +0200 target/cortex_a: fix R/W across non-contiguous virtual pages When read_buffer/write_buffer uses AHB access, a virt2phys translation is required to get the physical address for the AHB access. But each translation is valid only within the limits of the page. If the read_buffer/write_buffer crosses the page boundary, we cannot assume that contiguous virtual pages are mapped on contiguous physical pages, thus a new virt2phys translation is required at each cross of page boundary. Split the AHB access in pages and loop among them. For simplicity, assume the page size is fixed to 4kB, that is the minimum size allowed by armv7a. Actually, in this specific case cortex_a_virt2phys() walks through the translation tables and can provide the real page size. Add a comment to explain it for further code improvement. Change-Id: I1030fa35b3032bf23f2259c4ff820521e03fe154 Signed-off-by: Antonio Borneo <borneo.anto...@gmail.com> diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 409da15..eb32e49 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2760,24 +2760,42 @@ static int cortex_a_read_memory_ahb(struct target *target, target_addr_t address return retval; } - if (mmu_enabled) { + if (!count || !buffer) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!mmu_enabled) + return mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); + + /* + * TODO: here we are pessimistic and we use the smaller page of 4kB, but + * cortex_a_virt2phys() does a full table walk, so can return the actual + * size of page (4kB or 64kB) or section (1MB or 16Mb). + */ + while (count) { + target_addr_t page_size = 0x1000; + uint32_t current_count; + virt = address; retval = cortex_a_virt2phys(target, virt, &phys); if (retval != ERROR_OK) return retval; - LOG_DEBUG("Reading at virtual address. " - "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, - virt, phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; + current_count = (page_size - (address & (page_size - 1))) / size; + if (current_count > count) + current_count = count; - retval = mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); + LOG_DEBUG("Reading at virtual address 0x%" PRIx32 " bytes. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, + size * current_count, virt, phys); - return retval; + retval = mem_ap_read_buf(armv7a->memory_ap, buffer, size, current_count, phys); + if (retval != ERROR_OK) + return retval; + count -= current_count; + address += size * current_count; + buffer += size * current_count; + } + return ERROR_OK; } static int cortex_a_write_phys_memory(struct target *target, @@ -2854,25 +2872,42 @@ static int cortex_a_write_memory_ahb(struct target *target, target_addr_t addres return retval; } - if (mmu_enabled) { + if (!count || !buffer) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!mmu_enabled) + return mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); + + /* + * TODO: here we are pessimistic and we use the smaller page of 4kB, but + * cortex_a_virt2phys() does a full table walk, so can return the actual + * size of page (4kB or 64kB) or section (1MB or 16Mb). + */ + while (count) { + target_addr_t page_size = 0x1000; + uint32_t current_count; + virt = address; retval = cortex_a_virt2phys(target, virt, &phys); if (retval != ERROR_OK) return retval; - LOG_DEBUG("Writing to virtual address. " - "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, - virt, - phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; + current_count = (page_size - (address & (page_size - 1))) / size; + if (current_count > count) + current_count = count; - retval = mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); + LOG_DEBUG("Writing to virtual address 0x%" PRIx32 " bytes. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, + size * current_count, virt, phys); - return retval; + retval = mem_ap_write_buf(armv7a->memory_ap, buffer, size, current_count, phys); + if (retval != ERROR_OK) + return retval; + count -= current_count; + address += size * current_count; + buffer += size * current_count; + } + return ERROR_OK; } static int cortex_a_read_buffer(struct target *target, target_addr_t address, -- ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel