flash/nor/kinetis: fix FCF handling
[openocd.git] / src / flash / nor / kinetis.c
index bceaf84745c6cb85c36e62c46c30e9333b773ee4..07c5eac36850fe025a36df366e4bc6603a1c0288 100644 (file)
@@ -389,7 +389,6 @@ 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;
 
 
@@ -1250,7 +1249,7 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t wcount)
 {
        struct target *target = bank->target;
-       uint32_t buffer_size = 2048;            /* Default minimum value */
+       uint32_t buffer_size;
        struct working_area *write_algorithm;
        struct working_area *source;
        struct kinetis_flash_bank *k_bank = bank->driver_priv;
@@ -1261,10 +1260,6 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
        int retval;
        uint8_t fstat;
 
-       /* Increase buffer_size if needed */
-       if (buffer_size < (target->working_area_size/2))
-               buffer_size = (target->working_area_size/2);
-
        /* allocate working area with flash programming code */
        if (target_alloc_working_area(target, sizeof(kinetis_flash_write_code),
                        &write_algorithm) != ERROR_OK) {
@@ -1277,16 +1272,19 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                return retval;
 
-       /* memory buffer */
-       while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
-               buffer_size /= 4;
-               if (buffer_size <= 256) {
-                       /* free working area, write algorithm already allocated */
-                       target_free_working_area(target, write_algorithm);
+       /* memory buffer, size *must* be multiple of word */
+       buffer_size = target_get_working_area_avail(target) & ~(sizeof(uint32_t) - 1);
+       if (buffer_size < 256) {
+               LOG_WARNING("large enough working area not available, can't do block memory writes");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       } else if (buffer_size > 16384) {
+               /* probably won't benefit from more than 16k ... */
+               buffer_size = 16384;
+       }
 
-                       LOG_WARNING("No large enough working area available, can't do block memory writes");
-                       return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
-               }
+       if (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
+               LOG_ERROR("allocating working area failed");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
 
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
@@ -1338,7 +1336,8 @@ static int kinetis_write_block(struct flash_bank *bank, const uint8_t *buffer,
        return retval;
 }
 
-static int kinetis_protect(struct flash_bank *bank, int set, int first, int last)
+static int kinetis_protect(struct flash_bank *bank, int set, unsigned int first,
+               unsigned int last)
 {
        if (allow_fcf_writes) {
                LOG_ERROR("Protection setting is possible with 'kinetis fcf_source protection' only!");
@@ -1350,7 +1349,7 @@ static int kinetis_protect(struct flash_bank *bank, int set, int first, int last
                return ERROR_FLASH_BANK_INVALID;
        }
 
-       for (int i = first; i < bank->num_prot_blocks && i <= last; i++)
+       for (unsigned int i = first; i < bank->num_prot_blocks && i <= last; i++)
                bank->prot_blocks[i].is_protected = set;
 
        LOG_INFO("Protection bits will be written at the next FCF sector erase or write.");
@@ -1392,7 +1391,7 @@ static int kinetis_protect_check(struct flash_bank *bank)
        }
 
        b = k_bank->protection_block;
-       for (int i = 0; i < bank->num_prot_blocks; i++) {
+       for (unsigned int i = 0; i < bank->num_prot_blocks; i++) {
                if ((fprot >> b) & 1)
                        bank->prot_blocks[i].is_protected = 0;
                else
@@ -1439,7 +1438,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
                assert(bank_iter->prot_blocks);
 
                if (k_bank->flash_class == FC_PFLASH) {
-                       for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
+                       for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) {
                                if (bank_iter->prot_blocks[i].is_protected == 1)
                                        fprot &= ~pflash_bit;
 
@@ -1447,7 +1446,7 @@ static int kinetis_fill_fcf(struct flash_bank *bank, uint8_t *fcf)
                        }
 
                } else if (k_bank->flash_class == FC_FLEX_NVM) {
-                       for (int i = 0; i < bank_iter->num_prot_blocks; i++) {
+                       for (unsigned int i = 0; i < bank_iter->num_prot_blocks; i++) {
                                if (bank_iter->prot_blocks[i].is_protected == 1)
                                        fdprot &= ~dflash_bit;
 
@@ -1616,7 +1615,8 @@ static void kinetis_invalidate_flash_cache(struct kinetis_chip *k_chip)
 }
 
 
-static int kinetis_erase(struct flash_bank *bank, int first, int last)
+static int kinetis_erase(struct flash_bank *bank, unsigned int first,
+               unsigned int last)
 {
        int result;
        struct kinetis_flash_bank *k_bank = bank->driver_priv;
@@ -1639,18 +1639,16 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
         * requested erase is PFlash or NVM and encompasses the entire
         * block.  Should be quicker.
         */
-       for (int i = first; i <= last; i++) {
+       for (unsigned int i = first; i <= last; i++) {
                /* set command and sector address */
                result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTERASE, k_bank->prog_base + bank->sectors[i].offset,
                                0, 0, 0, 0,  0, 0, 0, 0,  NULL);
 
                if (result != ERROR_OK) {
-                       LOG_WARNING("erase sector %d failed", i);
+                       LOG_WARNING("erase sector %u failed", i);
                        return ERROR_FLASH_OPERATION_FAILED;
                }
 
-               bank->sectors[i].is_erased = 1;
-
                if (k_bank->prog_base == 0
                        && bank->sectors[i].offset <= FCF_ADDRESS
                        && bank->sectors[i].offset + bank->sectors[i].size > FCF_ADDRESS + FCF_SIZE) {
@@ -1664,7 +1662,8 @@ static int kinetis_erase(struct flash_bank *bank, int first, int last)
                                result = kinetis_write_inner(bank, fcf_buffer, FCF_ADDRESS, FCF_SIZE);
                                if (result != ERROR_OK)
                                        LOG_WARNING("Flash Configuration Field write failed");
-                               bank->sectors[i].is_erased = 0;
+                               else
+                                       LOG_DEBUG("Generated FCF written");
                        }
                }
        }
@@ -1793,6 +1792,8 @@ static int kinetis_write_sections(struct flash_bank *bank, const uint8_t *buffer
                buffer += size;
                offset += size;
                count -= size;
+
+               keep_alive();
        }
 
        free(buffer_aligned);
@@ -1885,6 +1886,8 @@ static int kinetis_write_inner(struct flash_bank *bank, const uint8_t *buffer,
                                buffer += 4;
                                offset += 4;
                                words_remaining--;
+
+                               keep_alive();
                        }
                }
                free(new_buffer);
@@ -1904,6 +1907,7 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
        int result;
        bool set_fcf = false;
        bool fcf_in_data_valid = false;
+       bool fcf_differs = false;
        int sect = 0;
        struct kinetis_flash_bank *k_bank = bank->driver_priv;
        struct kinetis_chip *k_chip = k_bank->k_chip;
@@ -1936,31 +1940,45 @@ static int kinetis_write(struct flash_bank *bank, const uint8_t *buffer,
                                         && 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 (memcmp(fcf_in_data, fcf_buffer, 8)) {
+                               fcf_differs = true;
+                               LOG_INFO("Setting of backdoor key is not supported in mode 'kinetis fcf_source protection'.");
+                       }
+                       if (memcmp(fcf_in_data + FCF_FPROT, fcf_buffer + FCF_FPROT, 4)) {
+                               fcf_differs = true;
+                               LOG_INFO("Flash protection requested in the 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.");
+                               fcf_differs = true;
+                               LOG_INFO("Data flash protection requested in the 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("Device security requested in the programmed file! Write denied.");
+                       } else if (fcf_in_data[FCF_FSEC] != fcf_buffer[FCF_FSEC]) {
+                               fcf_differs = true;
                                LOG_INFO("Strange unsecure mode 0x%02" PRIx8
-                                        "requested in programmed file!",
-                                        fcf_in_data[FCF_FSEC]);
+                                       " requested in the programmed file, set FSEC = 0x%02" PRIx8
+                                       " in the startup code!",
+                                       fcf_in_data[FCF_FSEC], fcf_buffer[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[FCF_FOPT] != fcf_buffer[FCF_FOPT]) {
+                               fcf_differs = true;
+                               LOG_INFO("FOPT requested in the programmed file differs from current setting, set 'kinetis fopt 0x%02"
+                                       PRIx8 "'.", fcf_in_data[FCF_FOPT]);
+                       }
+
+                       /* If the device has ECC flash, then we cannot re-program FCF */
+                       if (fcf_differs) {
+                               if (k_chip->flash_support & FS_ECC) {
+                                       fcf_in_data_valid = false;
+                                       LOG_INFO("Cannot re-program FCF. Expect verify errors at FCF (0x400-0x40f).");
+                               } else {
+                                       LOG_INFO("Trying to re-program FCF.");
+                                       if (!(k_chip->flash_support & FS_PROGRAM_LONGWORD))
+                                               LOG_INFO("Flash re-programming may fail on this device!");
+                               }
                        }
-                       if (!fcf_in_data_valid)
-                               LOG_INFO("Expect verify errors at FCF (0x408-0x40f).");
                }
        }
 
@@ -2685,7 +2703,7 @@ static int kinetis_probe(struct flash_bank *bank)
 
                if (bank->size > limit) {
                        bank->size = limit;
-                       LOG_DEBUG("FlexNVM bank %d limited to 0x%08" PRIx32 " due to active EEPROM backup",
+                       LOG_DEBUG("FlexNVM bank %u limited to 0x%08" PRIx32 " due to active EEPROM backup",
                                k_bank->bank_number, limit);
                }
 
@@ -2694,7 +2712,7 @@ static int kinetis_probe(struct flash_bank *bank)
                         k_bank->bank_number, size_k, k_bank->prog_base, k_bank->sector_size);
 
        } else {
-               LOG_ERROR("Cannot determine parameters for bank %d, only %d banks on device",
+               LOG_ERROR("Cannot determine parameters for bank %u, only %u banks on device",
                                k_bank->bank_number, num_blocks);
                return ERROR_FLASH_BANK_INVALID;
        }
@@ -2728,7 +2746,7 @@ static int kinetis_probe(struct flash_bank *bank)
        }
 
        if (k_bank->sector_size == 0) {
-               LOG_ERROR("Unknown sector size for bank %d", bank->bank_number);
+               LOG_ERROR("Unknown sector size for bank %u", bank->bank_number);
                return ERROR_FLASH_BANK_INVALID;
        }
 
@@ -2823,7 +2841,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
 
                if (block_dirty) {
                        /* the whole bank is not erased, check sector-by-sector */
-                       for (int i = 0; i < bank->num_sectors; i++) {
+                       for (unsigned int i = 0; i < bank->num_sectors; i++) {
                                /* normal margin */
                                result = kinetis_ftfx_command(bank->target, FTFx_CMD_SECTSTAT,
                                                k_bank->prog_base + bank->sectors[i].offset,
@@ -2839,7 +2857,7 @@ static int kinetis_blank_check(struct flash_bank *bank)
                        }
                } else {
                        /* the whole bank is erased, update all sectors */
-                       for (int i = 0; i < bank->num_sectors; i++)
+                       for (unsigned int i = 0; i < bank->num_sectors; i++)
                                bank->sectors[i].is_erased = 1;
                }
        } else {
@@ -3030,7 +3048,6 @@ COMMAND_HANDLER(kinetis_fopt_handler)
 
        if (CMD_ARGC == 1) {
                fcf_fopt = (uint8_t)strtoul(CMD_ARGV[0], NULL, 0);
-               fcf_fopt_configured = true;
        } else {
                command_print(CMD, "FCF_FOPT 0x%02" PRIx8, fcf_fopt);
        }

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)