summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarc Pignat <marc.pignat@hevs.ch>2010-02-16 10:08:18 +0100
committerØyvind Harboe <oyvind.harboe@zylin.com>2010-02-19 08:18:12 +0100
commit3f30563c88fcf02a8a8e671d817299adfda628ec (patch)
tree25bb5314dd6f3b5a66c0fbc7eb0a765ca26dbae0 /src
parentaa8db989b90766f4aefe72f96c1c0a37d27d1369 (diff)
downloadopenocd+libswd-3f30563c88fcf02a8a8e671d817299adfda628ec.tar.gz
openocd+libswd-3f30563c88fcf02a8a8e671d817299adfda628ec.tar.bz2
openocd+libswd-3f30563c88fcf02a8a8e671d817299adfda628ec.tar.xz
openocd+libswd-3f30563c88fcf02a8a8e671d817299adfda628ec.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/target/arm920t.c120
1 files changed, 103 insertions, 17 deletions
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;
}