Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_paal_classic_pal.c Source File

arm_uc_paal_classic_pal.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_FILESYSTEM) && (ARM_UC_FEATURE_PAL_FILESYSTEM == 1)
00021 
00022 #include "update-client-paal/arm_uc_paal_update_api.h"
00023 
00024 #include "update-client-pal-filesystem/arm_uc_pal_extensions.h"
00025 #include "update-client-metadata-header/arm_uc_metadata_header_v2.h"
00026 #include "arm_uc_pal_filesystem_utils.h"
00027 
00028 #include "pal.h"
00029 
00030 #include "mbed-trace/mbed_trace.h"
00031 #define TRACE_GROUP "UCPI"
00032 
00033 #include <stdio.h>
00034 
00035 #define ARM_UC_FIRMWARE_FOLDER_NAME "firmware"
00036 
00037 /* pointer to external callback handler */
00038 static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL;
00039 
00040 static void arm_uc_pal_classic_signal_callback(uintptr_t event)
00041 {
00042     if (arm_uc_pal_external_callback) {
00043         arm_uc_pal_external_callback(event);
00044     }
00045 }
00046 
00047 static void arm_uc_pal_classic_callback(palImageEvents_t event)
00048 {
00049     /*
00050         ARM_UC_PAAL_EVENT_INITIALIZE_DONE,
00051         ARM_UC_PAAL_EVENT_PREPARE_DONE,
00052         ARM_UC_PAAL_EVENT_WRITE_DONE,
00053         ARM_UC_PAAL_EVENT_FINALIZE_DONE,
00054         ARM_UC_PAAL_EVENT_READ_DONE,
00055         ARM_UC_PAAL_EVENT_ACTIVATE_DONE,
00056         ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE,
00057         ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE,
00058         ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE,
00059         ARM_UC_PAAL_EVENT_INITIALIZE_ERROR,
00060         ARM_UC_PAAL_EVENT_PREPARE_ERROR,
00061         ARM_UC_PAAL_EVENT_WRITE_ERROR,
00062         ARM_UC_PAAL_EVENT_FINALIZE_ERROR,
00063         ARM_UC_PAAL_EVENT_READ_ERROR,
00064         ARM_UC_PAAL_EVENT_ACTIVATE_ERROR,
00065         ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR,
00066         ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR,
00067         ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR,
00068     */
00069     tr_debug("arm_uc_pal_classic_callback");
00070 
00071     switch (event) {
00072         case PAL_IMAGE_EVENT_INIT:
00073             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00074             break;
00075         case PAL_IMAGE_EVENT_PREPARE:
00076             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00077             break;
00078         case PAL_IMAGE_EVENT_WRITE:
00079             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE);
00080             break;
00081         case PAL_IMAGE_EVENT_FINALIZE:
00082             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE);
00083             break;
00084         case PAL_IMAGE_EVENT_READTOBUFFER:
00085             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE);
00086             break;
00087         case PAL_IMAGE_EVENT_ACTIVATE:
00088             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE);
00089             break;
00090         default:
00091             break;
00092     }
00093 }
00094 
00095 /**
00096  * @brief Initialize the underlying storage and set the callback handler.
00097  *
00098  * @param callback Function pointer to event handler.
00099  * @return Returns ERR_NONE on accept, and signals the event handler with
00100  *         either DONE or ERROR when complete.
00101  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00102  */
00103 arm_uc_error_t ARM_UC_Classic_PAL_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback)
00104 {
00105     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00106 
00107     if (callback) {
00108         palStatus_t status1 = pal_imageInitAPI(arm_uc_pal_classic_callback);
00109         arm_uc_error_t status2 = pal_ext_imageInitAPI(arm_uc_pal_classic_signal_callback);
00110 
00111         if ((status1 == PAL_SUCCESS) && (status2.error == ERR_NONE)) {
00112             arm_uc_pal_external_callback = callback;
00113             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00114 
00115             result.code = ERR_NONE;
00116         } else {
00117             result.code = ERR_NOT_READY;
00118         }
00119     }
00120 
00121     return result;
00122 }
00123 
00124 /**
00125  * @brief Get a bitmap indicating supported features.
00126  * @details The bitmap is used in conjunction with the firmware and
00127  *          installer details struct to indicate what fields are supported
00128  *          and which values are valid.
00129  *
00130  * @return Capability bitmap.
00131  */
00132 ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_Classic_PAL_GetCapabilities(void)
00133 {
00134     ARM_UC_PAAL_UPDATE_CAPABILITIES result = {
00135         .installer_arm_hash = 0,
00136         .installer_oem_hash = 0,
00137         .installer_layout   = 0,
00138         .firmware_hash      = 1,
00139         .firmware_hmac      = 0,
00140         .firmware_campaign  = 0,
00141         .firmware_version   = 1,
00142         .firmware_size      = 1
00143     };
00144 
00145     return result;
00146 }
00147 
00148 /**
00149  * @brief Get maximum number of supported storage locations.
00150  *
00151  * @return Number of storage locations.
00152  */
00153 uint32_t ARM_UC_Classic_PAL_GetMaxID(void)
00154 {
00155     return 1;
00156 }
00157 
00158 /**
00159  * @brief Prepare the storage layer for a new firmware image.
00160  * @details The storage location is set up to receive an image with
00161  *          the details passed in the details struct.
00162  *
00163  * @param location Storage location ID.
00164  * @param details Pointer to a struct with firmware details.
00165  * @param buffer Temporary buffer for formatting and storing metadata.
00166  * @return Returns ERR_NONE on accept, and signals the event handler with
00167  *         either DONE or ERROR when complete.
00168  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00169  */
00170 arm_uc_error_t ARM_UC_Classic_PAL_Prepare(uint32_t location,
00171                                           const arm_uc_firmware_details_t *details,
00172                                           arm_uc_buffer_t *buffer)
00173 {
00174     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00175 
00176     if (details && buffer) {
00177         /* encode firmware details in buffer */
00178         arm_uc_error_t header_status = arm_uc_create_external_header_v2(details,
00179                                                                         buffer);
00180 
00181         if (header_status.error == ERR_NONE) {
00182             /* format file name and path */
00183             char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 };
00184 
00185             arm_uc_error_t rv = arm_uc_pal_filesystem_get_path(location,
00186                                                     FIRMWARE_IMAGE_ITEM_HEADER,
00187                                                     file_path,
00188                                                     PAL_MAX_FILE_AND_FOLDER_LENGTH);
00189 
00190             if (rv.code == ERR_NONE) {
00191                 tr_debug("file_path: %s", file_path);
00192 
00193                 palFileDescriptor_t file = 0;
00194 
00195                 /* open file and get file handler */
00196                 palStatus_t status = pal_fsFopen(file_path,
00197                                                  PAL_FS_FLAG_READWRITETRUNC,
00198                                                  &file);
00199 
00200                 if (status == PAL_SUCCESS) {
00201                     size_t xfer_size = 0;
00202 
00203                     /* write buffer to file */
00204                     status = pal_fsFwrite(&file,
00205                                           buffer->ptr,
00206                                           buffer->size,
00207                                           &xfer_size);
00208 
00209                     tr_debug("written: %lu", (unsigned long)xfer_size);
00210 
00211                     /* call event hadnler and set return code if write was successful */
00212                     if ((status == PAL_SUCCESS) &&
00213                             (xfer_size == buffer->size)) {
00214                         result.code = ERR_NONE;
00215 
00216                         arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00217                     }
00218 
00219                     /* close file after write */
00220                     status = pal_fsFclose(&file);
00221 
00222                     if (status != PAL_SUCCESS) {
00223                         tr_error("pal_fsFclose failed: %" PRId32, status);
00224                     }
00225                 } else {
00226                     tr_error("pal_fsFopen failed: %" PRId32, status);
00227                 }
00228             } else {
00229                 tr_error("file name and path too long");
00230             }
00231         } else {
00232             tr_error("header too large for buffer");
00233         }
00234     }
00235 
00236     return result;
00237 }
00238 
00239 /**
00240  * @brief Write a fragment to the indicated storage location.
00241  * @details The storage location must have been allocated using the Prepare
00242  *          call. The call is expected to write the entire fragment before
00243  *          signaling completion.
00244  *
00245  * @param location Storage location ID.
00246  * @param offset Offset in bytes to where the fragment should be written.
00247  * @param buffer Pointer to buffer struct with fragment.
00248  * @return Returns ERR_NONE on accept, and signals the event handler with
00249  *         either DONE or ERROR when complete.
00250  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00251  */
00252 arm_uc_error_t ARM_UC_Classic_PAL_Write(uint32_t location,
00253                                         uint32_t offset,
00254                                         const arm_uc_buffer_t *buffer)
00255 {
00256     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00257 
00258     if (buffer) {
00259         palStatus_t status = pal_imageWrite(location,
00260                                             offset,
00261                                             (palConstBuffer_t *) buffer);
00262 
00263         if (status == PAL_SUCCESS) {
00264             result.code = ERR_NONE;
00265         } else {
00266             result.code = ERR_NOT_READY;
00267         }
00268     }
00269 
00270     return result;
00271 }
00272 
00273 /**
00274  * @brief Close storage location for writing and flush pending data.
00275  *
00276  * @param location Storage location ID.
00277  * @return Returns ERR_NONE on accept, and signals the event handler with
00278  *         either DONE or ERROR when complete.
00279  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00280  */
00281 arm_uc_error_t ARM_UC_Classic_PAL_Finalize(uint32_t location)
00282 {
00283     arm_uc_error_t result = { .code = ERR_NOT_READY };
00284 
00285     palStatus_t status = pal_imageFinalize(location);
00286 
00287     if (status == PAL_SUCCESS) {
00288         result.code = ERR_NONE;
00289     }
00290 
00291     return result;
00292 }
00293 
00294 /**
00295  * @brief Read a fragment from the indicated storage location.
00296  * @details The function will read until the buffer is full or the end of
00297  *          the storage location has been reached. The actual amount of
00298  *          bytes read is set in the buffer struct.
00299  *
00300  * @param location Storage location ID.
00301  * @param offset Offset in bytes to read from.
00302  * @param buffer Pointer to buffer struct to store fragment. buffer->size
00303  *        contains the intended read size.
00304  * @return Returns ERR_NONE on accept, and signals the event handler with
00305  *         either DONE or ERROR when complete.
00306  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00307  *         buffer->size contains actual bytes read on return.
00308  */
00309 arm_uc_error_t ARM_UC_Classic_PAL_Read(uint32_t location,
00310                                        uint32_t offset,
00311                                        arm_uc_buffer_t *buffer)
00312 {
00313     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00314 
00315     if (buffer) {
00316         palStatus_t status = pal_imageReadToBuffer(location,
00317                                                    offset,
00318                                                    (palBuffer_t *) buffer);
00319 
00320         if (status == PAL_SUCCESS) {
00321             tr_debug("pal_imageReadToBuffer succeeded: %" PRIX32, buffer->size);
00322             result.code = ERR_NONE;
00323         } else {
00324             tr_error("pal_imageReadToBuffer failed");
00325             result.code = ERR_NOT_READY;
00326         }
00327     }
00328 
00329     return result;
00330 }
00331 
00332 /**
00333  * @brief Set the firmware image in the slot to be the new active image.
00334  * @details This call is responsible for initiating the process for
00335  *          applying a new/different image. Depending on the platform this
00336  *          could be:
00337  *           * An empty call, if the installer can deduce which slot to
00338  *             choose from based on the firmware details.
00339  *           * Setting a flag to indicate which slot to use next.
00340  *           * Decompressing/decrypting/installing the firmware image on
00341  *             top of another.
00342  *
00343  * @param location Storage location ID.
00344  * @return Returns ERR_NONE on accept, and signals the event handler with
00345  *         either DONE or ERROR when complete.
00346  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00347  */
00348 arm_uc_error_t ARM_UC_Classic_PAL_Activate(uint32_t location)
00349 {
00350     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00351 
00352     result = pal_ext_imageActivate(location);
00353 
00354     return result;
00355 }
00356 
00357 /**
00358  * @brief Get firmware details for the actively running firmware.
00359  * @details This call populates the passed details struct with information
00360  *          about the currently active firmware image. Only the fields
00361  *          marked as supported in the capabilities bitmap will have valid
00362  *          values.
00363  *
00364  * @param details Pointer to firmware details struct to be populated.
00365  * @return Returns ERR_NONE on accept, and signals the event handler with
00366  *         either DONE or ERROR when complete.
00367  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00368  */
00369 arm_uc_error_t ARM_UC_Classic_PAL_GetActiveFirmwareDetails(arm_uc_firmware_details_t *details)
00370 {
00371     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00372 
00373     if (details) {
00374         result = pal_ext_imageGetActiveDetails(details);
00375     }
00376 
00377     return result;
00378 }
00379 
00380 /**
00381  * @brief Get firmware details for the firmware image in the slot passed.
00382  * @details This call populates the passed details struct with information
00383  *          about the firmware image in the slot passed. Only the fields
00384  *          marked as supported in the capabilities bitmap will have valid
00385  *          values.
00386  *
00387  * @param details Pointer to firmware details struct to be populated.
00388  * @return Returns ERR_NONE on accept, and signals the event handler with
00389  *         either DONE or ERROR when complete.
00390  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00391  */
00392 arm_uc_error_t ARM_UC_Classic_PAL_GetFirmwareDetails(uint32_t location,
00393                                                      arm_uc_firmware_details_t *details)
00394 {
00395     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00396 
00397     if (details) {
00398         char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH + 1] = { 0 };
00399 
00400         arm_uc_error_t rv = arm_uc_pal_filesystem_get_path(location,
00401                                                     FIRMWARE_IMAGE_ITEM_HEADER,
00402                                                     file_path,
00403                                                     PAL_MAX_FILE_AND_FOLDER_LENGTH);
00404 
00405         if (rv.code == ERR_NONE) {
00406             palFileDescriptor_t file = 0;
00407 
00408             /* open metadata header file if it exists */
00409             palStatus_t pal_rc = pal_fsFopen(file_path,
00410                                              PAL_FS_FLAG_READONLY,
00411                                              &file);
00412 
00413             if (pal_rc == PAL_SUCCESS) {
00414                 size_t xfer_size = 0;
00415 
00416                 /* read metadata header */
00417                 uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 };
00418 
00419                 pal_rc = pal_fsFread(&file,
00420                                      read_buffer,
00421                                      ARM_UC_EXTERNAL_HEADER_SIZE_V2,
00422                                      &xfer_size);
00423 
00424                 /* check return code */
00425                 if ((pal_rc == PAL_SUCCESS) &&
00426                         (xfer_size == ARM_UC_EXTERNAL_HEADER_SIZE_V2)) {
00427                     tr_debug("read bytes: %lu", (unsigned long)xfer_size);
00428 
00429                     /* read out header magic */
00430                     uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]);
00431 
00432                     /* read out header magic */
00433                     uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]);
00434 
00435                     /* choose version to decode */
00436                     if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) &&
00437                             (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2)) {
00438                         result = arm_uc_parse_external_header_v2(read_buffer, details);
00439 
00440                         tr_debug("version: %" PRIu64, details->version);
00441                         tr_debug("size: %"PRIu64, details->size);
00442 
00443                         if (result.error == ERR_NONE) {
00444                             arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE);
00445                         }
00446                     } else {
00447                         /* invalid header format */
00448                         tr_error("invalid header in slot %" PRIu32, location);
00449                     }
00450                 } else if (xfer_size != ARM_UC_EXTERNAL_HEADER_SIZE_V2) {
00451                     /* invalid header format */
00452                     tr_error("invalid header in slot %" PRIu32, location);
00453                 } else {
00454                     /* unsuccessful read */
00455                     tr_error("pal_fsFread returned 0x%" PRIX32, (uint32_t) pal_rc);
00456                 }
00457 
00458                 /* close file after use */
00459                 pal_rc = pal_fsFclose(&file);
00460 
00461                 if (pal_rc != PAL_SUCCESS) {
00462                     tr_error("pal_fsFclose failed: %" PRId32, pal_rc);
00463                 }
00464             } else {
00465                 /* header file not present, slot is either invalid or unused. */
00466                 result.code = ERR_NOT_READY;
00467             }
00468         }
00469     }
00470 
00471     return result;
00472 }
00473 
00474 /**
00475  * @brief Get details for the component responsible for installation.
00476  * @details This call populates the passed details struct with information
00477  *          about the local installer. Only the fields marked as supported
00478  *          in the capabilities bitmap will have valid values. The
00479  *          installer could be the bootloader, a recovery image, or some
00480  *          other component responsible for applying the new firmware
00481  *          image.
00482  *
00483  * @param details Pointer to installer details struct to be populated.
00484  * @return Returns ERR_NONE on accept, and signals the event handler with
00485  *         either DONE or ERROR when complete.
00486  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00487  */
00488 arm_uc_error_t ARM_UC_Classic_PAL_GetInstallerDetails(arm_uc_installer_details_t *details)
00489 {
00490     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00491 
00492     if (details) {
00493         result = pal_ext_installerGetDetails(details);
00494     }
00495 
00496     return result;
00497 }
00498 
00499 const ARM_UC_PAAL_UPDATE ARM_UCP_FILESYSTEM = {
00500     .Initialize                 = ARM_UC_Classic_PAL_Initialize,
00501     .GetCapabilities            = ARM_UC_Classic_PAL_GetCapabilities,
00502     .GetMaxID                   = ARM_UC_Classic_PAL_GetMaxID,
00503     .Prepare                    = ARM_UC_Classic_PAL_Prepare,
00504     .Write                      = ARM_UC_Classic_PAL_Write,
00505     .Finalize                   = ARM_UC_Classic_PAL_Finalize,
00506     .Read                       = ARM_UC_Classic_PAL_Read,
00507     .Activate                   = ARM_UC_Classic_PAL_Activate,
00508     .GetActiveFirmwareDetails   = ARM_UC_Classic_PAL_GetActiveFirmwareDetails,
00509     .GetFirmwareDetails         = ARM_UC_Classic_PAL_GetFirmwareDetails,
00510     .GetInstallerDetails        = ARM_UC_Classic_PAL_GetInstallerDetails
00511 };
00512 
00513 #endif /* ARM_UC_FEATURE_PAL_FILESYSTEM */