Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
arm_uc_pal_blockdevice_implementation.c
00001 //---------------------------------------------------------------------------- 00002 // The confidential and proprietary information contained in this file may 00003 // only be used by a person authorised under and to the extent permitted 00004 // by a subsisting licensing agreement from ARM Limited or its affiliates. 00005 // 00006 // (C) COPYRIGHT 2017 ARM Limited or its affiliates. 00007 // ALL RIGHTS RESERVED 00008 // 00009 // This entire notice must be reproduced on all copies of this file 00010 // and copies of this file may only be made by a person if such person is 00011 // permitted to do so under the terms of a subsisting license agreement 00012 // from ARM Limited or its affiliates. 00013 //---------------------------------------------------------------------------- 00014 00015 #if defined(ARM_UC_USE_PAL_BLOCKDEVICE) 00016 00017 #define __STDC_FORMAT_MACROS 00018 00019 #include "update-client-pal-blockdevice/arm_uc_pal_blockdevice.h" 00020 00021 #include "update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h" 00022 00023 #include "update-client-common/arm_uc_config.h" 00024 #include "update-client-common/arm_uc_error.h" 00025 #include "update-client-common/arm_uc_types.h" 00026 #include "update-client-common/arm_uc_metadata_header_v2.h" 00027 00028 #define TRACE_GROUP "UCPI" 00029 #include "update-client-common/arm_uc_trace.h" 00030 #include <inttypes.h> 00031 00032 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 00033 #define MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 0 00034 #endif 00035 00036 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 00037 #define MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 0 00038 #endif 00039 00040 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 00041 #define MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 1 00042 #endif 00043 00044 #ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 00045 #define MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 1 00046 #endif 00047 00048 /* consistency check */ 00049 #if (MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE == 0) 00050 #error Update client storage page cannot be zero. 00051 #endif 00052 00053 #if (MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS == 0) 00054 #error Update client storage locations must be at least 1. 00055 #endif 00056 00057 /* Check that the statically allocated buffers are aligned with the block size */ 00058 #define ARM_UC_PAL_ONE_BUFFER (ARM_UC_BUFFER_SIZE / 2) 00059 #define ARM_UC_PAL_PAGES (ARM_UC_PAL_ONE_BUFFER / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) 00060 00061 #if !((ARM_UC_PAL_PAGES * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) == ARM_UC_PAL_ONE_BUFFER) 00062 #error Update client buffer must be divisible by the block page size 00063 #endif 00064 00065 /* Calculate aligned external header size */ 00066 #define ARM_UC_PAL_HEADER_SIZE (((ARM_UC_EXTERNAL_HEADER_SIZE_V2 + MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE - 1) \ 00067 / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) 00068 00069 static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_block_event_handler = NULL; 00070 00071 static void arm_uc_pal_blockdevice_signal_internal(uint32_t event) 00072 { 00073 if (arm_uc_block_event_handler) 00074 { 00075 arm_uc_block_event_handler(event); 00076 } 00077 } 00078 00079 /** 00080 * @brief Initialize the underlying storage and set the callback handler. 00081 * 00082 * @param callback Function pointer to event handler. 00083 * @return Returns ERR_NONE on accept, and signals the event handler with 00084 * either DONE or ERROR when complete. 00085 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00086 */ 00087 arm_uc_error_t ARM_UC_PAL_BlockDevice_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) 00088 { 00089 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00090 00091 if (callback) 00092 { 00093 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Initialize"); 00094 00095 int status = arm_uc_blockdevice_init(); 00096 00097 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00098 { 00099 arm_uc_block_event_handler = callback; 00100 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); 00101 result.code = ERR_NONE; 00102 } 00103 } 00104 00105 return result; 00106 } 00107 00108 /** 00109 * @brief Get maximum number of supported storage locations. 00110 * 00111 * @return Number of storage locations. 00112 */ 00113 uint32_t ARM_UC_PAL_BlockDevice_GetMaxID(void) 00114 { 00115 return 0; 00116 } 00117 00118 /** 00119 * @brief Prepare the storage layer for a new firmware image. 00120 * @details The storage location is set up to receive an image with 00121 * the details passed in the details struct. 00122 * 00123 * @param location Storage location ID. 00124 * @param details Pointer to a struct with firmware details. 00125 * @param buffer Temporary buffer for formatting and storing metadata. 00126 * @return Returns ERR_NONE on accept, and signals the event handler with 00127 * either DONE or ERROR when complete. 00128 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00129 */ 00130 arm_uc_error_t ARM_UC_PAL_BlockDevice_Prepare(uint32_t location, 00131 const arm_uc_firmware_details_t* details, 00132 arm_uc_buffer_t* buffer) 00133 { 00134 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00135 00136 if (details && buffer && buffer->ptr) 00137 { 00138 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Prepare: %" PRIX32 " %" PRIX32, 00139 location, details->size); 00140 00141 /* encode firmware details in buffer */ 00142 arm_uc_error_t header_status = arm_uc_create_external_header_v2(details, 00143 buffer); 00144 if (header_status.error == ERR_NONE) 00145 { 00146 /* round up header to page size */ 00147 uint32_t page_size = arm_uc_blockdevice_get_program_size(); 00148 uint32_t header_size = ((buffer->size + page_size - 1) / 00149 page_size) * page_size; 00150 00151 /* round up to sector size */ 00152 uint32_t sector_size = arm_uc_blockdevice_get_erase_size(); 00153 uint32_t erase_size = ((header_size + details->size + sector_size - 1) / 00154 sector_size) * sector_size; 00155 00156 /* find location address */ 00157 uint64_t physical_address = 00158 MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + 00159 ((uint64_t) location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / 00160 MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS); 00161 00162 UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32, physical_address, erase_size); 00163 00164 /* erase */ 00165 int status = arm_uc_blockdevice_erase(physical_address, erase_size); 00166 00167 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00168 { 00169 /* write header */ 00170 status = arm_uc_blockdevice_program(buffer->ptr, 00171 physical_address, 00172 header_size); 00173 00174 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00175 { 00176 /* set return code */ 00177 result.code = ERR_NONE; 00178 00179 /* signal done */ 00180 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); 00181 } 00182 else 00183 { 00184 UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); 00185 } 00186 } 00187 else 00188 { 00189 UC_PAAL_ERR_MSG("arm_uc_blockdevice_erase failed"); 00190 } 00191 } 00192 else 00193 { 00194 UC_PAAL_ERR_MSG("arm_uc_create_external_header_v2 failed"); 00195 } 00196 } 00197 00198 return result; 00199 } 00200 00201 /** 00202 * @brief Write a fragment to the indicated storage location. 00203 * @details The storage location must have been allocated using the Prepare 00204 * call. The call is expected to write the entire fragment before 00205 * signaling completion. 00206 * 00207 * @param location Storage location ID. 00208 * @param offset Offset in bytes to where the fragment should be written. 00209 * @param buffer Pointer to buffer struct with fragment. 00210 * @return Returns ERR_NONE on accept, and signals the event handler with 00211 * either DONE or ERROR when complete. 00212 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00213 */ 00214 arm_uc_error_t ARM_UC_PAL_BlockDevice_Write(uint32_t location, 00215 uint32_t offset, 00216 const arm_uc_buffer_t* buffer) 00217 { 00218 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00219 00220 if (buffer && buffer->ptr) 00221 { 00222 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Write: %" PRIX32 " %" PRIX32 " %" PRIX32, 00223 location, offset, buffer->size); 00224 00225 /* find location address */ 00226 uint64_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + 00227 ((uint64_t) location * 00228 MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / 00229 MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) + 00230 ARM_UC_PAL_HEADER_SIZE + 00231 offset; 00232 00233 int status = ARM_UC_BLOCKDEVICE_SUCCESS; 00234 00235 /* aligned write */ 00236 uint32_t page_size = arm_uc_blockdevice_get_program_size(); 00237 uint32_t aligned_size = (buffer->size / page_size) * page_size; 00238 00239 if (aligned_size > 0) 00240 { 00241 status = arm_uc_blockdevice_program(buffer->ptr, 00242 physical_address, 00243 aligned_size); 00244 } 00245 00246 /* write remainder */ 00247 uint32_t remainder_size = buffer->size - aligned_size; 00248 00249 if ((status == ARM_UC_BLOCKDEVICE_SUCCESS) && (remainder_size > 0)) 00250 { 00251 /* check if it is safe to use buffer, i.e. buffer is larger than a page */ 00252 if (buffer->size_max >= page_size) 00253 { 00254 memmove(buffer->ptr, &(buffer->ptr[aligned_size]), remainder_size); 00255 status = arm_uc_blockdevice_program(buffer->ptr, 00256 physical_address + aligned_size, 00257 page_size); 00258 } 00259 else 00260 { 00261 UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); 00262 00263 status = ARM_UC_BLOCKDEVICE_FAIL; 00264 } 00265 } 00266 00267 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00268 { 00269 /* set return code */ 00270 result.code = ERR_NONE; 00271 00272 /* signal done */ 00273 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); 00274 } 00275 else 00276 { 00277 UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); 00278 } 00279 } 00280 00281 return result; 00282 } 00283 00284 /** 00285 * @brief Close storage location for writing and flush pending data. 00286 * 00287 * @param location Storage location ID. 00288 * @return Returns ERR_NONE on accept, and signals the event handler with 00289 * either DONE or ERROR when complete. 00290 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00291 */ 00292 arm_uc_error_t ARM_UC_PAL_BlockDevice_Finalize(uint32_t location) 00293 { 00294 arm_uc_error_t result = { .code = ERR_NONE }; 00295 00296 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Finalize"); 00297 00298 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); 00299 00300 return result; 00301 } 00302 00303 /** 00304 * @brief Read a fragment from the indicated storage location. 00305 * @details The function will read until the buffer is full or the end of 00306 * the storage location has been reached. The actual amount of 00307 * bytes read is set in the buffer struct. 00308 * 00309 * @param location Storage location ID. 00310 * @param offset Offset in bytes to read from. 00311 * @param buffer Pointer to buffer struct to store fragment. buffer->size 00312 * contains the intended read size. 00313 * @return Returns ERR_NONE on accept, and signals the event handler with 00314 * either DONE or ERROR when complete. 00315 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00316 * buffer->size contains actual bytes read on return. 00317 */ 00318 arm_uc_error_t ARM_UC_PAL_BlockDevice_Read(uint32_t location, 00319 uint32_t offset, 00320 arm_uc_buffer_t* buffer) 00321 { 00322 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00323 00324 if (buffer && buffer->ptr) 00325 { 00326 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Read: %" PRIX32 " %" PRIX32 " %" PRIX32, 00327 location, offset, buffer->size); 00328 00329 /* find location address */ 00330 uint64_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + 00331 ((uint64_t) location * 00332 MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / 00333 MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) + 00334 ARM_UC_PAL_HEADER_SIZE + 00335 offset; 00336 uint32_t page_size = arm_uc_blockdevice_get_program_size(); 00337 uint32_t read_size = ((buffer->size - 1) / page_size + 1) * page_size; 00338 uint32_t status = ARM_UC_BLOCKDEVICE_FAIL; 00339 00340 if (read_size <= buffer->size_max) 00341 { 00342 status = arm_uc_blockdevice_read(buffer->ptr, 00343 physical_address, 00344 read_size); 00345 } 00346 00347 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00348 { 00349 /* set return code */ 00350 result.code = ERR_NONE; 00351 00352 /* signal done */ 00353 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); 00354 } 00355 else 00356 { 00357 UC_PAAL_ERR_MSG("arm_uc_blockdevice_read failed"); 00358 } 00359 } 00360 00361 return result; 00362 } 00363 00364 /** 00365 * @brief Set the firmware image in the slot to be the new active image. 00366 * @details This call is responsible for initiating the process for 00367 * applying a new/different image. Depending on the platform this 00368 * could be: 00369 * * An empty call, if the installer can deduce which slot to 00370 * choose from based on the firmware details. 00371 * * Setting a flag to indicate which slot to use next. 00372 * * Decompressing/decrypting/installing the firmware image on 00373 * top of another. 00374 * 00375 * @param location Storage location ID. 00376 * @return Returns ERR_NONE on accept, and signals the event handler with 00377 * either DONE or ERROR when complete. 00378 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00379 */ 00380 arm_uc_error_t ARM_UC_PAL_BlockDevice_Activate(uint32_t location) 00381 { 00382 arm_uc_error_t result = { .code = ERR_NONE }; 00383 00384 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Activate"); 00385 00386 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); 00387 00388 return result; 00389 } 00390 00391 /** 00392 * @brief Get firmware details for the firmware image in the slot passed. 00393 * @details This call populates the passed details struct with information 00394 * about the firmware image in the slot passed. Only the fields 00395 * marked as supported in the capabilities bitmap will have valid 00396 * values. 00397 * 00398 * @param details Pointer to firmware details struct to be populated. 00399 * @return Returns ERR_NONE on accept, and signals the event handler with 00400 * either DONE or ERROR when complete. 00401 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00402 */ 00403 arm_uc_error_t ARM_UC_PAL_BlockDevice_GetFirmwareDetails( 00404 uint32_t location, 00405 arm_uc_firmware_details_t* details) 00406 { 00407 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00408 00409 if (details) 00410 { 00411 UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_GetFirmwareDetails"); 00412 00413 /* find location address */ 00414 uint64_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + 00415 ((uint64_t) location * 00416 MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE / 00417 MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS); 00418 00419 uint8_t buffer[ARM_UC_PAL_HEADER_SIZE] = { 0 }; 00420 00421 int status = arm_uc_blockdevice_read(buffer, 00422 physical_address, 00423 ARM_UC_PAL_HEADER_SIZE); 00424 00425 if (status == ARM_UC_BLOCKDEVICE_SUCCESS) 00426 { 00427 result = arm_uc_parse_external_header_v2(buffer, details); 00428 00429 if (result.error == ERR_NONE) 00430 { 00431 /* signal done */ 00432 arm_uc_pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); 00433 } 00434 else 00435 { 00436 UC_PAAL_ERR_MSG("arm_uc_parse_external_header_v2 failed"); 00437 } 00438 } 00439 else 00440 { 00441 UC_PAAL_ERR_MSG("arm_uc_blockdevice_read failed"); 00442 } 00443 } 00444 00445 return result; 00446 } 00447 00448 #endif // #if defined(ARM_UC_USE_PAL_BLOCKDEVICE)
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2