Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_pal_blockdevice_implementation.c Source File

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)