forked from auracaster/openocd
target: cortex-m: defer cache identification on Cortex-M7 under reset
On Cortex-M7 only, several registers in System Control Space (SCS) are not accessible when the CPU is under reset, generating a bus error. This causes OpenOCD to fail examining the CPU when the board reset button is pressed or when the flag 'connect_assert_srst' is used on 'reset_config' command. Introduce a deferred identification of the cache and run it during polling and at target halted (just in case of polling disabled). Change-Id: Ia5c582ae95f825c5fb8c2dcfb320142f7ac04a9f Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/9232 Reviewed-by: Tomas Vanek <vanekt@fbl.cz> Tested-by: jenkins
This commit is contained in:
@@ -68,7 +68,7 @@ static struct armv7m_cache_size decode_ccsidr(uint32_t ccsidr)
|
||||
return size;
|
||||
}
|
||||
|
||||
int armv7m_identify_cache(struct target *target)
|
||||
static int armv7m_identify_cache_internal(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
@@ -191,6 +191,54 @@ int armv7m_identify_cache(struct target *target)
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* On Cortex-M7 only, when the CPU is kept in reset, several registers of the
|
||||
* System Control Space (SCS) are not accessible and return bus error.
|
||||
* The list of accessible registers is:
|
||||
* - 0xE000ED00
|
||||
* - 0xE000ED30
|
||||
* - 0xE000EDF0 ... 0xE000EEFC
|
||||
* - 0xE000EF40 ... 0xE000EF48
|
||||
* - 0xE000EFD0 ... 0xE000EFFC
|
||||
* This makes impossible detecting the cache during the reset.
|
||||
* Use a deferred mechanism to detect the cache during polling or when the
|
||||
* Cortex-M7 halts.
|
||||
*/
|
||||
int armv7m_identify_cache(struct target *target)
|
||||
{
|
||||
struct cortex_m_common *cortex_m = target_to_cm(target);
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
if (cache->info_valid)
|
||||
return ERROR_OK;
|
||||
|
||||
if (cortex_m->core_info->impl_part == CORTEX_M7_PARTNO
|
||||
&& cortex_m->dcb_dhcsr & S_RESET_ST) {
|
||||
cache->defer_identification = true;
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
return armv7m_identify_cache_internal(target);
|
||||
}
|
||||
|
||||
int armv7m_deferred_identify_cache(struct target *target)
|
||||
{
|
||||
struct armv7m_common *armv7m = target_to_armv7m(target);
|
||||
struct armv7m_cache_common *cache = &armv7m->armv7m_cache;
|
||||
|
||||
if (cache->info_valid || !cache->defer_identification)
|
||||
return ERROR_OK;
|
||||
|
||||
int retval = armv7m_identify_cache_internal(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
cache->defer_identification = false;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
int armv7m_d_cache_flush(struct target *target, uint32_t address,
|
||||
unsigned int length)
|
||||
{
|
||||
@@ -250,6 +298,11 @@ int armv7m_handle_cache_info_command(struct command_invocation *cmd,
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (cache->defer_identification) {
|
||||
command_print(cmd, "Cache not detected yet");
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
if (!cache->info_valid) {
|
||||
command_print(cmd, "No cache detected");
|
||||
return ERROR_OK;
|
||||
|
||||
@@ -38,6 +38,7 @@ struct armv7m_arch_cache {
|
||||
// common cache information
|
||||
struct armv7m_cache_common {
|
||||
bool info_valid;
|
||||
bool defer_identification;
|
||||
bool has_i_cache;
|
||||
bool has_d_u_cache;
|
||||
unsigned int loc; // level of coherency
|
||||
@@ -47,6 +48,7 @@ struct armv7m_cache_common {
|
||||
};
|
||||
|
||||
int armv7m_identify_cache(struct target *target);
|
||||
int armv7m_deferred_identify_cache(struct target *target);
|
||||
int armv7m_d_cache_flush(struct target *target, uint32_t address,
|
||||
unsigned int length);
|
||||
int armv7m_i_cache_inval(struct target *target, uint32_t address,
|
||||
|
||||
@@ -876,6 +876,10 @@ static int cortex_m_debug_entry(struct target *target)
|
||||
}
|
||||
|
||||
// read caches state
|
||||
retval = armv7m_deferred_identify_cache(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
uint32_t ccr = 0;
|
||||
if (armv7m->armv7m_cache.info_valid) {
|
||||
retval = mem_ap_read_u32(armv7m->debug_ap, CCR, &ccr);
|
||||
@@ -1018,6 +1022,10 @@ static int cortex_m_poll_one(struct target *target)
|
||||
|
||||
/* S_RESET_ST was expected (in a reset command). Continue processing
|
||||
* to quickly get out of TARGET_RESET state */
|
||||
} else {
|
||||
retval = armv7m_deferred_identify_cache(target);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (target->state == TARGET_RESET) {
|
||||
@@ -2952,6 +2960,18 @@ int cortex_m_examine(struct target *target)
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Use a safe value of sticky S_RESET_ST for cache detection, before
|
||||
* clearing it below.
|
||||
*/
|
||||
if (!armv7m->is_hla_target) {
|
||||
retval = armv7m_identify_cache(target);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Cannot detect cache");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't cumulate sticky S_RESET_ST at the very first read of DHCSR
|
||||
* as S_RESET_ST may indicate a reset that happened long time ago
|
||||
* (most probably the power-on reset before OpenOCD was started).
|
||||
@@ -3021,14 +3041,6 @@ 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);
|
||||
|
||||
if (!armv7m->is_hla_target) {
|
||||
retval = armv7m_identify_cache(target);
|
||||
if (retval != ERROR_OK) {
|
||||
LOG_ERROR("Cannot detect cache");
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
|
||||
Reference in New Issue
Block a user