Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
iap_flash_intf.c
00001 /** 00002 * @file iap_flash_intf.c 00003 * @brief Implementation of flash_intf.h 00004 * 00005 * DAPLink Interface Firmware 00006 * Copyright (c) 2009-2019, ARM Limited, All Rights Reserved 00007 * SPDX-License-Identifier: Apache-2.0 00008 * 00009 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00010 * not use this file except in compliance with the License. 00011 * You may obtain a copy of the License at 00012 * 00013 * http://www.apache.org/licenses/LICENSE-2.0 00014 * 00015 * Unless required by applicable law or agreed to in writing, software 00016 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00017 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00018 * See the License for the specific language governing permissions and 00019 * limitations under the License. 00020 */ 00021 00022 #include <string.h> 00023 00024 #include "daplink.h" 00025 #include "flash_intf.h" 00026 #include "util.h" 00027 #include "flash_hal.h" 00028 #include "FlashPrg.h" 00029 #include "compiler.h" 00030 #include "crc.h" 00031 #include "info.h" 00032 00033 // Application start must be aligned to page write 00034 COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_MIN_WRITE_SIZE == 0); 00035 // Application size must be a multiple of write size 00036 COMPILER_ASSERT(DAPLINK_ROM_APP_SIZE % DAPLINK_MIN_WRITE_SIZE == 0); 00037 // Sector size must be a multiple of write size 00038 COMPILER_ASSERT(DAPLINK_SECTOR_SIZE % DAPLINK_MIN_WRITE_SIZE == 0); 00039 // Application start must be aligned to a sector erase 00040 COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_SECTOR_SIZE == 0); 00041 // Update start must be aligned to sector write 00042 COMPILER_ASSERT(DAPLINK_ROM_UPDATE_START % DAPLINK_SECTOR_SIZE == 0); 00043 // Update size must be a multiple of sector size 00044 COMPILER_ASSERT(DAPLINK_ROM_UPDATE_SIZE % DAPLINK_SECTOR_SIZE == 0); 00045 00046 typedef enum { 00047 STATE_CLOSED, 00048 STATE_OPEN, 00049 STATE_ERROR 00050 } state_t; 00051 00052 static error_t init(void); 00053 static error_t uninit(void); 00054 static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size); 00055 static error_t erase_sector(uint32_t addr); 00056 static error_t erase_chip(void); 00057 static uint32_t program_page_min_size(uint32_t addr); 00058 static uint32_t erase_sector_size(uint32_t addr); 00059 00060 static bool page_program_allowed(uint32_t addr, uint32_t size); 00061 static bool sector_erase_allowed(uint32_t addr); 00062 static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size); 00063 static error_t intercept_sector_erase(uint32_t addr); 00064 static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size); 00065 static uint8_t target_flash_busy(void); 00066 00067 static const flash_intf_t flash_intf = { 00068 init, 00069 uninit, 00070 program_page, 00071 erase_sector, 00072 erase_chip, 00073 program_page_min_size, 00074 erase_sector_size, 00075 target_flash_busy, 00076 }; 00077 00078 const flash_intf_t *const flash_intf_iap_protected = &flash_intf; 00079 00080 static state_t state = STATE_CLOSED; 00081 static bool update_complete; 00082 static bool mass_erase_performed; 00083 static bool current_sector_set; 00084 static uint32_t current_sector; 00085 static uint32_t current_sector_size; 00086 static bool current_page_set; 00087 static uint32_t current_page; 00088 static uint32_t current_page_write_size; 00089 static uint32_t crc; 00090 static uint8_t sector_buf[DAPLINK_SECTOR_SIZE]; 00091 00092 static error_t init() 00093 { 00094 int iap_status; 00095 bool update_supported = DAPLINK_ROM_UPDATE_SIZE != 0; 00096 00097 if (state != STATE_CLOSED) { 00098 util_assert(0); 00099 return ERROR_INTERNAL; 00100 } 00101 00102 if (!update_supported) { 00103 return ERROR_IAP_UPDT_NOT_SUPPORTED; 00104 } 00105 00106 iap_status = Init(0, 0, 0); 00107 00108 if (iap_status != 0) { 00109 return ERROR_IAP_INIT; 00110 } 00111 00112 update_complete = false; 00113 mass_erase_performed = false; 00114 current_sector_set = false; 00115 current_sector = 0; 00116 current_sector_size = 0; 00117 current_page_set = false; 00118 current_page = 0; 00119 current_page_write_size = 0; 00120 crc = 0; 00121 memset(sector_buf, 0, sizeof(sector_buf)); 00122 state = STATE_OPEN; 00123 return ERROR_SUCCESS; 00124 } 00125 00126 static error_t uninit(void) 00127 { 00128 int iap_status; 00129 00130 if (STATE_CLOSED == state) { 00131 util_assert(0); 00132 return ERROR_INTERNAL; 00133 } 00134 00135 state = STATE_CLOSED; 00136 iap_status = UnInit(0); 00137 00138 if (iap_status != 0) { 00139 return ERROR_IAP_UNINIT; 00140 } 00141 00142 if (!update_complete && !daplink_is_bootloader()) { 00143 // Interface - Error if the bootloader update is not complete 00144 // Bootloader - For 3rd party applications the end of the update 00145 // is unknown so it is not an error if the transfer 00146 // ends early. 00147 return ERROR_IAP_UPDT_INCOMPLETE; 00148 } 00149 00150 return ERROR_SUCCESS; 00151 } 00152 00153 static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size) 00154 { 00155 uint32_t iap_status; 00156 error_t status; 00157 uint32_t min_prog_size; 00158 uint32_t sector_size; 00159 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE; 00160 00161 if (state != STATE_OPEN) { 00162 util_assert(0); 00163 return ERROR_INTERNAL; 00164 } 00165 00166 min_prog_size = program_page_min_size(addr); 00167 sector_size = erase_sector_size(addr); 00168 00169 // Address must be on a write size boundary 00170 if (addr % min_prog_size != 0) { 00171 util_assert(0); 00172 state = STATE_ERROR; 00173 return ERROR_INTERNAL; 00174 } 00175 00176 // Programming size must be a non-zero multiple of the minimum write size 00177 if ((size < min_prog_size) || (size % min_prog_size != 0)) { 00178 util_assert(0); 00179 state = STATE_ERROR; 00180 return ERROR_INTERNAL; 00181 } 00182 00183 // Write must not cross a sector boundary 00184 if ((addr % sector_size) + size > sector_size) { 00185 util_assert(0); 00186 state = STATE_ERROR; 00187 return ERROR_INTERNAL; 00188 } 00189 00190 // Write must be in an erased sector (current_sector is always erased if it is set) 00191 if (!mass_erase_performed) { 00192 if (!current_sector_set) { 00193 util_assert(0); 00194 state = STATE_ERROR; 00195 return ERROR_INTERNAL; 00196 } 00197 00198 if ((addr < current_sector) || (addr >= current_sector + current_sector_size)) { 00199 util_assert(0); 00200 state = STATE_ERROR; 00201 return ERROR_INTERNAL; 00202 } 00203 } 00204 00205 // Address must be sequential - no gaps 00206 if (current_page_set && (addr != current_page + current_page_write_size)) { 00207 util_assert(0); 00208 state = STATE_ERROR; 00209 return ERROR_INTERNAL; 00210 } 00211 00212 if (!page_program_allowed(addr, size)) { 00213 state = STATE_ERROR; 00214 return ERROR_IAP_WRITE; 00215 } 00216 00217 current_page_set = true; 00218 current_page = addr; 00219 current_page_write_size = size; 00220 status = intercept_page_write(addr, buf, size); 00221 00222 if (status != ERROR_IAP_NO_INTERCEPT) { 00223 // The operation has been intercepted so 00224 // return the result 00225 if (ERROR_SUCCESS != status) { 00226 state = STATE_ERROR; 00227 } 00228 00229 return status; 00230 } 00231 00232 iap_status = flash_program_page(addr, size, (uint8_t *)buf); 00233 00234 if (iap_status != 0) { 00235 state = STATE_ERROR; 00236 return ERROR_IAP_WRITE; 00237 } 00238 00239 if (addr + size >= updt_end) { 00240 // Something has been updated so recompute the crc 00241 info_crc_compute(); 00242 update_complete = true; 00243 } 00244 00245 return ERROR_SUCCESS; 00246 } 00247 00248 static error_t erase_sector(uint32_t addr) 00249 { 00250 uint32_t iap_status; 00251 error_t status; 00252 uint32_t sector_size; 00253 00254 if (state != STATE_OPEN) { 00255 util_assert(0); 00256 return ERROR_INTERNAL; 00257 } 00258 00259 // Address must be on a sector boundary 00260 sector_size = erase_sector_size(addr); 00261 00262 if (addr % sector_size != 0) { 00263 util_assert(0); 00264 state = STATE_ERROR; 00265 return ERROR_INTERNAL; 00266 } 00267 00268 // Address must be sequential - no gaps 00269 if (current_sector_set && (addr != current_sector + current_sector_size)) { 00270 util_assert(0); 00271 state = STATE_ERROR; 00272 return ERROR_INTERNAL; 00273 } 00274 00275 if (!sector_erase_allowed(addr)) { 00276 state = STATE_ERROR; 00277 return ERROR_IAP_ERASE_SECTOR; 00278 } 00279 00280 current_sector_set = true; 00281 current_sector = addr; 00282 current_sector_size = sector_size; 00283 status = intercept_sector_erase(addr); 00284 00285 if (status != ERROR_IAP_NO_INTERCEPT) { 00286 // The operation has been intercepted so 00287 // return the result 00288 if (ERROR_SUCCESS != status) { 00289 state = STATE_ERROR; 00290 } 00291 00292 return status; 00293 } 00294 00295 iap_status = flash_erase_sector(addr); 00296 00297 if (iap_status != 0) { 00298 state = STATE_ERROR; 00299 return ERROR_IAP_ERASE_SECTOR; 00300 } 00301 00302 return ERROR_SUCCESS; 00303 } 00304 00305 static error_t erase_chip(void) 00306 { 00307 uint32_t updt_start = DAPLINK_ROM_UPDATE_START; 00308 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE; 00309 00310 if (state != STATE_OPEN) { 00311 util_assert(0); 00312 return ERROR_INTERNAL; 00313 } 00314 00315 if (mass_erase_performed) { 00316 // Mass erase only allowed once 00317 util_assert(0); 00318 state = STATE_ERROR; 00319 return ERROR_INTERNAL; 00320 } 00321 00322 for (uint32_t addr = updt_start; addr < updt_end; addr += DAPLINK_SECTOR_SIZE) { 00323 error_t status; 00324 status = erase_sector(addr); 00325 00326 if (status != ERROR_SUCCESS) { 00327 state = STATE_ERROR; 00328 return ERROR_IAP_ERASE_ALL; 00329 } 00330 } 00331 00332 mass_erase_performed = true; 00333 return ERROR_SUCCESS; 00334 } 00335 00336 static uint32_t program_page_min_size(uint32_t addr) 00337 { 00338 return DAPLINK_MIN_WRITE_SIZE; 00339 } 00340 00341 static uint32_t erase_sector_size(uint32_t addr) 00342 { 00343 return DAPLINK_SECTOR_SIZE; 00344 } 00345 00346 static bool page_program_allowed(uint32_t addr, uint32_t size) 00347 { 00348 // Check if any data would overlap with the application region 00349 if ((addr < DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE) && (addr + size > DAPLINK_ROM_APP_START)) { 00350 return false; 00351 } 00352 00353 return true; 00354 } 00355 00356 static bool sector_erase_allowed(uint32_t addr) 00357 { 00358 uint32_t app_start = DAPLINK_ROM_APP_START; 00359 uint32_t app_end = DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE; 00360 00361 // Check if the sector is part of the application 00362 if ((addr >= app_start) && (addr < app_end)) { 00363 return false; 00364 } 00365 00366 return true; 00367 } 00368 00369 static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size) 00370 { 00371 error_t status; 00372 uint32_t crc_size; 00373 uint32_t updt_start = DAPLINK_ROM_UPDATE_START; 00374 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE; 00375 00376 if (state != STATE_OPEN) { 00377 util_assert(0); 00378 return ERROR_INTERNAL; 00379 } 00380 00381 if ((addr < updt_start) || (addr >= updt_end)) { 00382 return ERROR_IAP_OUT_OF_BOUNDS; 00383 } 00384 00385 if (!daplink_is_interface()) { 00386 return ERROR_IAP_NO_INTERCEPT; 00387 } 00388 00389 /* Everything below here is interface specific */ 00390 crc_size = MIN(size, updt_end - addr - 4); 00391 crc = crc32_continue(crc, buf, crc_size); 00392 00393 // Intercept the data if it is in the first sector 00394 if ((addr >= updt_start) && (addr < updt_start + DAPLINK_SECTOR_SIZE)) { 00395 uint32_t buf_offset = addr - updt_start; 00396 memcpy(sector_buf + buf_offset, buf, size); 00397 // Intercept was successful 00398 return ERROR_SUCCESS; 00399 } 00400 00401 // Finalize update if this is the last sector 00402 if (updt_end == addr + size) { 00403 uint32_t iap_status; 00404 uint32_t size_left = updt_end - addr; 00405 uint32_t crc_in_image = (buf[size_left - 4] << 0) | 00406 (buf[size_left - 3] << 8) | 00407 (buf[size_left - 2] << 16) | 00408 (buf[size_left - 1] << 24); 00409 00410 if (crc != crc_in_image) { 00411 return ERROR_BL_UPDT_BAD_CRC; 00412 } 00413 00414 // Program the current buffer 00415 iap_status = flash_program_page(addr, size, (uint8_t *)buf); 00416 00417 if (iap_status != 0) { 00418 return ERROR_IAP_WRITE; 00419 } 00420 00421 status = critical_erase_and_program(DAPLINK_ROM_UPDATE_START, sector_buf, DAPLINK_SECTOR_SIZE); 00422 00423 if (ERROR_SUCCESS == status) { 00424 status = ERROR_SUCCESS; 00425 } 00426 00427 // The bootloader has been updated so recompute the crc 00428 info_crc_compute(); 00429 update_complete = true; 00430 return status; 00431 } 00432 00433 return ERROR_IAP_NO_INTERCEPT; 00434 } 00435 00436 static error_t intercept_sector_erase(uint32_t addr) 00437 { 00438 error_t status; 00439 uint32_t updt_start = DAPLINK_ROM_UPDATE_START; 00440 uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE; 00441 00442 if (state != STATE_OPEN) { 00443 util_assert(0); 00444 return ERROR_INTERNAL; 00445 } 00446 00447 if ((addr < updt_start) || (addr >= updt_end)) { 00448 return ERROR_IAP_OUT_OF_BOUNDS; 00449 } 00450 00451 if (!daplink_is_interface()) { 00452 return ERROR_IAP_NO_INTERCEPT; 00453 } 00454 00455 /* Everything below here is interface specific */ 00456 00457 if (DAPLINK_ROM_UPDATE_START == addr) { 00458 uint32_t addr = DAPLINK_ROM_UPDATE_START; 00459 status = critical_erase_and_program(addr, (uint8_t *)DAPLINK_ROM_IF_START, DAPLINK_MIN_WRITE_SIZE); 00460 00461 if (ERROR_SUCCESS == status) { 00462 // Intercept was successful 00463 status = ERROR_SUCCESS; 00464 } 00465 00466 return status; 00467 } 00468 00469 return ERROR_IAP_NO_INTERCEPT; 00470 } 00471 00472 static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size) 00473 { 00474 uint32_t iap_status; 00475 00476 if (size < DAPLINK_MIN_WRITE_SIZE) { 00477 util_assert(0); 00478 return ERROR_INTERNAL; 00479 } 00480 00481 // CRITICAL SECTION BELOW HERE! 00482 // If something goes wrong with either 00483 // the erase or write then the device 00484 // will no longer be bootable. 00485 // Erase the first sector 00486 iap_status = flash_erase_sector(addr); 00487 00488 if (iap_status != 0) { 00489 return ERROR_ERASE_ALL; 00490 } 00491 00492 // Program the interface's vector table 00493 iap_status = flash_program_page(addr, size, (uint8_t *)data); 00494 00495 if (iap_status != 0) { 00496 return ERROR_IAP_WRITE; 00497 } 00498 00499 return ERROR_SUCCESS; 00500 } 00501 00502 static uint8_t target_flash_busy(void){ 00503 return (state == STATE_OPEN); 00504 }
Generated on Tue Jul 12 2022 15:37:18 by
1.7.2