Simple interface for Mbed Cloud Client

Dependents:  

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 /* Calculate aligned external header size */
00074 #define ARM_UC_PAL_HEADER_SIZE (((ARM_UC_INTERNAL_HEADER_SIZE_V2 + MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE - 1)   \
00075                                 / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE)
00076 
00077 static void (*arm_uc_pal_flashiap_callback)(uint32_t) = NULL;
00078 
00079 static void arm_uc_pal_flashiap_signal_internal(uint32_t event)
00080 {
00081     if (arm_uc_pal_flashiap_callback)
00082     {
00083         arm_uc_pal_flashiap_callback(event);
00084     }
00085 }
00086 
00087 arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(void (*callback)(uint32_t))
00088 {
00089     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00090 
00091     int32_t status = arm_uc_flashiap_init();
00092 
00093     if (status == ARM_UC_FLASHIAP_SUCCESS)
00094     {
00095         arm_uc_pal_flashiap_callback = callback;
00096         arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_INITIALIZE_DONE);
00097 
00098         result.code = ERR_NONE;
00099     }
00100 
00101     return result;
00102 }
00103 
00104 /**
00105  * @brief Get maximum number of supported storage locations.
00106  *
00107  * @return Number of storage locations.
00108  */
00109 uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void)
00110 {
00111     return MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS;
00112 }
00113 
00114 /**
00115  * @brief Prepare the storage layer for a new firmware image.
00116  * @details The storage location is set up to receive an image with
00117  *          the details passed in the details struct.
00118  *
00119  * @param location Storage location ID.
00120  * @param details Pointer to a struct with firmware details.
00121  * @param buffer Temporary buffer for formatting and storing metadata.
00122  * @return Returns ERR_NONE on accept, and signals the event handler with
00123  *         either DONE or ERROR when complete.
00124  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00125  */
00126 arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t location,
00127                                            const arm_uc_firmware_details_t* details,
00128                                            arm_uc_buffer_t* buffer)
00129 {
00130     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00131 
00132     if (details && buffer && buffer->ptr)
00133     {
00134         UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Prepare: %" PRIX32 " %" PRIX32,
00135                  location, details->size);
00136 
00137         /* encode firmware details in buffer */
00138         result  = arm_uc_create_internal_header_v2(details, buffer);
00139 
00140         /* make space for new firmware */
00141         if (result.error == ERR_NONE)
00142         {
00143             /* find location start address */
00144             uint32_t slot_size = MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE /
00145                                  MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS;
00146             uint32_t start_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +
00147                                      location * slot_size;
00148 
00149             /* find end address */
00150             uint32_t end_address = start_address +
00151                                    ARM_UC_PAL_HEADER_SIZE +
00152                                    details->size;
00153 
00154             uint32_t erase_address = start_address;
00155 
00156             /* find exact erase size */
00157             while (erase_address < end_address)
00158             {
00159                 uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_address);
00160                 erase_address += sector_size;
00161             }
00162 
00163             if (erase_address > (start_address + slot_size))
00164             {
00165                 result.code = ERR_INVALID_PARAMETER;
00166                 UC_PAAL_ERR_MSG("Firmware too large");
00167             }
00168             else
00169             {
00170                 /* erase */
00171                 erase_address = start_address;
00172                 while (erase_address < end_address)
00173                 {
00174                     uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_address);
00175 
00176                     int32_t status = arm_uc_flashiap_erase(erase_address, sector_size);
00177 
00178                     UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32 " %" PRId32,
00179                              erase_address,
00180                              sector_size,
00181                              status);
00182 
00183                     if (status == ARM_UC_FLASHIAP_SUCCESS)
00184                     {
00185                         erase_address += sector_size;
00186                     }
00187                     else
00188                     {
00189                         result.code = ERR_INVALID_PARAMETER;
00190                         break;
00191                     }
00192                 }
00193             }
00194 
00195             if (result.error == ERR_NONE)
00196             {
00197                 UC_PAAL_TRACE("program: %" PRIX32 " %" PRIX32,
00198                          start_address,
00199                          ARM_UC_PAL_HEADER_SIZE);
00200 
00201                 uint32_t page_size = arm_uc_flashiap_get_page_size();
00202 
00203                 /* set default return code */
00204                 result.code = ERR_NONE;
00205 
00206                 for (uint32_t index = 0;
00207                      index < ARM_UC_PAL_HEADER_SIZE;
00208                      index += page_size)
00209                 {
00210                     /* write header */
00211                     int32_t status = arm_uc_flashiap_program(&buffer->ptr[index],
00212                                                              start_address + index,
00213                                                              page_size);
00214 
00215                     if (status != ARM_UC_FLASHIAP_SUCCESS)
00216                     {
00217                         /* set return code */
00218                         result.code = ERR_INVALID_PARAMETER;
00219                         break;
00220                     }
00221                 }
00222 
00223                 if (result.error == ERR_NONE)
00224                 {
00225                     /* signal done */
00226                     arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00227                 }
00228                 else
00229                 {
00230                     UC_PAAL_ERR_MSG("arm_uc_flashiap_program failed");
00231                 }
00232             }
00233             else
00234             {
00235                 UC_PAAL_ERR_MSG("arm_uc_flashiap_erase failed");
00236             }
00237         }
00238         else
00239         {
00240             UC_PAAL_ERR_MSG("arm_uc_create_internal_header_v2 failed");
00241         }
00242     }
00243 
00244     return result;
00245 }
00246 
00247 /**
00248  * @brief Write a fragment to the indicated storage location.
00249  * @details The storage location must have been allocated using the Prepare
00250  *          call. The call is expected to write the entire fragment before
00251  *          signaling completion.
00252  *
00253  * @param location Storage location ID.
00254  * @param offset Offset in bytes to where the fragment should be written.
00255  * @param buffer Pointer to buffer struct with fragment.
00256  * @return Returns ERR_NONE on accept, and signals the event handler with
00257  *         either DONE or ERROR when complete.
00258  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00259  */
00260 arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t location,
00261                                          uint32_t offset,
00262                                          const arm_uc_buffer_t* buffer)
00263 {
00264     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00265 
00266     if (buffer && buffer->ptr)
00267     {
00268         /* find location address */
00269         uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +
00270                                     (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE /
00271                                      MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) +
00272                                     ARM_UC_PAL_HEADER_SIZE +
00273                                     offset;
00274 
00275         UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32,
00276                  buffer->ptr,
00277                  buffer->size,
00278                  physical_address,
00279                  offset);
00280 
00281         /* set default return code */
00282         result.code = ERR_NONE;
00283 
00284         uint32_t page_size = arm_uc_flashiap_get_page_size();
00285 
00286         for (uint32_t index = 0; index < buffer->size; index += page_size)
00287         {
00288             int status = arm_uc_flashiap_program(&buffer->ptr[index],
00289                                                  physical_address + index,
00290                                                  page_size);
00291 
00292             if (status != ARM_UC_FLASHIAP_SUCCESS)
00293             {
00294                 /* set return code */
00295                 result.code = ERR_INVALID_PARAMETER;
00296                 break;
00297             }
00298         }
00299 
00300         if (result.error == ERR_NONE)
00301         {
00302             /* signal done */
00303             arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE);
00304         }
00305         else
00306         {
00307             UC_PAAL_ERR_MSG("arm_uc_flashiap_program failed");
00308         }
00309     }
00310 
00311     return result;
00312 }
00313 
00314 /**
00315  * @brief Close storage location for writing and flush pending data.
00316  *
00317  * @param location Storage location ID.
00318  * @return Returns ERR_NONE on accept, and signals the event handler with
00319  *         either DONE or ERROR when complete.
00320  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00321  */
00322 arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t location)
00323 {
00324     arm_uc_error_t result = { .code = ERR_NONE };
00325 
00326     UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Finalize");
00327 
00328     arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE);
00329 
00330     return result;
00331 }
00332 
00333 /**
00334  * @brief Read a fragment from the indicated storage location.
00335  * @details The function will read until the buffer is full or the end of
00336  *          the storage location has been reached. The actual amount of
00337  *          bytes read is set in the buffer struct.
00338  *
00339  * @param location Storage location ID.
00340  * @param offset Offset in bytes to read from.
00341  * @param buffer Pointer to buffer struct to store fragment. buffer->size
00342  *        contains the intended read size.
00343  * @return Returns ERR_NONE on accept, and signals the event handler with
00344  *         either DONE or ERROR when complete.
00345  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00346  *         buffer->size contains actual bytes read on return.
00347  */
00348 arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t location,
00349                                         uint32_t offset,
00350                                         arm_uc_buffer_t* buffer)
00351 {
00352     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00353 
00354     if (buffer && buffer->ptr)
00355     {
00356         UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Read: %" PRIX32 " %" PRIX32 " %" PRIX32,
00357                  location, offset, buffer->size);
00358 
00359         /* find location address */
00360         uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +
00361                                     (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE /
00362                                      MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) +
00363                                     ARM_UC_PAL_HEADER_SIZE +
00364                                     offset;
00365 
00366         uint32_t read_size = buffer->size;
00367 
00368         int status = arm_uc_flashiap_read(buffer->ptr,
00369                                           physical_address,
00370                                           read_size);
00371 
00372         if (status == ARM_UC_FLASHIAP_SUCCESS)
00373         {
00374             /* set return code */
00375             result.code = ERR_NONE;
00376 
00377             /* signal done */
00378             arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE);
00379         }
00380         else
00381         {
00382             UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed");
00383         }
00384     }
00385 
00386     return result;
00387 }
00388 
00389 /**
00390  * @brief Set the firmware image in the slot to be the new active image.
00391  * @details This call is responsible for initiating the process for
00392  *          applying a new/different image. Depending on the platform this
00393  *          could be:
00394  *           * An empty call, if the installer can deduce which slot to
00395  *             choose from based on the firmware details.
00396  *           * Setting a flag to indicate which slot to use next.
00397  *           * Decompressing/decrypting/installing the firmware image on
00398  *             top of another.
00399  *
00400  * @param location Storage location ID.
00401  * @return Returns ERR_NONE on accept, and signals the event handler with
00402  *         either DONE or ERROR when complete.
00403  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00404  */
00405 arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t location)
00406 {
00407     arm_uc_error_t result = { .code = ERR_NONE };
00408 
00409     UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Activate");
00410 
00411     arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE);
00412 
00413     return result;
00414 }
00415 
00416 /**
00417  * @brief Get firmware details for the firmware image in the slot passed.
00418  * @details This call populates the passed details struct with information
00419  *          about the firmware image in the slot passed. Only the fields
00420  *          marked as supported in the capabilities bitmap will have valid
00421  *          values.
00422  *
00423  * @param details Pointer to firmware details struct to be populated.
00424  * @return Returns ERR_NONE on accept, and signals the event handler with
00425  *         either DONE or ERROR when complete.
00426  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00427  */
00428 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails(
00429                                         uint32_t location,
00430                                         arm_uc_firmware_details_t* details)
00431 {
00432     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00433 
00434     if (details)
00435     {
00436         UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_GetFirmwareDetails");
00437 
00438         /* find location address */
00439         uint32_t physical_address = MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +
00440                                     (location * MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE /
00441                                      MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS);
00442 
00443         uint8_t buffer[ARM_UC_PAL_HEADER_SIZE] = { 0 };
00444 
00445         int status = arm_uc_flashiap_read(buffer,
00446                                           physical_address,
00447                                           ARM_UC_PAL_HEADER_SIZE);
00448 
00449         if (status == ARM_UC_FLASHIAP_SUCCESS)
00450         {
00451             result = arm_uc_parse_internal_header_v2(buffer, details);
00452 
00453             if (result.error == ERR_NONE)
00454             {
00455                 /* signal done */
00456                 arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE);
00457             }
00458             else
00459             {
00460                 UC_PAAL_ERR_MSG("arm_uc_parse_internal_header_v2 failed");
00461             }
00462         }
00463         else
00464         {
00465             UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed");
00466         }
00467     }
00468 
00469     return result;
00470 }
00471 
00472 /*****************************************************************************/
00473 
00474 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t* details)
00475 {
00476     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00477 
00478     if (details)
00479     {
00480         /* read details from memory if offset is set */
00481         if (MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS)
00482         {
00483             /* set default error code */
00484             result.code = ERR_NOT_READY;
00485 
00486             /* Use flash driver eventhough we are reading from internal flash.
00487                This will make it easier to use with uVisor.
00488              */
00489             uint8_t version_buffer[8] = { 0 };
00490 
00491             /* read metadata magic and version from flash */
00492             int rc = arm_uc_flashiap_read(version_buffer,
00493                                           MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS,
00494                                           8);
00495 
00496             if (rc == ARM_UC_FLASHIAP_SUCCESS)
00497             {
00498                 /* read out header magic */
00499                 uint32_t headerMagic = arm_uc_parse_uint32(&version_buffer[0]);
00500 
00501                 /* read out header magic */
00502                 uint32_t headerVersion = arm_uc_parse_uint32(&version_buffer[4]);
00503 
00504                 /* choose version to decode */
00505                 switch(headerVersion)
00506                 {
00507                     case ARM_UC_INTERNAL_HEADER_VERSION_V2:
00508                     {
00509                         result.code = ERR_NONE;
00510                         /* Check the header magic */
00511                         if (headerMagic != ARM_UC_INTERNAL_HEADER_MAGIC_V2)
00512                         {
00513                             UC_PAAL_ERR_MSG("firmware header is v2, but does not contain v2 magic");
00514                             result.code = ERR_NOT_READY;
00515                         }
00516 
00517                         uint8_t read_buffer[ARM_UC_INTERNAL_HEADER_SIZE_V2] = { 0 };
00518                         /* Read the rest of the header */
00519                         if (result.error == ERR_NONE)
00520                         {
00521                             rc = arm_uc_flashiap_read(read_buffer,
00522                                                       MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS,
00523                                                       ARM_UC_INTERNAL_HEADER_SIZE_V2);
00524                             if (rc != 0)
00525                             {
00526                                 result.code = ERR_NOT_READY;
00527                                 UC_PAAL_ERR_MSG("failed to read v2 header");
00528                             }
00529                         }
00530                         /* Parse the header */
00531                         if (result.error == ERR_NONE)
00532                         {
00533                             result = arm_uc_parse_internal_header_v2(read_buffer, details);
00534                             if (result.error != ERR_NONE)
00535                             {
00536                                 UC_PAAL_ERR_MSG("failed to parse v2 header");
00537                             }
00538                         }
00539                         break;
00540                     }
00541                     /*
00542                      * Other firmware header versions can be supported here.
00543                      */
00544                     default:
00545                     {
00546                         UC_PAAL_ERR_MSG("unrecognized firmware header version");
00547                         result.code = ERR_NOT_READY;
00548                     }
00549                 }
00550             }
00551             else
00552             {
00553                 UC_PAAL_ERR_MSG("flash read failed");
00554             }
00555         }
00556         else
00557         {
00558             /* offset not set - zero out struct */
00559             memset(details, 0, sizeof(arm_uc_firmware_details_t));
00560 
00561             result.code = ERR_NONE;
00562         }
00563 
00564         /* signal event if operation was successful */
00565         if (result.error == ERR_NONE)
00566         {
00567             UC_PAAL_TRACE("callback");
00568 
00569             arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE);
00570         }
00571     }
00572 
00573     return result;
00574 }
00575 
00576 arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t* details)
00577 {
00578     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00579 
00580     if (details)
00581     {
00582         /* only read from memory if offset is set */
00583         if (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS)
00584         {
00585             uint8_t* arm = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +
00586                 offsetof(arm_uc_installer_details_t, arm_hash));
00587 
00588             uint8_t* oem = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +
00589                 offsetof(arm_uc_installer_details_t, oem_hash));
00590 
00591             uint8_t* layout = (uint8_t*) (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +
00592                 offsetof(arm_uc_installer_details_t, layout));
00593 
00594             /* populate installer details struct */
00595             memcpy(&details->arm_hash, arm, ARM_UC_SHA256_SIZE);
00596             memcpy(&details->oem_hash, oem, ARM_UC_SHA256_SIZE);
00597             details->layout = arm_uc_parse_uint32(layout);
00598         }
00599         else
00600         {
00601             /* offset not set, zero details struct */
00602             memset(details, 0, sizeof(arm_uc_installer_details_t));
00603         }
00604 
00605         arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE);
00606 
00607         result.code = ERR_NONE;
00608     }
00609 
00610     return result;
00611 }
00612 
00613 #endif