This is an automated email from Gerrit. Matthias Welwarsky ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/3032
-- gerrit commit 0e5ec36c8c8c326f02ae64076a8a105218944dcc Author: Matthias Welwarsky <[email protected]> Date: Sun Oct 18 13:46:30 2015 +0200 armv7a: add function to update i-cache after setting a soft breakpoint After updating the program code, e.g. placing a "BKPT" instruction into existing code, the instruction cache must be manually updated. This patch adds the function armv7a_di_cache_clean_inval_virt() which: - cleans the dcache at the breakpoint location to PoU - invalidates the icache - invalidates the branch predictor Note: cleaning outer caches is not required because they're beyond the PoU Change-Id: I9812afcaf5397c488aefffffbdffe5625a22de46 Signed-off-by: Matthias Welwarsky <[email protected]> diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c index ff9829f..baddb3e 100644 --- a/src/target/armv7a_cache.c +++ b/src/target/armv7a_cache.c @@ -322,6 +322,72 @@ done: return retval; } +/* I-Cache Invalidate of virtual address range + * DDI0406C says in chapter G.5.2 + * DCCMVAU to clean D-Cache to PoU, to make the change visible to the I-Cache + * ICIMVAU to invalidate the I-Cache to PoU + * BPIMVA to invalidate the changed location in the branch predictor + * + * This will work if the program change was written through the CPU, i.e. using + * the APB-AP, since it's then in the D-Cache. If the change was written through + * the AHB-AP, we will need a different sequence. + * + * AHB memory writes are like DMA, so we need to: + * - Invalidate the D-Cache location before writing the change + * - write the change + * - Invalidate the location in I-Cache + * - Invalidate the Branch Predictor + */ +int armv7a_di_cache_clean_inval_virt(struct target *target, uint32_t virt, + uint32_t size) +{ + struct armv7a_common *armv7a = target_to_armv7a(target); + struct arm_dpm *dpm = armv7a->arm.dpm; + struct armv7a_cache_common *armv7a_cache = + &armv7a->armv7a_mmu.armv7a_cache; + uint32_t linelen = armv7a_cache->iminline; + uint32_t va_line, va_end; + int retval; + + retval = armv7a_l1_i_cache_sanity_check(target); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + va_line = virt & (-linelen); + va_end = virt + size; + + while (va_line < va_end) { + /* DCCMVAU */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 11, 1), va_line); + if (retval != ERROR_OK) + goto done; + /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); + if (retval != ERROR_OK) + goto done; + /* BPIMVA */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line); + if (retval != ERROR_OK) + goto done; + va_line += linelen; + } + dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("i-cache invalidate failed"); + dpm->finish(dpm); + + return retval; +} + /* * We assume that target core was chosen correctly. It means if same data diff --git a/src/target/armv7a_cache.h b/src/target/armv7a_cache.h index a83d4db..19ad9ab 100644 --- a/src/target/armv7a_cache.h +++ b/src/target/armv7a_cache.h @@ -22,6 +22,8 @@ int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt, unsigned int size); int armv7a_l1_i_cache_inval_all(struct target *target); +int armv7a_di_cache_clean_inval_virt(struct target *target, uint32_t virt, + unsigned int size); int armv7a_cache_auto_flush_on_write(struct target *target, uint32_t virt, uint32_t size); int armv7a_cache_auto_flush_all_data(struct target *target); -- ------------------------------------------------------------------------------ _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
