Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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