From 6d5b4d709cb05e8daf0350ac507b928da95d0abb Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Sun, 17 Jul 2016 16:22:47 +0200 Subject: [PATCH] flash Kinetis: Detect RESET/WDOG loop, fix detection of secured MCU 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 Reviewed-on: http://openocd.zylin.com/3547 Tested-by: jenkins Reviewed-by: Steven Stallion Reviewed-by: Andreas Fritiofson --- src/flash/nor/kinetis.c | 80 ++++++++++++++++++++++------------------- tcl/target/klx.cfg | 26 +++++++------- tcl/target/kx.cfg | 13 +++---- 3 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 0f6397581f..5c3ff0d68d 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -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]) { @@ -589,17 +594,6 @@ COMMAND_HANDLER(kinetis_check_flash_security_status) 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 @@ -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) diff --git a/tcl/target/klx.cfg b/tcl/target/klx.cfg index d2d2c28431..0df6612f70 100644 --- a/tcl/target/klx.cfg +++ b/tcl/target/klx.cfg @@ -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 +#} diff --git a/tcl/target/kx.cfg b/tcl/target/kx.cfg index ad76ac663f..b39ee3dd18 100644 --- a/tcl/target/kx.cfg +++ b/tcl/target/kx.cfg @@ -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 -- 2.30.2