flash Kinetis: Detect RESET/WDOG loop, fix detection of secured MCU 47/3547/4
authorTomas Vanek <vanekt@fbl.cz>
Sun, 17 Jul 2016 14:22:47 +0000 (16:22 +0200)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Sun, 14 Aug 2016 08:10:06 +0000 (09:10 +0100)
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>
src/flash/nor/kinetis.c
tcl/target/klx.cfg
tcl/target/kx.cfg

index 0f63975..5c3ff0d 100644 (file)
@@ -227,6 +227,8 @@ struct kinetis_flash_bank {
        } flash_support;
 };
 
+#define MDM_AP                 1
+
 #define MDM_REG_STAT           0x00
 #define MDM_REG_CTRL           0x04
 #define MDM_REG_ID             0xfc
@@ -261,7 +263,7 @@ static int kinetis_mdm_write_register(struct adiv5_dap *dap, unsigned reg, uint3
        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;
@@ -281,7 +283,7 @@ static int kinetis_mdm_read_register(struct adiv5_dap *dap, unsigned reg, uint32
 {
        int 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;
@@ -575,9 +577,12 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
        retval = kinetis_mdm_read_register(dap, MDM_REG_ID, &val);
        if (retval != ERROR_OK) {
                LOG_ERROR("MDM: failed to read ID register");
-               goto fail;
+               return ERROR_OK;
        }
 
+       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]) {
@@ -590,17 +595,6 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
                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
         * communication with the internals of the processor, including the
@@ -610,33 +604,40 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
        retval = kinetis_mdm_read_register(dap, MDM_REG_STAT, &val);
        if (retval != ERROR_OK) {
                LOG_ERROR("MDM: failed to read MDM_REG_STAT");
-               goto fail;
+               return ERROR_OK;
        }
 
-       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);
+               retval = dap_run(dap);
                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! **********");
@@ -648,17 +649,22 @@ COMMAND_HANDLER(kinetis_check_flash_security_status)
                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;
-
-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)
index d2d2c28..0df6612 100644 (file)
@@ -29,14 +29,6 @@ swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
 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
@@ -49,14 +41,20 @@ adapter_khz 1000
 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
 }
 
-$_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
+#}
index ad76ac6..b39ee3d 100644 (file)
@@ -33,14 +33,6 @@ swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_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
@@ -51,6 +43,11 @@ adapter_khz 1000
 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