From 3f30563c88fcf02a8a8e671d817299adfda628ec Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Tue, 16 Feb 2010 10:08:18 +0100 Subject: atm920t : fix breakpoints and data cache handling Breakpoints did not work because the data cache was not flushed properly. As a bonus add capability to write to memory marked as read only by the MMU, which allows software breakpoints in such memory regions. --- src/target/arm920t.c | 120 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/target/arm920t.c b/src/target/arm920t.c index 3b75ca97..7cc228d0 100644 --- a/src/target/arm920t.c +++ b/src/target/arm920t.c @@ -559,34 +559,120 @@ static int arm920t_write_phys_memory(struct target *target, /** Writes a buffer, in the specified word size, with current MMU settings. */ -int arm920t_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) +int arm920t_write_memory(struct target *target, uint32_t address, + uint32_t size, uint32_t count, uint8_t *buffer) { int retval; + const uint32_t cache_mask = ~0x1f; /* cache line size : 32 byte */ + struct arm920t_common *arm920t = target_to_arm920(target); - if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) - return retval; - - /* This fn is used to write breakpoints, so we need to make sure - * that the data cache is flushed and the instruction cache is - * invalidated - */ - if (((size == 4) || (size == 2)) && (count == 1)) + /* FIX!!!! this should be cleaned up and made much more general. The + * plan is to write up and test on arm920t specifically and + * then generalize and clean up afterwards. */ + if (arm920t->armv4_5_mmu.mmu_enabled && (count == 1) && ((size==2) || (size==4))) { - struct arm920t_common *arm920t = target_to_arm920(target); + /* special case the handling of single word writes to bypass MMU + * to allow implementation of breakpoints in memory marked read only + * by MMU */ + int type; + uint32_t cb; + int domain; + uint32_t ap; + uint32_t pa; + + /* + * We need physical address and cb + */ + pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap); + if (type == -1) + { + return pa; + } if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { - LOG_DEBUG("D-Cache enabled, flush and invalidate cache line"); - /* MCR p15,0,Rd,c7,c10,2 */ - retval = arm920t_write_cp15_interpreted(target, 0xee070f5e, 0x0, address); - if (retval != ERROR_OK) - return retval; + if (cb & 0x1) + { + LOG_DEBUG("D-Cache buffered, drain write buffer"); + /* + * Buffered ? + * Drain write buffer - MCR p15,0,Rd,c7,c10,4 + */ + + retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 10, 4), 0x0, 0); + if (retval != ERROR_OK) + return retval; + } + + if (cb == 0x3) + { + /* + * Write back memory ? -> clean cache + * + * There is no way for cleaning a data cache line using + * cp15 scan chain, so copy the full cache line from + * cache to physical memory. + */ + uint8_t data[32]; + + LOG_DEBUG("D-Cache in 'write back' mode, flush cache line"); + + retval = target_read_memory(target, address & cache_mask, 1, sizeof(data), &data[0]); + if (retval != ERROR_OK) + return retval; + + retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa & cache_mask, 1, sizeof(data), &data[0]); + if (retval != ERROR_OK) + return retval; + } + + /* Cached ? */ + if (cb & 0x2) + { + /* + * Cached ? -> Invalidate data cache using MVA + * + * MCR p15,0,Rd,c7,c6,1 + */ + LOG_DEBUG("D-Cache enabled, invalidate cache line"); + + retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), 0x0, address & cache_mask); + if (retval != ERROR_OK) + return retval; + } } - if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + /* write directly to physical memory bypassing any read only MMU bits, etc. */ + retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer); + if (retval != ERROR_OK) + return retval; + } else + { + if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK) + return retval; + } + + /* If ICache is enabled, we have to invalidate affected ICache lines + * the DCache is forced to write-through, so we don't have to clean it here + */ + if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled) + { + if (count <= 1) { + /* invalidate ICache single entry with MVA + * ee070f35 mcr 15, 0, r0, cr7, cr5, {1} + */ LOG_DEBUG("I-Cache enabled, invalidating affected I-Cache line"); - retval = arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address); + retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), 0x0, address & cache_mask); + if (retval != ERROR_OK) + return retval; + } + else + { + /* invalidate ICache + * 8: ee070f15 mcr 15, 0, r0, cr7, cr5, {0} + * */ + retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0x0, 0x0); if (retval != ERROR_OK) return retval; } -- cgit v1.2.3