aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorMatthias Welwarsky <matthias@welwarsky.de>2015-10-18 13:50:58 +0200
committerPaul Fertser <fercerpav@gmail.com>2015-11-30 05:43:03 +0000
commitf24aa404ba14bb048f55752b241a6a8185f77b3f (patch)
tree25d94221865bd97d9e3d5640a91c74078bd2cffe /src/target
parent9484dd5ebfcc7f9426f8ffc37f5486cd0387bb6a (diff)
cortex_a: Update instruction cache after setting a soft breakpoint
Call armv7a_l1_d_cache_flush_virt() before writing the breakpoint, to make sure the d-cache is clean and invalid at the breakpoint location down to PoC. Call armv7a_l1_d_cache_inval_virt() after writing the breakpoint again, so that d-cache will pick up the modified code. Call armv7a_l1_i_cache_inval_virt() after writing the breakpoint to memory to make the change visible to the CPU. Change-Id: I24fc27058d99cb00d7f6002ccb623cab66b0d234 Signed-off-by: Matthias Welwarsky <matthias@welwarsky.de> Reviewed-on: http://openocd.zylin.com/3033 Reviewed-by: Paul Fertser <fercerpav@gmail.com> Tested-by: jenkins
Diffstat (limited to 'src/target')
-rw-r--r--src/target/armv7a_cache.c2
-rw-r--r--src/target/armv7a_cache.h2
-rw-r--r--src/target/cortex_a.c27
3 files changed, 30 insertions, 1 deletions
diff --git a/src/target/armv7a_cache.c b/src/target/armv7a_cache.c
index a049174c..acc388a2 100644
--- a/src/target/armv7a_cache.c
+++ b/src/target/armv7a_cache.c
@@ -152,7 +152,7 @@ int armv7a_cache_auto_flush_all_data(struct target *target)
}
-static int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
+int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
uint32_t size)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
diff --git a/src/target/armv7a_cache.h b/src/target/armv7a_cache.h
index fbd158b4..e0ebb618 100644
--- a/src/target/armv7a_cache.h
+++ b/src/target/armv7a_cache.h
@@ -21,6 +21,8 @@
int armv7a_l1_d_cache_clean_virt(struct target *target, uint32_t virt,
unsigned int size);
+int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt,
+ unsigned int size);
int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt,
unsigned int size);
int armv7a_l1_i_cache_inval_all(struct target *target);
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 39e59ae7..5268cf21 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -1509,11 +1509,25 @@ static int cortex_a_set_breakpoint(struct target *target,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
+
+ /* make sure data cache is cleaned & invalidated down to PoC */
+ if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) {
+ armv7a_cache_flush_virt(target, breakpoint->address,
+ breakpoint->length);
+ }
+
retval = target_write_memory(target,
breakpoint->address & 0xFFFFFFFE,
breakpoint->length, 1, code);
if (retval != ERROR_OK)
return retval;
+
+ /* update i-cache at breakpoint location */
+ armv7a_l1_d_cache_inval_virt(target, breakpoint->address,
+ breakpoint->length);
+ armv7a_l1_i_cache_inval_virt(target, breakpoint->address,
+ breakpoint->length);
+
breakpoint->set = 0x11; /* Any nice value but 0 */
}
@@ -1733,6 +1747,13 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
return ERROR_OK;
}
} else {
+
+ /* make sure data cache is cleaned & invalidated down to PoC */
+ if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) {
+ armv7a_cache_flush_virt(target, breakpoint->address,
+ breakpoint->length);
+ }
+
/* restore original instruction (kept in target endianness) */
if (breakpoint->length == 4) {
retval = target_write_memory(target,
@@ -1747,6 +1768,12 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
if (retval != ERROR_OK)
return retval;
}
+
+ /* update i-cache at breakpoint location */
+ armv7a_l1_d_cache_inval_virt(target, breakpoint->address,
+ breakpoint->length);
+ armv7a_l1_i_cache_inval_virt(target, breakpoint->address,
+ breakpoint->length);
}
breakpoint->set = 0;