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.
arm_uc_pal_flashiap_implementation.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // SPDX-License-Identifier: Apache-2.0 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); 00007 // you may not use this file except in compliance with the License. 00008 // You may obtain a copy of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // ---------------------------------------------------------------------------- 00018 00019 #include "arm_uc_config.h" 00020 #if defined(ARM_UC_FEATURE_PAL_FLASHIAP) && (ARM_UC_FEATURE_PAL_FLASHIAP == 1) 00021 #if defined(TARGET_LIKE_MBED) 00022 00023 #define __STDC_FORMAT_MACROS 00024 00025 #include "update-client-pal-flashiap/arm_uc_pal_flashiap.h" 00026 #include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" 00027 #include "update-client-metadata-header/arm_uc_metadata_header_v2.h" 00028 00029 #include <inttypes.h> 00030 #include <stddef.h> 00031 00032 #ifndef MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 00033 #define MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 0 00034 #endif 00035 00036 #ifndef MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 00037 #define MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 0 00038 #endif 00039 00040 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 00041 #define MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 0 00042 #endif 00043 00044 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 00045 #define MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 0 00046 #endif 00047 00048 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 00049 #define MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 1 00050 #endif 00051 00052 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 00053 #define MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 1 00054 #endif 00055 00056 /* consistency check */ 00057 #if (MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE == 0) 00058 #error Update client storage page cannot be zero. 00059 #endif 00060 00061 #if (MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS == 0) 00062 #error Update client storage locations must be at least 1. 00063 #endif 00064 00065 /* Check that the statically allocated buffers are aligned with the block size */ 00066 #define ARM_UC_PAL_ONE_BUFFER (ARM_UC_BUFFER_SIZE / 2) 00067 #define ARM_UC_PAL_PAGES (ARM_UC_PAL_ONE_BUFFER / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) 00068 00069 #if !((ARM_UC_PAL_PAGES * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) == ARM_UC_PAL_ONE_BUFFER) 00070 #error Update client buffer must be divisible by the block page size 00071 #endif 00072 00073 /* Use internal header format because we are using internal flash and 00074 is assumed to be trusted */ 00075 #define ARM_UC_PAL_HEADER_SIZE (uint32_t) ARM_UC_INTERNAL_HEADER_SIZE_V2 00076 00077 static uint64_t arm_uc_pal_flashiap_firmware_size = 0; 00078 00079 static void (*arm_uc_pal_flashiap_callback)(uint32_t) = NULL; 00080 00081 static void arm_uc_pal_flashiap_signal_internal(uint32_t event) 00082 { 00083 if (arm_uc_pal_flashiap_callback) { 00084 arm_uc_pal_flashiap_callback(event); 00085 } 00086 } 00087 00088 /** 00089 * @brief Align address up/down to sector boundary 00090 * 00091 * @param addr The address that need to be rounded up 00092 * @param round_down if the value is 1, will align down to sector 00093 boundary otherwise align up. 00094 * @return Returns the address aligned to sector boundary 00095 */ 00096 static uint32_t arm_uc_pal_flashiap_align_to_sector(uint32_t addr, int8_t round_down) 00097 { 00098 uint32_t sector_start_addr = arm_uc_flashiap_get_flash_start(); 00099 00100 /* check the address is pointing to internal flash */ 00101 if ((addr > sector_start_addr + arm_uc_flashiap_get_flash_size()) || 00102 (addr < sector_start_addr)) { 00103 return ARM_UC_FLASH_INVALID_SIZE; 00104 } 00105 00106 /* add sectors from start of flash until exeeced the required address 00107 we cannot assume uniform sector size as in some mcu sectors have 00108 drastically different sizes */ 00109 uint32_t sector_size = ARM_UC_FLASH_INVALID_SIZE; 00110 while (sector_start_addr < addr) { 00111 sector_size = arm_uc_flashiap_get_sector_size(sector_start_addr); 00112 if (sector_size != ARM_UC_FLASH_INVALID_SIZE) { 00113 sector_start_addr += sector_size; 00114 } else { 00115 return ARM_UC_FLASH_INVALID_SIZE; 00116 } 00117 } 00118 00119 /* if round down to nearest section, remove the last sector from addr */ 00120 if (round_down != 0 && sector_start_addr > addr) { 00121 sector_start_addr -= sector_size; 00122 } 00123 00124 return sector_start_addr; 00125 } 00126 00127 /** 00128 * @brief Round size up to nearest page 00129 * 00130 * @param size The size that need to be rounded up 00131 * @return Returns the size rounded up to the nearest page 00132 */ 00133 static uint32_t arm_uc_pal_flashiap_round_up_to_page_size(uint32_t size) 00134 { 00135 uint32_t page_size = arm_uc_flashiap_get_page_size(); 00136 00137 if (size != 0) { 00138 size = ((size - 1) / page_size + 1) * page_size; 00139 } 00140 00141 return size; 00142 } 00143 00144 /** 00145 * @brief Get the physicl slot address and size given slot_id 00146 * 00147 * @param slot_id Storage location ID. 00148 * @param slot_addr the slot address is returned in this pointer 00149 * @param slot_size the slot size is returned in this pointer 00150 * @return Returns ERR_NONE on success. 00151 * Returns ERR_INVALID_PARAMETER on error. 00152 */ 00153 static arm_uc_error_t arm_uc_pal_flashiap_get_slot_addr_size(uint32_t slot_id, 00154 uint32_t *slot_addr, 00155 uint32_t *slot_size) 00156 { 00157 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00158 /* find the start address of the whole storage area. It needs to be aligned to 00159 sector boundary and we cannot go outside user defined storage area, hence 00160 rounding up to sector boundary */ 00161 uint32_t storage_start_addr = arm_uc_pal_flashiap_align_to_sector( 00162 MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS, 0); 00163 /* find the end address of the whole storage area. It needs to be aligned to 00164 sector boundary and we cannot go outside user defined storage area, hence 00165 rounding down to sector boundary */ 00166 uint32_t storage_end_addr = arm_uc_pal_flashiap_align_to_sector( 00167 MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + \ 00168 MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE, 1); 00169 /* find the maximum size each slot can have given the start and end, without 00170 considering the alignment of individual slots */ 00171 uint32_t max_slot_size = (storage_end_addr - storage_start_addr) / \ 00172 MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; 00173 /* find the start address of slot. It needs to align to sector boundary. We 00174 choose here to round down at each slot boundary */ 00175 uint32_t slot_start_addr = arm_uc_pal_flashiap_align_to_sector( 00176 storage_start_addr + \ 00177 slot_id * max_slot_size, 1); 00178 /* find the end address of the slot, rounding down to sector boundary same as 00179 the slot start address so that we make sure two slot don't overlap */ 00180 uint32_t slot_end_addr = arm_uc_pal_flashiap_align_to_sector( 00181 slot_start_addr + \ 00182 max_slot_size, 1); 00183 00184 /* Any calculation above might result in an invalid address. */ 00185 if ((storage_start_addr == ARM_UC_FLASH_INVALID_SIZE) || 00186 (storage_end_addr == ARM_UC_FLASH_INVALID_SIZE) || 00187 (slot_start_addr == ARM_UC_FLASH_INVALID_SIZE) || 00188 (slot_end_addr == ARM_UC_FLASH_INVALID_SIZE) || 00189 (slot_id >= MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)) { 00190 UC_PAAL_ERR_MSG("Aligning fw storage slot to erase sector failed" 00191 " storage_start_addr %" PRIX32 " slot_start_addr %" PRIX32 00192 " max_slot_size %" PRIX32, storage_start_addr, slot_start_addr, 00193 max_slot_size); 00194 *slot_addr = ARM_UC_FLASH_INVALID_SIZE; 00195 *slot_size = ARM_UC_FLASH_INVALID_SIZE; 00196 } else { 00197 *slot_addr = slot_start_addr; 00198 *slot_size = slot_end_addr - slot_start_addr; 00199 result.code = ERR_NONE; 00200 } 00201 00202 return result; 00203 } 00204 00205 /** 00206 * @brief Initialise the flash IAP API 00207 * 00208 * @param callback function pointer to the PAAL event handler 00209 * @return Returns ERR_NONE on success. 00210 * Returns ERR_INVALID_PARAMETER on error. 00211 */ 00212 arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(void (*callback)(uint32_t)) 00213 { 00214 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00215 00216 int32_t status = arm_uc_flashiap_init(); 00217 00218 if (status == ARM_UC_FLASHIAP_SUCCESS) { 00219 arm_uc_pal_flashiap_callback = callback; 00220 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); 00221 00222 result.code = ERR_NONE; 00223 } 00224 00225 return result; 00226 } 00227 00228 /** 00229 * @brief Get maximum number of supported storage locations. 00230 * 00231 * @return Number of storage locations. 00232 */ 00233 uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void) 00234 { 00235 return MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; 00236 } 00237 00238 /** 00239 * @brief Prepare the storage layer for a new firmware image. 00240 * @details The storage location is set up to receive an image with 00241 * the details passed in the details struct. 00242 * 00243 * @param slot_id Storage location ID. 00244 * @param details Pointer to a struct with firmware details. 00245 * @param buffer Temporary buffer for formatting and storing metadata. 00246 * @return Returns ERR_NONE on accept, and signals the event handler with 00247 * either DONE or ERROR when complete. 00248 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00249 */ 00250 arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t slot_id, 00251 const arm_uc_firmware_details_t *details, 00252 arm_uc_buffer_t *buffer) 00253 { 00254 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Prepare slot_id %" PRIu32 " details %p buffer %p", 00255 slot_id, details, buffer); 00256 00257 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00258 uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; 00259 uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; 00260 uint32_t erase_size = ARM_UC_FLASH_INVALID_SIZE; 00261 00262 /* validate input */ 00263 if (details && buffer && buffer->ptr && \ 00264 slot_id < MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) { 00265 UC_PAAL_TRACE("FW size %" PRIu64, details->size); 00266 result.error = ERR_NONE; 00267 } else { 00268 UC_PAAL_TRACE("Input validation failed"); 00269 } 00270 00271 /* calculate space for new firmware */ 00272 if (result.error == ERR_NONE) { 00273 /* find slot start address */ 00274 result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, &slot_addr, &slot_size); 00275 00276 /* find the amount of space that need to be erased */ 00277 erase_size = arm_uc_pal_flashiap_align_to_sector( 00278 slot_addr + \ 00279 arm_uc_pal_flashiap_round_up_to_page_size(details->size) + \ 00280 arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE), 00281 0) - slot_addr; 00282 00283 if ((result.error == ERR_NONE) && (erase_size > slot_size)) { 00284 result.code = PAAL_ERR_FIRMWARE_TOO_LARGE; 00285 UC_PAAL_ERR_MSG("Firmware too large! required %" PRIX32 " available: %" PRIX32, 00286 erase_size, slot_size); 00287 } 00288 } 00289 00290 /* erase space for new firmware */ 00291 if (result.error == ERR_NONE) { 00292 uint32_t erase_addr = slot_addr; 00293 while (erase_addr < slot_addr + erase_size) { 00294 uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_addr); 00295 UC_PAAL_TRACE("erase: addr %" PRIX32 " size %" PRIX32, 00296 erase_addr, sector_size); 00297 if (sector_size != ARM_UC_FLASH_INVALID_SIZE) { 00298 int32_t status = arm_uc_flashiap_erase(erase_addr, sector_size); 00299 if (status == ARM_UC_FLASHIAP_SUCCESS) { 00300 erase_addr += sector_size; 00301 } else { 00302 UC_PAAL_ERR_MSG("Flash erase failed with status %" PRIi32, status); 00303 result.code = ERR_INVALID_PARAMETER; 00304 break; 00305 } 00306 } else { 00307 UC_PAAL_ERR_MSG("Get sector size for addr %" PRIX32 " failed", erase_addr); 00308 result.code = ERR_INVALID_PARAMETER; 00309 break; 00310 } 00311 } 00312 } 00313 00314 /* generate header blob */ 00315 if (result.error == ERR_NONE) { 00316 result = arm_uc_create_internal_header_v2(details, buffer); 00317 if (result.error != ERR_NONE) { 00318 UC_PAAL_ERR_MSG("arm_uc_create_internal_header_v2 failed"); 00319 } 00320 } 00321 00322 /* write header blob */ 00323 if (result.error == ERR_NONE) { 00324 uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); 00325 UC_PAAL_TRACE("program: %" PRIX32 " %" PRIX32, 00326 slot_addr, hdr_size); 00327 00328 /* write header */ 00329 int32_t status = arm_uc_flashiap_program((const uint8_t *) buffer->ptr, 00330 slot_addr, 00331 hdr_size); 00332 if (status != ARM_UC_FLASHIAP_SUCCESS) { 00333 /* set return code */ 00334 result.code = ERR_INVALID_PARAMETER; 00335 } 00336 } 00337 00338 if (result.error == ERR_NONE) { 00339 /* store firmware size in global */ 00340 arm_uc_pal_flashiap_firmware_size = details->size; 00341 00342 /* signal done */ 00343 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); 00344 } 00345 00346 return result; 00347 } 00348 00349 /** 00350 * @brief Write a fragment to the indicated storage location. 00351 * @details The storage location must have been allocated using the Prepare 00352 * call. The call is expected to write the entire fragment before 00353 * signaling completion. 00354 * 00355 * @param slot_id Storage location ID. 00356 * @param offset Offset in bytes to where the fragment should be written. 00357 * @param buffer Pointer to buffer struct with fragment. 00358 * @return Returns ERR_NONE on accept, and signals the event handler with 00359 * either DONE or ERROR when complete. 00360 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00361 */ 00362 arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t slot_id, 00363 uint32_t offset, 00364 const arm_uc_buffer_t *buffer) 00365 { 00366 /* find slot address and size */ 00367 uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; 00368 uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; 00369 arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, 00370 &slot_addr, 00371 &slot_size); 00372 00373 if (buffer && buffer->ptr && result.error == ERR_NONE) { 00374 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32, 00375 buffer->ptr, buffer->size, slot_addr, offset); 00376 00377 /* set default error */ 00378 result.code = ERR_INVALID_PARAMETER; 00379 00380 /* find physical address of the write */ 00381 uint32_t page_size = arm_uc_flashiap_get_page_size(); 00382 uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); 00383 uint32_t physical_address = slot_addr + hdr_size + offset; 00384 uint32_t write_size = buffer->size; 00385 00386 /* if last chunk, pad out to page_size aligned size */ 00387 if ((buffer->size % page_size != 0) && 00388 ((offset + buffer->size) >= arm_uc_pal_flashiap_firmware_size) && 00389 (arm_uc_pal_flashiap_round_up_to_page_size(buffer->size) <= buffer->size_max)) { 00390 write_size = arm_uc_pal_flashiap_round_up_to_page_size(buffer->size); 00391 } 00392 00393 /* check page alignment of the program address and size */ 00394 if ((write_size % page_size == 0) && (physical_address % page_size == 0)) { 00395 UC_PAAL_TRACE("programming addr %" PRIX32 " size %" PRIX32, 00396 physical_address, write_size); 00397 int status = arm_uc_flashiap_program((const uint8_t *) buffer->ptr, 00398 physical_address, 00399 write_size); 00400 if (status != ARM_UC_FLASHIAP_SUCCESS) { 00401 UC_PAAL_ERR_MSG("arm_uc_flashiap_program failed"); 00402 } else { 00403 result.code = ERR_NONE; 00404 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); 00405 } 00406 } else { 00407 UC_PAAL_ERR_MSG("program size %" PRIX32 " or address %" PRIX32 00408 " not aligned to page size %" PRIX32, buffer->size, 00409 physical_address, page_size); 00410 } 00411 } else { 00412 result.code = ERR_INVALID_PARAMETER; 00413 } 00414 00415 return result; 00416 } 00417 00418 /** 00419 * @brief Close storage location for writing and flush pending data. 00420 * 00421 * @param slot_id Storage location ID. 00422 * @return Returns ERR_NONE on accept, and signals the event handler with 00423 * either DONE or ERROR when complete. 00424 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00425 */ 00426 arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t slot_id) 00427 { 00428 arm_uc_error_t result = { .code = ERR_NONE }; 00429 00430 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Finalize"); 00431 00432 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); 00433 00434 return result; 00435 } 00436 00437 /** 00438 * @brief Read a fragment from the indicated storage location. 00439 * @details The function will read until the buffer is full or the end of 00440 * the storage location has been reached. The actual amount of 00441 * bytes read is set in the buffer struct. 00442 * 00443 * @param slot_id Storage location ID. 00444 * @param offset Offset in bytes to read from. 00445 * @param buffer Pointer to buffer struct to store fragment. buffer->size 00446 * contains the intended read size. 00447 * @return Returns ERR_NONE on accept, and signals the event handler with 00448 * either DONE or ERROR when complete. 00449 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00450 * buffer->size contains actual bytes read on return. 00451 */ 00452 arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t slot_id, 00453 uint32_t offset, 00454 arm_uc_buffer_t *buffer) 00455 { 00456 /* find slot address and size */ 00457 uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; 00458 uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; 00459 arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, 00460 &slot_addr, 00461 &slot_size); 00462 00463 if (buffer && buffer->ptr && result.error == ERR_NONE) { 00464 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Read: %" PRIX32 " %" PRIX32 " %" PRIX32, 00465 slot_id, offset, buffer->size); 00466 00467 /* find physical address of the read */ 00468 uint32_t read_size = buffer->size; 00469 uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); 00470 uint32_t physical_address = slot_addr + hdr_size + offset; 00471 00472 UC_PAAL_TRACE("reading addr %" PRIX32 " size %" PRIX32, 00473 physical_address, read_size); 00474 00475 int status = arm_uc_flashiap_read(buffer->ptr, 00476 physical_address, 00477 read_size); 00478 00479 if (status == ARM_UC_FLASHIAP_SUCCESS) { 00480 result.code = ERR_NONE; 00481 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); 00482 } else { 00483 result.code = ERR_INVALID_PARAMETER; 00484 UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed"); 00485 } 00486 } else { 00487 result.code = ERR_INVALID_PARAMETER; 00488 } 00489 00490 return result; 00491 } 00492 00493 /** 00494 * @brief Set the firmware image in the slot to be the new active image. 00495 * @details This call is responsible for initiating the process for 00496 * applying a new/different image. Depending on the platform this 00497 * could be: 00498 * * An empty call, if the installer can deduce which slot to 00499 * choose from based on the firmware details. 00500 * * Setting a flag to indicate which slot to use next. 00501 * * Decompressing/decrypting/installing the firmware image on 00502 * top of another. 00503 * 00504 * @param slot_id Storage location ID. 00505 * @return Returns ERR_NONE on accept, and signals the event handler with 00506 * either DONE or ERROR when complete. 00507 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00508 */ 00509 arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t slot_id) 00510 { 00511 arm_uc_error_t result = { .code = ERR_NONE }; 00512 00513 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Activate"); 00514 00515 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); 00516 00517 return result; 00518 } 00519 00520 /** 00521 * @brief Get firmware details for the firmware image in the slot passed. 00522 * @details This call populates the passed details struct with information 00523 * about the firmware image in the slot passed. Only the fields 00524 * marked as supported in the capabilities bitmap will have valid 00525 * values. 00526 * 00527 * @param details Pointer to firmware details struct to be populated. 00528 * @return Returns ERR_NONE on accept, and signals the event handler with 00529 * either DONE or ERROR when complete. 00530 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00531 */ 00532 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails( 00533 uint32_t slot_id, 00534 arm_uc_firmware_details_t *details) 00535 { 00536 UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_GetFirmwareDetails"); 00537 00538 /* find slot address and size */ 00539 uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; 00540 uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; 00541 arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, 00542 &slot_addr, 00543 &slot_size); 00544 00545 if (details && result.error == ERR_NONE) { 00546 uint8_t buffer[ARM_UC_PAL_HEADER_SIZE] = { 0 }; 00547 00548 int status = arm_uc_flashiap_read(buffer, 00549 slot_addr, 00550 ARM_UC_PAL_HEADER_SIZE); 00551 00552 if (status == ARM_UC_FLASHIAP_SUCCESS) { 00553 result = arm_uc_parse_internal_header_v2(buffer, details); 00554 00555 if (result.error == ERR_NONE) { 00556 /* signal done */ 00557 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); 00558 } else { 00559 UC_PAAL_ERR_MSG("arm_uc_parse_internal_header_v2 failed"); 00560 } 00561 } else { 00562 UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed"); 00563 } 00564 } 00565 00566 return result; 00567 } 00568 00569 /*****************************************************************************/ 00570 00571 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t *details) 00572 { 00573 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00574 00575 if (details) { 00576 /* read details from memory if offset is set */ 00577 if (MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS) { 00578 /* set default error code */ 00579 result.code = ERR_NOT_READY; 00580 00581 /* Use flash driver eventhough we are reading from internal flash. 00582 This will make it easier to use with uVisor. 00583 */ 00584 uint8_t version_buffer[8] = { 0 }; 00585 00586 /* read metadata magic and version from flash */ 00587 int rc = arm_uc_flashiap_read(version_buffer, 00588 MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, 00589 8); 00590 00591 if (rc == ARM_UC_FLASHIAP_SUCCESS) { 00592 /* read out header magic */ 00593 uint32_t headerMagic = arm_uc_parse_uint32(&version_buffer[0]); 00594 00595 /* read out header magic */ 00596 uint32_t headerVersion = arm_uc_parse_uint32(&version_buffer[4]); 00597 00598 /* choose version to decode */ 00599 switch (headerVersion) { 00600 case ARM_UC_INTERNAL_HEADER_VERSION_V2: { 00601 result.code = ERR_NONE; 00602 /* Check the header magic */ 00603 if (headerMagic != ARM_UC_INTERNAL_HEADER_MAGIC_V2) { 00604 UC_PAAL_ERR_MSG("firmware header is v2, but does not contain v2 magic"); 00605 result.code = ERR_NOT_READY; 00606 } 00607 00608 uint8_t read_buffer[ARM_UC_INTERNAL_HEADER_SIZE_V2] = { 0 }; 00609 /* Read the rest of the header */ 00610 if (result.error == ERR_NONE) { 00611 rc = arm_uc_flashiap_read(read_buffer, 00612 MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, 00613 ARM_UC_INTERNAL_HEADER_SIZE_V2); 00614 if (rc != 0) { 00615 result.code = ERR_NOT_READY; 00616 UC_PAAL_ERR_MSG("failed to read v2 header"); 00617 } 00618 } 00619 /* Parse the header */ 00620 if (result.error == ERR_NONE) { 00621 result = arm_uc_parse_internal_header_v2(read_buffer, details); 00622 if (result.error != ERR_NONE) { 00623 UC_PAAL_ERR_MSG("failed to parse v2 header"); 00624 } 00625 } 00626 break; 00627 } 00628 /* 00629 * Other firmware header versions can be supported here. 00630 */ 00631 default: { 00632 UC_PAAL_ERR_MSG("unrecognized firmware header version"); 00633 result.code = ERR_NOT_READY; 00634 } 00635 } 00636 } else { 00637 UC_PAAL_ERR_MSG("flash read failed"); 00638 } 00639 } else { 00640 /* offset not set - zero out struct */ 00641 memset(details, 0, sizeof(arm_uc_firmware_details_t)); 00642 00643 result.code = ERR_NONE; 00644 } 00645 00646 /* signal event if operation was successful */ 00647 if (result.error == ERR_NONE) { 00648 UC_PAAL_TRACE("callback"); 00649 00650 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); 00651 } 00652 } 00653 00654 return result; 00655 } 00656 00657 /** 00658 * @brief Get details for the firmware installer. 00659 * @details This call populates the passed details struct with information 00660 * about the firmware installer. 00661 * 00662 * @param details Pointer to firmware details struct to be populated. 00663 * @return Returns ERR_NONE on accept, and signals the event handler with 00664 * either DONE or ERROR when complete. 00665 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00666 */ 00667 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t *details) 00668 { 00669 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00670 00671 if (details) { 00672 /* only read from memory if offset is set */ 00673 if (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS) { 00674 uint8_t *arm = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + 00675 offsetof(arm_uc_installer_details_t, arm_hash)); 00676 00677 uint8_t *oem = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + 00678 offsetof(arm_uc_installer_details_t, oem_hash)); 00679 00680 uint8_t *layout = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + 00681 offsetof(arm_uc_installer_details_t, layout)); 00682 00683 /* populate installer details struct */ 00684 memcpy(&details->arm_hash, arm, ARM_UC_SHA256_SIZE); 00685 memcpy(&details->oem_hash, oem, ARM_UC_SHA256_SIZE); 00686 details->layout = arm_uc_parse_uint32(layout); 00687 } else { 00688 /* offset not set, zero details struct */ 00689 memset(details, 0, sizeof(arm_uc_installer_details_t)); 00690 } 00691 00692 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); 00693 00694 result.code = ERR_NONE; 00695 } 00696 00697 return result; 00698 } 00699 00700 #endif /* TARGET_LIKE_MBED */ 00701 #endif /* ARM_UC_FEATURE_PAL_FLASHIAP */
Generated on Mon Aug 29 2022 19:53:38 by
