From e3f3b77729a07e8c0fa036c8ec1e021773142892 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 6 Sep 2017 22:34:14 +0200 Subject: [PATCH] flash Kinetis: make FCF protection more user friendly The Flash Configuration Field on Kinetis devices requires protection because it is located in program flash space (at 0x400) and writing an improper data to it may permanently lock the device. Even an erased flash sector containing FCF engages security lock (not permanent one) on the next reset or power cycle. 'kinetis fcf_source protection' mode was introduced in the change #3562. Flash driver in this mode sets FCF immediately after sector erase to prevent unintentional security lock. To do so the driver needs to know FCF values before flash image data is actually processed. Flash protection bits are available in bank structure, FOPT can be set by 'kinetis fopt' command and securing device by FSEC is not supported. Nevertheless an inexperienced user flashed the device using an image with FCF values different from those set in OpenOCD config and concluded programming did not work as some verify errors showed. This change tries to write maximum possible from image data retaining FCF protection. Check FCF in programmed data and report if some field differs from values set by OpenOCD flash block protection and 'kinetis fopt' command. Warn user about verify errors caused by FCF protection. On devices with ECC flash (K26, K66 and KV5x) it is impossible to change already programmed FCF - it would result in an ECC error. As FCF was written just after erase in 'kinetis fcf_source protection' mode the warning issued during flash write is the only possible action. On non-ECC flash devices use cumulative flash programming to set FCF values requested in programmed image data. Use FSEC from programmed data only if it does not request a secure mode. Device can be secured only in 'kinetis fcf_source write' mode. Use FOPT from programmed data if its value was not configured in OpenOCD config by 'kinetis fopt' command. Change-Id: If65fbbd7700069f57e4ae32234dce371bff93674 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4228 Tested-by: jenkins Reviewed-by: Robert Foss Reviewed-by: Paul Fertser --- src/flash/nor/kinetis.c | 55 +++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 5c0ffbd6f6..2c2d062acd 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -287,6 +287,7 @@ struct kinetis_chip { FS_NO_CMD_BLOCKSTAT = 0x40, FS_WIDTH_256BIT = 0x80, + FS_ECC = 0x100, } flash_support; enum { @@ -388,6 +389,7 @@ static const struct kinetis_type kinetis_types_old[] = { static bool allow_fcf_writes; static uint8_t fcf_fopt = 0xff; +static bool fcf_fopt_configured; static bool create_banks; @@ -1881,9 +1883,13 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, { int result; bool set_fcf = false; + bool fcf_in_data_valid = false; int sect = 0; struct kinetis_flash_bank *k_bank = bank->driver_priv; struct kinetis_chip *k_chip = k_bank->k_chip; + uint8_t fcf_buffer[FCF_SIZE]; + uint8_t fcf_current[FCF_SIZE]; + uint8_t fcf_in_data[FCF_SIZE]; result = kinetis_check_run_mode(k_chip); if (result != ERROR_OK) @@ -1904,11 +1910,41 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } if (set_fcf) { - uint8_t fcf_buffer[FCF_SIZE]; - uint8_t fcf_current[FCF_SIZE]; - kinetis_fill_fcf(bank, fcf_buffer); + fcf_in_data_valid = offset <= FCF_ADDRESS + && offset + count >= FCF_ADDRESS + FCF_SIZE; + if (fcf_in_data_valid) { + memcpy(fcf_in_data, buffer + FCF_ADDRESS - offset, FCF_SIZE); + if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer, 4)) { + fcf_in_data_valid = false; + LOG_INFO("Flash protection requested in programmed file differs from current setting."); + } + if (fcf_in_data[FCF_FDPROT] != fcf_buffer[FCF_FDPROT]) { + fcf_in_data_valid = false; + LOG_INFO("Data flash protection requested in programmed file differs from current setting."); + } + if ((fcf_in_data[FCF_FSEC] & 3) != 2) { + fcf_in_data_valid = false; + LOG_INFO("Device security requested in programmed file!"); + } else if (k_chip->flash_support & FS_ECC + && fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) { + fcf_in_data_valid = false; + LOG_INFO("Strange unsecure mode 0x%02" PRIx8 + "requested in programmed file!", + fcf_in_data[FCF_FSEC]); + } + if ((k_chip->flash_support & FS_ECC || fcf_fopt_configured) + && fcf_in_data[FCF_FOPT] != fcf_fopt) { + fcf_in_data_valid = false; + LOG_INFO("FOPT requested in programmed file differs from current setting."); + } + if (!fcf_in_data_valid) + LOG_INFO("Expect verify errors at FCF (0x408-0x40f)."); + } + } + + if (set_fcf && !fcf_in_data_valid) { if (offset < FCF_ADDRESS) { /* write part preceding FCF */ result = kinetis_write_inner(bank, buffer, offset, FCF_ADDRESS - offset); @@ -1937,9 +1973,10 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer, } return result; - } else + } else { /* no FCF fiddling, normal write */ return kinetis_write_inner(bank, buffer, offset, count); + } } @@ -2146,7 +2183,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) k_chip->nvm_sector_size = 4<<10; k_chip->max_flash_prog_size = 1<<10; num_blocks = 4; - k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_ECC; cpu_mhz = 180; break; @@ -2300,7 +2337,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) k_chip->max_flash_prog_size = 1<<10; num_blocks = 1; maxaddr_shift = 14; - k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT; + k_chip->flash_support = FS_PROGRAM_PHRASE | FS_PROGRAM_SECTOR | FS_WIDTH_256BIT | FS_ECC; k_chip->pflash_base = 0x10000000; k_chip->progr_accel_ram = 0x18000000; cpu_mhz = 240; @@ -2959,10 +2996,12 @@ COMMAND_HANDLER(kinetis_fopt_handler) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (CMD_ARGC == 1) + if (CMD_ARGC == 1) { fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0); - else + fcf_fopt_configured = true; + } else { command_print(CMD_CTX, "FCF_FOPT 0x%02" PRIx8, fcf_fopt); + } return ERROR_OK; } -- 2.30.2