leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_pal_flashiap_implementation.c Source File

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 */