target: cortex-m: add support for armv8m caches

Cores like Cortex-M7, Cortex-M55 and Cortex-M85 can have either
D-Cache and/or I-Cache.
Using SW breakpoints in RAM requires handling these caches.

Detect the presence of cache at examine.
Detect cache state (enable/disable) at debug entry.
Take care of caches synchronization through the PoC (usually the
SRAM) while setting and removing SW breakpoints.
Add command 'cache_info' to check cache presence and size.

Change-Id: Ice637c215fe3042c8fff57edefbab1b86515ef4b
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/9077
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
Tested-by: jenkins
This commit is contained in:
Antonio Borneo
2025-08-05 12:06:22 +02:00
parent 2abf8daa80
commit 04da6e2c62
7 changed files with 454 additions and 0 deletions

View File

@@ -21,6 +21,7 @@
#include "jtag/interface.h"
#include "breakpoints.h"
#include "cortex_m.h"
#include "armv7m_cache.h"
#include "target_request.h"
#include "target_type.h"
#include "arm_adi_v5.h"
@@ -30,6 +31,7 @@
#include "arm_semihosting.h"
#include "smp.h"
#include <helper/nvp.h>
#include <helper/string_choices.h>
#include <helper/time_support.h>
#include <rtt/rtt.h>
@@ -873,6 +875,14 @@ static int cortex_m_debug_entry(struct target *target)
return retval;
}
// read caches state
uint32_t ccr = 0;
if (armv7m->armv7m_cache.info_valid) {
retval = mem_ap_read_u32(armv7m->debug_ap, CCR, &ccr);
if (retval != ERROR_OK)
return retval;
}
/* Load all registers to arm.core_cache */
if (!cortex_m->slow_register_read) {
retval = cortex_m_fast_read_all_regs(target);
@@ -926,6 +936,11 @@ static int cortex_m_debug_entry(struct target *target)
secure_state ? "Secure" : "Non-Secure",
target_state_name(target));
if (armv7m->armv7m_cache.info_valid)
LOG_TARGET_DEBUG(target, "D-Cache %s, I-Cache %s",
str_enabled_disabled(ccr & CCR_DC_MASK),
str_enabled_disabled(ccr & CCR_IC_MASK));
/* Errata 3092511 workaround
* Cortex-M7 can halt in an incorrect address when breakpoint
* and exception occurs simultaneously */
@@ -1938,12 +1953,25 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
// make sure data cache is cleaned & invalidated down to PoC
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
retval = target_write_memory(target,
breakpoint->address & 0xFFFFFFFE,
breakpoint->length, 1,
code);
if (retval != ERROR_OK)
return retval;
// update i-cache at breakpoint location
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
breakpoint->is_set = true;
}
@@ -1986,12 +2014,25 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
target_write_u32(target, comparator_list[fp_num].fpcr_address,
comparator_list[fp_num].fpcr_value);
} else {
// make sure data cache is cleaned & invalidated down to PoC
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
/* restore original instruction (kept in target endianness) */
retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE,
breakpoint->length, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
// update i-cache at breakpoint location
retval = armv7m_d_cache_flush(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
retval = armv7m_i_cache_inval(target, breakpoint->address, breakpoint->length);
if (retval != ERROR_OK)
return retval;
}
breakpoint->is_set = false;
@@ -2906,6 +2947,12 @@ int cortex_m_examine(struct target *target)
LOG_TARGET_INFO(target, "target has %d breakpoints, %d watchpoints",
cortex_m->fp_num_code,
cortex_m->dwt_num_comp);
retval = armv7m_identify_cache(target);
if (retval != ERROR_OK) {
LOG_ERROR("Cannot detect cache");
return retval;
}
}
return ERROR_OK;
@@ -3238,6 +3285,16 @@ COMMAND_HANDLER(handle_cortex_m_reset_config_command)
return ERROR_OK;
}
COMMAND_HANDLER(handle_cortex_m_cache_info_command)
{
if (CMD_ARGC)
return ERROR_COMMAND_SYNTAX_ERROR;
struct target *target = get_current_target(CMD_CTX);
return armv7m_handle_cache_info_command(CMD, target);
}
static const struct command_registration cortex_m_exec_command_handlers[] = {
{
.name = "maskisr",
@@ -3260,6 +3317,13 @@ static const struct command_registration cortex_m_exec_command_handlers[] = {
.help = "configure software reset handling",
.usage = "['sysresetreq'|'vectreset']",
},
{
.name = "cache_info",
.handler = handle_cortex_m_cache_info_command,
.mode = COMMAND_EXEC,
.help = "display information about target caches",
.usage = "",
},
{
.chain = smp_command_handlers,
},