Kinetis driver checks MDM STAT register to detect secured state of MCU.
Original version often reported a blank device as secured one.
Change #3010 has not fixed all false reports.
After changes in arm_adi_v5 infrastructure secured devices was not detected
at all.
New algorithm uses multiple MDM STAT reads and counts MDM_STAT_SYSSEC and
MDM_STAT_FREADY bits. Both secured MCU and MCU locked-up in RESET/WDOG loop
are detected reliably.
Detection is run in both kx.cfg and klx.cfg from examine-start event,
not examine-end as before. Event is configured only for non hla adapter.
Minor fix in klx.cfg: commented out adapter_khz 24000 in reset-init.
Such frequency is not supported in VLPR CPU mode and with JTAG.
Change-Id: I2ec2b68c45bde9898159cd15fbdcbcfa538c41d9
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3547
Tested-by: jenkins
Reviewed-by: Steven Stallion <stallion@squareup.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
#define MDM_REG_STAT 0x00
#define MDM_REG_CTRL 0x04
#define MDM_REG_ID 0xfc
#define MDM_REG_STAT 0x00
#define MDM_REG_CTRL 0x04
#define MDM_REG_ID 0xfc
int retval;
LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value);
int retval;
LOG_DEBUG("MDM_REG[0x%02x] <- %08" PRIX32, reg, value);
- retval = dap_queue_ap_write(dap_ap(dap, 1), reg, value);
+ retval = dap_queue_ap_write(dap_ap(dap, MDM_AP), reg, value);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a write request");
return retval;
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a write request");
return retval;
- retval = dap_queue_ap_read(dap_ap(dap, 1), reg, result);
+ retval = dap_queue_ap_read(dap_ap(dap, MDM_AP), reg, result);
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a read request");
return retval;
if (retval != ERROR_OK) {
LOG_DEBUG("MDM: failed to queue a read request");
return retval;
retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read ID register");
retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read ID register");
+ if (val == 0)
+ return ERROR_OK;
+
bool found = false;
for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) {
if (val == kinetis_known_mdm_ids[i]) {
bool found = false;
for (size_t i = 0; i < ARRAY_SIZE(kinetis_known_mdm_ids); i++) {
if (val == kinetis_known_mdm_ids[i]) {
if (!found)
LOG_WARNING("MDM: unknown ID %08" PRIX32, val);
if (!found)
LOG_WARNING("MDM: unknown ID %08" PRIX32, val);
- /*
- * ... Read the MDM-AP status register until the Flash Ready bit sets...
- */
- retval = kinetis_mdm_poll_register(dap, MDM_REG_STAT,
- MDM_STAT_FREADY,
- MDM_STAT_FREADY);
- if (retval != ERROR_OK) {
- LOG_ERROR("MDM: flash ready timeout");
- goto fail;
- }
-
/*
* ... Read the System Security bit to determine if security is enabled.
* If System Security = 0, then proceed. If System Security = 1, then
/*
* ... Read the System Security bit to determine if security is enabled.
* If System Security = 0, then proceed. If System Security = 1, then
retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read MDM_REG_STAT");
retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val);
if (retval != ERROR_OK) {
LOG_ERROR("MDM: failed to read MDM_REG_STAT");
- if ((val & (MDM_STAT_SYSSEC | MDM_STAT_CORE_HALTED)) == MDM_STAT_SYSSEC) {
- LOG_WARNING("MDM: Secured MCU state detected however it may be a false alarm");
- LOG_WARNING("MDM: Halting target to detect secured state reliably");
+ /*
+ * System Security bit is also active for short time during reset.
+ * If a MCU has blank flash and runs in RESET/WDOG loop,
+ * System Security bit is active most of time!
+ * We should observe Flash Ready bit and read status several times
+ * to avoid false detection of secured MCU
+ */
+ int secured_score = 0, flash_not_ready_score = 0;
- retval = target_halt(target);
- if (retval == ERROR_OK)
- retval = target_wait_state(target, TARGET_HALTED, 100);
+ if ((val & (MDM_STAT_SYSSEC | MDM_STAT_FREADY)) != MDM_STAT_FREADY) {
+ uint32_t stats[32];
+ int i;
- if (retval != ERROR_OK) {
- LOG_WARNING("MDM: Target not halted, trying reset halt");
- target->reset_halt = true;
- target->type->assert_reset(target);
- target->type->deassert_reset(target);
+ for (i = 0; i < 32; i++) {
+ stats[i] = MDM_STAT_FREADY;
+ dap_queue_ap_read(dap_ap(dap, MDM_AP), MDM_REG_STAT, &stats[i]);
-
- /* re-read status */
- retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val);
if (retval != ERROR_OK) {
if (retval != ERROR_OK) {
- LOG_ERROR("MDM: failed to read MDM_REG_STAT");
- goto fail;
+ LOG_DEBUG("MDM: dap_run failed when validating secured state");
+ return ERROR_OK;
+ }
+ for (i = 0; i < 32; i++) {
+ if (stats[i] & MDM_STAT_SYSSEC)
+ secured_score++;
+ if (!(stats[i] & MDM_STAT_FREADY))
+ flash_not_ready_score++;
- if (val & MDM_STAT_SYSSEC) {
+ if (flash_not_ready_score <= 8 && secured_score > 24) {
jtag_poll_set_enabled(false);
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
jtag_poll_set_enabled(false);
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****");
LOG_WARNING("**** ****");
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
LOG_WARNING("**** command, power cycle the MCU and restart OpenOCD. ****");
LOG_WARNING("**** ****");
LOG_WARNING("*********** ATTENTION! ATTENTION! ATTENTION! ATTENTION! **********");
+
+ } else if (flash_not_ready_score > 24) {
+ jtag_poll_set_enabled(false);
+ LOG_WARNING("**** Your Kinetis MCU is probably locked-up in RESET/WDOG loop. ****");
+ LOG_WARNING("**** Common reason is a blank flash (at least a reset vector). ****");
+ LOG_WARNING("**** Issue 'kinetis mdm halt' command or if SRST is connected ****");
+ LOG_WARNING("**** and configured, use 'reset halt' ****");
+ LOG_WARNING("**** If MCU cannot be halted, it is likely secured and running ****");
+ LOG_WARNING("**** in RESET/WDOG loop. Issue 'kinetis mdm mass_erase' ****");
+
} else {
LOG_INFO("MDM: Chip is unsecured. Continuing.");
jtag_poll_set_enabled(true);
}
return ERROR_OK;
} else {
LOG_INFO("MDM: Chip is unsecured. Continuing.");
jtag_poll_set_enabled(true);
}
return ERROR_OK;
-
-fail:
- LOG_ERROR("MDM: Failed to check security status of the MCU. Cannot proceed further");
- jtag_poll_set_enabled(false);
- return retval;
}
FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
}
FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
-# It is important that "kinetis mdm check_security" is called for
-# 'examine-end' event and not 'eximine-start'. Calling it in 'examine-start'
-# causes "kinetis mdm check_security" to fail the first time openocd
-# calls it when it tries to connect after the CPU has been power-cycled.
-$_CHIPNAME.cpu configure -event examine-end {
- kinetis mdm check_security
-}
-
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash
reset_config srst_nogate
if {![using_hla]} {
reset_config srst_nogate
if {![using_hla]} {
+ # Detect secured MCU or boot lock-up in RESET/WDOG loop
+ $_CHIPNAME.cpu configure -event examine-start {
+ kinetis mdm check_security
+ }
+
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
}
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
}
-$_TARGETNAME configure -event reset-init {
- # Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual
- # specifies up to 24MHz for run mode; Table 17 of Sub-Family Data
- # Sheet rev4 lists 25MHz as the maximum frequency.
- adapter_khz 24000
-}
+# Table 5-1. Clock Summary of KL25 Sub-Family Reference Manual
+# specifies up to 24MHz for run mode; Table 17 of Sub-Family Data
+# Sheet rev4 lists 25MHz as the maximum frequency.
+# Uncoment only if VLPR mode is not used
+#$_TARGETNAME configure -event reset-init {
+# adapter_khz 24000
+#}
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -chain-position $_CHIPNAME.cpu
-# It is important that "kinetis mdm check_security" is called for
-# 'examine-end' event and not 'eximine-start'. Calling it in 'examine-start'
-# causes "kinetis mdm check_security" to fail the first time openocd
-# calls it when it tries to connect after the CPU has been power-cycled.
-$_CHIPNAME.cpu configure -event examine-end {
- kinetis mdm check_security
-}
-
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash
reset_config srst_nogate
if {![using_hla]} {
reset_config srst_nogate
if {![using_hla]} {
+ # Detect secured MCU or boot lock-up in RESET/WDOG loop
+ $_CHIPNAME.cpu configure -event examine-start {
+ kinetis mdm check_security
+ }
+
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)