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_linux_implementation.c Source File

arm_uc_pal_linux_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_IS_PC_LINUX)
00020 
00021 #include "update-client-pal-linux/arm_uc_pal_linux_implementation_internal.h"
00022 #include "update-client-pal-linux/arm_uc_pal_linux_implementation.h"
00023 #include "update-client-paal/arm_uc_paal_update_api.h"
00024 
00025 #include "update-client-common/arm_uc_trace.h"
00026 #include "update-client-common/arm_uc_utilities.h"
00027 #include "update-client-common/arm_uc_metadata_header_v2.h"
00028 
00029 #define __STDC_FORMAT_MACROS
00030 #include <inttypes.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033 #include <pthread.h>
00034 #include <stdlib.h>
00035 #include <sys/stat.h>
00036 #include <sys/wait.h>
00037 
00038 extern linux_worker_thread_info_t linux_worker_thread;
00039 
00040 /* worker struct, must be accessible externally */
00041 arm_ucp_worker_config_t arm_uc_worker_parameters = { 0 };
00042 
00043 static FILE* arm_uc_firmware_descriptor = NULL;
00044 
00045 static arm_uc_error_t spawn_thread(void *(*start_routine) (void *), void *arg)
00046 {
00047     arm_uc_error_t result = {ERR_NONE};
00048 
00049     /* Get the thread mutex. This prevents another thread from being spawned until this one completes.
00050        There should only ever be one thread at a time, since they are spawned via a single-threaded
00051        state machine, but this guarantees that there will only be one. */
00052     int status = pthread_mutex_trylock(&linux_worker_thread.mutex);
00053     if (status == EBUSY) {
00054         ARM_UC_SET_ERROR(result, ERR_NOT_READY);
00055     }
00056     else if (status != 0) {
00057         uint32_t code = (TWO_CC('P', 'T') << 16) | (status & 0xFFFF);
00058         ARM_UC_SET_ERROR(result, code);
00059     }
00060     /* Create "detached thread" attribute only once */
00061     if (result.error == ERR_NONE && linux_worker_thread.attr_initialized == 0)
00062     {
00063         if ((status = pthread_attr_init(&linux_worker_thread.attr)) != 0)
00064         {
00065             result.error = ERR_INVALID_PARAMETER;
00066             pthread_mutex_unlock(&linux_worker_thread.mutex);
00067         }
00068         else
00069         {
00070             if ((status = pthread_attr_setdetachstate(&linux_worker_thread.attr, PTHREAD_CREATE_DETACHED)) != 0)
00071             {
00072                 result.error = ERR_INVALID_PARAMETER;
00073                 pthread_mutex_unlock(&linux_worker_thread.mutex);
00074             }
00075             else
00076             {
00077                 linux_worker_thread.attr_initialized = 1;
00078             }
00079         }
00080     }
00081     if (result.error == ERR_NONE) {
00082         /* create a detached thread to execute the supplied routine */
00083         int status = pthread_create(&linux_worker_thread.thread,
00084                                     &linux_worker_thread.attr,
00085                                     start_routine,
00086                                     arg);
00087 
00088         /* check if thread was created successfully */
00089         if (status != 0)
00090         {
00091             result.code = ERR_INVALID_PARAMETER;
00092             pthread_mutex_unlock(&linux_worker_thread.mutex);
00093         }
00094     }
00095     return result;
00096 }
00097 
00098 /**
00099  * @brief Initialize the underlying storage and set the callback handler.
00100  *
00101  * @param callback Function pointer to event handler.
00102  * @return Returns ERR_NONE on accept, and signals the event handler with
00103  *         either DONE or ERROR when complete.
00104  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00105  */
00106 arm_uc_error_t ARM_UC_PAL_Linux_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback)
00107 {
00108     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00109 
00110     if (callback)
00111     {
00112         arm_uc_pal_linux_internal_set_callback(callback);
00113 
00114         /* create folder for headers if it does not already exist */
00115         errno = 0;
00116         int status = mkdir(ARM_UC_HEADER_FOLDER_PATH, 0700);
00117 
00118         if ((status == 0) || (errno == EEXIST))
00119         {
00120             /* create folder for firmwares if it does not already exist */
00121             errno = 0;
00122             status = mkdir(ARM_UC_FIRMWARE_FOLDER_PATH, 0700);
00123 
00124             if ((status == 0) || (errno == EEXIST))
00125             {
00126                 /* set return code on success */
00127                 result.code = ERR_NONE;
00128             }
00129         }
00130 
00131         /* signal completion or perform extended preparation */
00132         if (result.error == ERR_NONE)
00133         {
00134             /* set explicit ERR_NONE upon success */
00135             result.code = ERR_NONE;
00136 
00137             if (arm_uc_worker_parameters.initialize)
00138             {
00139                 /* use extended prepare, invoke script from worker thread */
00140 
00141                 /* create a second thread which executes worker_parameters_prepare */
00142                 result = spawn_thread(arm_uc_pal_linux_extended_post_worker,
00143                                       arm_uc_worker_parameters.initialize);
00144             }
00145             else
00146             {
00147                 /* call event handler */
00148                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE, false);
00149             }
00150         }
00151 
00152     }
00153 
00154     return result;
00155 }
00156 
00157 /**
00158  * @brief Get maximum number of supported storage locations.
00159  *
00160  * @return Number of storage locations.
00161  */
00162 uint32_t ARM_UC_PAL_Linux_GetMaxID(void)
00163 {
00164     return 1;
00165 }
00166 
00167 /**
00168  * @brief Prepare the storage layer for a new firmware image.
00169  * @details The storage location is set up to receive an image with
00170  *          the details passed in the details struct.
00171  *
00172  * @param location Storage location ID.
00173  * @param details Pointer to a struct with firmware details.
00174  * @param buffer Temporary buffer for formatting and storing metadata.
00175  * @return Returns ERR_NONE on accept, and signals the event handler with
00176  *         either DONE or ERROR when complete.
00177  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00178  */
00179 arm_uc_error_t ARM_UC_PAL_Linux_Prepare(uint32_t location,
00180                                         const arm_uc_firmware_details_t* details,
00181                                         arm_uc_buffer_t* buffer)
00182 {
00183     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00184 
00185     if (details && buffer)
00186     {
00187         UC_PAAL_TRACE("details size: %" PRIu64, details->size);
00188 
00189         /* write header */
00190         result = arm_uc_pal_linux_internal_write_header(&location, details);
00191 
00192         /* allocate space for firmware */
00193         if (result.error == ERR_NONE)
00194         {
00195             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00196 
00197             /* construct header file path */
00198             result = arm_uc_pal_linux_internal_file_path(file_path,
00199                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00200                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00201                                                          "firmware",
00202                                                          &location);
00203 
00204             UC_PAAL_TRACE("file path: %s", file_path);
00205 
00206             if (result.error == ERR_NONE)
00207             {
00208                 /* open file */
00209                 errno = 0;
00210                 FILE* descriptor = fopen(file_path, "wb");
00211 
00212                 if (descriptor != NULL)
00213                 {
00214                     /* allocate space by writing empty file */
00215                     memset(buffer->ptr, 0, buffer->size_max);
00216                     buffer->size = buffer->size_max;
00217 
00218                     uint64_t index = 0;
00219                     while (index < details->size)
00220                     {
00221                         /* calculate write size to handle overspill */
00222                         size_t actual_size = details->size - index;
00223 
00224                         if (actual_size > buffer->size)
00225                         {
00226                             actual_size = buffer->size;
00227                         }
00228 
00229                         /* write buffer */
00230                         size_t xfer_size = fwrite(buffer->ptr,
00231                                                   sizeof(uint8_t),
00232                                                   actual_size,
00233                                                   descriptor);
00234 
00235                         /* break out if write failed */
00236                         if (xfer_size == actual_size)
00237                         {
00238                             index += actual_size;
00239                         }
00240                         else
00241                         {
00242                             result.code = ERR_INVALID_PARAMETER;
00243                             break;
00244                         }
00245                     }
00246 
00247                     /* close file after write */
00248                     int status = fclose(descriptor);
00249 
00250                     if (status == EOF)
00251                     {
00252                         UC_PAAL_ERR_MSG("failed to allocate space for firmware");
00253                         result.code = ERR_INVALID_PARAMETER;
00254                     }
00255                 }
00256                 else
00257                 {
00258                     UC_PAAL_ERR_MSG("failed to open file: %s", strerror(errno));
00259                 }
00260             }
00261             else
00262             {
00263                 UC_PAAL_ERR_MSG("file name and path too long");
00264             }
00265         }
00266         else
00267         {
00268             UC_PAAL_ERR_MSG("could not write header");
00269         }
00270 
00271         /* signal completion or perform extended preparation */
00272         if (result.error == ERR_NONE)
00273         {
00274             /* set explicit ERR_NONE upon success */
00275             result.code = ERR_NONE;
00276 
00277             if (arm_uc_worker_parameters.prepare)
00278             {
00279                 /* use extended prepare, invoke script from worker thread */
00280                 /* export location */
00281                 arm_uc_pal_linux_internal_set_location(&location);
00282 
00283                 /* create a second thread which executes worker_parameters_prepare */
00284                 result = spawn_thread(arm_uc_pal_linux_extended_post_worker,
00285                                       arm_uc_worker_parameters.prepare);
00286             }
00287             else
00288             {
00289                 /* call event handler */
00290                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE, false);
00291             }
00292         }
00293     }
00294 
00295     return result;
00296 }
00297 
00298 /**
00299  * @brief Write a fragment to the indicated storage location.
00300  * @details The storage location must have been allocated using the Prepare
00301  *          call. The call is expected to write the entire fragment before
00302  *          signaling completion.
00303  *
00304  * @param location Storage location ID.
00305  * @param offset Offset in bytes to where the fragment should be written.
00306  * @param buffer Pointer to buffer struct with fragment.
00307  * @return Returns ERR_NONE on accept, and signals the event handler with
00308  *         either DONE or ERROR when complete.
00309  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00310  */
00311 arm_uc_error_t ARM_UC_PAL_Linux_Write(uint32_t location,
00312                                       uint32_t offset,
00313                                       const arm_uc_buffer_t* buffer)
00314 {
00315     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00316 
00317     if (buffer)
00318     {
00319         /* reverse default error code */
00320         result.code = ERR_NONE;
00321 
00322         /* open file if descriptor is not set */
00323         if (arm_uc_firmware_descriptor == NULL)
00324         {
00325             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00326 
00327             /* construct firmware file path */
00328             result = arm_uc_pal_linux_internal_file_path(file_path,
00329                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00330                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00331                                                          "firmware",
00332                                                          &location);
00333 
00334             if (result.error == ERR_NONE)
00335             {
00336                 /* open file */
00337                 if (arm_uc_worker_parameters.write)
00338                 {
00339                     /* in extended write, each fragment is stored in its own file */
00340                     arm_uc_firmware_descriptor = fopen(file_path, "w+b");
00341 
00342                     /* export offset before resetting it */
00343                     arm_uc_pal_linux_internal_set_offset(offset);
00344                     offset = 0;
00345                 }
00346                 else
00347                 {
00348                     /* in normal write, each fragment is added to an existing file */
00349                     arm_uc_firmware_descriptor = fopen(file_path, "r+b");
00350                 }
00351             }
00352             else
00353             {
00354                 UC_PAAL_ERR_MSG("firmware file name and path too long");
00355             }
00356         }
00357 
00358         /* continue if file is open */
00359         if (arm_uc_firmware_descriptor != NULL)
00360         {
00361             /* set write position */
00362             int status = fseek(arm_uc_firmware_descriptor,
00363                                offset,
00364                                SEEK_SET);
00365 
00366             /* continue if position is set */
00367             if (status == 0)
00368             {
00369                 /* write buffer */
00370                 size_t xfer_size = fwrite(buffer->ptr,
00371                                           sizeof(uint8_t),
00372                                           buffer->size,
00373                                           arm_uc_firmware_descriptor);
00374 
00375                 /* set error code if write failed */
00376                 if (xfer_size != buffer->size)
00377                 {
00378                     UC_PAAL_ERR_MSG("failed to write firmware");
00379                     result.code = ERR_INVALID_PARAMETER;
00380                 }
00381 
00382                 /* if using extended write */
00383                 if (arm_uc_worker_parameters.write)
00384                 {
00385                     /* close file after write */
00386                     int status = fclose(arm_uc_firmware_descriptor);
00387                     arm_uc_firmware_descriptor = NULL;
00388 
00389                     if (status == EOF)
00390                     {
00391                         UC_PAAL_ERR_MSG("failed to close firmware file");
00392                         result.code = ERR_INVALID_PARAMETER;
00393                     }
00394                 }
00395             }
00396             else
00397             {
00398                 UC_PAAL_ERR_MSG("failed to seek in firmware");
00399                 result.code = ERR_INVALID_PARAMETER;
00400             }
00401         }
00402 
00403         /* signal completion or perform extended write */
00404         if (result.error == ERR_NONE)
00405         {
00406             /* set explicit ERR_NONE */
00407             result.code = ERR_NONE;
00408 
00409             if (arm_uc_worker_parameters.write)
00410             {
00411                 /* use extended write, invoke script from worker thread */
00412                 /* export location */
00413                 arm_uc_pal_linux_internal_set_location(&location);
00414 
00415                 /* create a second thread which executes worker_parameters_write */
00416                 result = spawn_thread(arm_uc_pal_linux_extended_post_worker,
00417                                       arm_uc_worker_parameters.write);
00418             }
00419             else
00420             {
00421                 /* call event handler */
00422                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE, false);
00423             }
00424         }
00425     }
00426 
00427     return result;
00428 }
00429 
00430 /**
00431  * @brief Close storage location for writing and flush pending data.
00432  *
00433  * @param location Storage location ID.
00434  * @return Returns ERR_NONE on accept, and signals the event handler with
00435  *         either DONE or ERROR when complete.
00436  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00437  */
00438 arm_uc_error_t ARM_UC_PAL_Linux_Finalize(uint32_t location)
00439 {
00440     arm_uc_error_t result = { .code = ERR_NONE };
00441 
00442     /* only close firmware file if descriptor is not NULL */
00443     if (arm_uc_firmware_descriptor != NULL)
00444     {
00445         /* close file */
00446         int status = fclose(arm_uc_firmware_descriptor);
00447         arm_uc_firmware_descriptor = NULL;
00448 
00449         if (status == EOF)
00450         {
00451             UC_PAAL_ERR_MSG("failed to close firmware file");
00452             result.code = ERR_INVALID_PARAMETER;
00453         }
00454     }
00455 
00456     /* signal completion or perform extended finalization */
00457     if (result.error == ERR_NONE)
00458     {
00459         /* explicitly set code to ERR_NONE */
00460         result.code = ERR_NONE;
00461 
00462         /* use extended finalize, invoke script from worker thread */
00463         if (arm_uc_worker_parameters.finalize)
00464         {
00465             /* export location */
00466             arm_uc_pal_linux_internal_set_location(&location);
00467 
00468             /* create a second thread which executes worker_parameters_finalize */
00469             result = spawn_thread(arm_uc_pal_linux_extended_post_worker,
00470                                   arm_uc_worker_parameters.finalize);
00471         }
00472         else
00473         {
00474             /* call event handler */
00475             arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE, false);
00476         }
00477     }
00478 
00479     return result;
00480 }
00481 
00482 /**
00483  * @brief Read a fragment from the indicated storage location.
00484  * @details The function will read until the buffer is full or the end of
00485  *          the storage location has been reached. The actual amount of
00486  *          bytes read is set in the buffer struct.
00487  *
00488  * @param location Storage location ID.
00489  * @param offset Offset in bytes to read from.
00490  * @param buffer Pointer to buffer struct to store fragment. buffer->size
00491  *        contains the intended read size.
00492  * @return Returns ERR_NONE on accept, and signals the event handler with
00493  *         either DONE or ERROR when complete.
00494  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00495  *         buffer->size contains actual bytes read on return.
00496  */
00497 arm_uc_error_t ARM_UC_PAL_Linux_Read(uint32_t location,
00498                                      uint32_t offset,
00499                                      arm_uc_buffer_t* buffer)
00500 {
00501     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00502 
00503     if (buffer)
00504     {
00505         /* use extended finalize, invoke script from worker thread */
00506         if (arm_uc_worker_parameters.read)
00507         {
00508             /* export location, offset and buffer */
00509             arm_uc_pal_linux_internal_set_location(&location);
00510             arm_uc_pal_linux_internal_set_offset(offset);
00511             arm_uc_pal_linux_internal_set_buffer(buffer);
00512 
00513             /* create a second thread which executes worker_parameters_read */
00514             result = spawn_thread(arm_uc_pal_linux_extended_pre_worker,
00515                                   arm_uc_worker_parameters.read);
00516         }
00517         else
00518         {
00519             /* normal read */
00520             char file_path[ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH] = { 0 };
00521 
00522             /* construct firmware file path */
00523             result = arm_uc_pal_linux_internal_file_path(file_path,
00524                                                          ARM_UC_MAXIMUM_FILE_AND_PATH_LENGTH,
00525                                                          ARM_UC_FIRMWARE_FOLDER_PATH,
00526                                                          "firmware",
00527                                                          &location);
00528 
00529             /* file path is valid */
00530             if (result.error == ERR_NONE)
00531             {
00532                 result = arm_uc_pal_linux_internal_read(file_path, offset, buffer);
00533 
00534                 /* signal completion */
00535                 if (result.error == ERR_NONE)
00536                 {
00537                     /* call event handler */
00538                     arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE, false);
00539                 }
00540             }
00541         }
00542     }
00543 
00544     return result;
00545 }
00546 
00547 /**
00548  * @brief Set the firmware image in the slot to be the new active image.
00549  * @details This call is responsible for initiating the process for
00550  *          applying a new/different image. Depending on the platform this
00551  *          could be:
00552  *           * An empty call, if the installer can deduce which slot to
00553  *             choose from based on the firmware details.
00554  *           * Setting a flag to indicate which slot to use next.
00555  *           * Decompressing/decrypting/installing the firmware image on
00556  *             top of another.
00557  *
00558  * @param location Storage location ID.
00559  * @return Returns ERR_NONE on accept, and signals the event handler with
00560  *         either DONE or ERROR when complete.
00561  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00562  */
00563 arm_uc_error_t ARM_UC_PAL_Linux_Activate(uint32_t location)
00564 {
00565     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00566 
00567     /* read firmware details from location */
00568     arm_uc_firmware_details_t details = { 0 };
00569     result = arm_uc_pal_linux_internal_read_header(&location, &details);
00570 
00571     if (result.error == ERR_NONE)
00572     {
00573         UC_PAAL_TRACE("version: %" PRIu64, details.version);
00574         UC_PAAL_TRACE("size: %"PRIu64, details.size);
00575 
00576         /* write details to active location */
00577         result = arm_uc_pal_linux_internal_write_header(NULL, &details);
00578 
00579         if (result.error == ERR_NONE)
00580         {
00581             /* explicitly set code to ERR_NONE */
00582             result.code = ERR_NONE;
00583 
00584             /* use extended activate, invoke script from worker thread */
00585             if (arm_uc_worker_parameters.activate)
00586             {
00587                 /* export location */
00588                 arm_uc_pal_linux_internal_set_location(&location);
00589 
00590                 /* create a second thread which executes worker_parameters_read */
00591                 result = spawn_thread(arm_uc_pal_linux_extended_post_worker,
00592                                       arm_uc_worker_parameters.activate);
00593             }
00594             else
00595             {
00596                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE, false);
00597             }
00598         }
00599     }
00600 
00601     return result;
00602 }
00603 
00604 /**
00605  * @brief Get firmware details for the actively running firmware.
00606  * @details This call populates the passed details struct with information
00607  *          about the currently active firmware image. Only the fields
00608  *          marked as supported in the capabilities bitmap will have valid
00609  *          values.
00610  *
00611  * @param details Pointer to firmware details struct to be populated.
00612  * @return Returns ERR_NONE on accept, and signals the event handler with
00613  *         either DONE or ERROR when complete.
00614  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00615  */
00616 arm_uc_error_t ARM_UC_PAL_Linux_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details)
00617 {
00618     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00619 
00620     if (details)
00621     {
00622         /* use extended get firmware details, invoke script from worker thread */
00623         if (arm_uc_worker_parameters.active_details)
00624         {
00625             /* export details */
00626             arm_uc_pal_linux_internal_set_details(details);
00627 
00628             /* create a second thread which executes worker_parameters_read */
00629             result = spawn_thread(arm_uc_pal_linux_extended_pre_worker,
00630                                   arm_uc_worker_parameters.active_details);
00631 
00632         }
00633         else
00634         {
00635             /* normal read */
00636             result = arm_uc_pal_linux_internal_read_header(NULL, details);
00637 
00638             if (result.error == ERR_NONE)
00639             {
00640                 UC_PAAL_TRACE("version: %" PRIu64, details->version);
00641                 UC_PAAL_TRACE("size: %"PRIu64, details->size);
00642 
00643                 if (result.error == ERR_NONE)
00644                 {
00645                     arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, false);
00646                 }
00647             }
00648         }
00649     }
00650 
00651     return result;
00652 }
00653 
00654 /**
00655  * @brief Get firmware details for the firmware image in the slot passed.
00656  * @details This call populates the passed details struct with information
00657  *          about the firmware image in the slot passed. Only the fields
00658  *          marked as supported in the capabilities bitmap will have valid
00659  *          values.
00660  *
00661  * @param details Pointer to firmware details struct to be populated.
00662  * @return Returns ERR_NONE on accept, and signals the event handler with
00663  *         either DONE or ERROR when complete.
00664  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00665  */
00666 arm_uc_error_t ARM_UC_PAL_Linux_GetFirmwareDetails(uint32_t location,
00667                                                    arm_uc_firmware_details_t* details)
00668 {
00669     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00670 
00671     if (details)
00672     {
00673         /* use extended get firmware details, invoke script from worker thread */
00674         if (arm_uc_worker_parameters.details)
00675         {
00676             /* export location and details */
00677             arm_uc_pal_linux_internal_set_location(&location);
00678             arm_uc_pal_linux_internal_set_details(details);
00679 
00680             /* create a second thread which executes worker_parameters_read */
00681             result = spawn_thread(arm_uc_pal_linux_extended_pre_worker,
00682                                   arm_uc_worker_parameters.details);
00683         }
00684         else
00685         {
00686             /* normal read */
00687             result = arm_uc_pal_linux_internal_read_header(&location, details);
00688 
00689             if (result.error == ERR_NONE)
00690             {
00691                 UC_PAAL_TRACE("version: %" PRIu64, details->version);
00692                 UC_PAAL_TRACE("size: %"PRIu64, details->size);
00693 
00694                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, false);
00695             }
00696         }
00697     }
00698 
00699     return result;
00700 }
00701 
00702 /**
00703  * @brief Get details for the component responsible for installation.
00704  * @details This call populates the passed details struct with information
00705  *          about the local installer. Only the fields marked as supported
00706  *          in the capabilities bitmap will have valid values. The
00707  *          installer could be the bootloader, a recovery image, or some
00708  *          other component responsible for applying the new firmware
00709  *          image.
00710  *
00711  * @param details Pointer to installer details struct to be populated.
00712  * @return Returns ERR_NONE on accept, and signals the event handler with
00713  *         either DONE or ERROR when complete.
00714  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00715  */
00716 arm_uc_error_t ARM_UC_PAL_Linux_GetInstallerDetails(arm_uc_installer_details_t* details)
00717 {
00718     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00719 
00720     if (details)
00721     {
00722         /* use extended installer details, invoke script from worker thread */
00723         if (arm_uc_worker_parameters.installer)
00724         {
00725             /* export installer details */
00726             arm_uc_pal_linux_internal_set_installer(details);
00727 
00728             /* create a second thread which executes worker_parameters_read */
00729             result = spawn_thread(arm_uc_pal_linux_extended_pre_worker,
00730                                   arm_uc_worker_parameters.installer);
00731         }
00732         else
00733         {
00734             /* normal read */
00735             result = arm_uc_pal_linux_internal_read_installer(details);
00736 
00737             if (result.error == ERR_NONE)
00738             {
00739                 arm_uc_pal_linux_signal_callback(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, false);
00740             }
00741         }
00742     }
00743 
00744     return result;
00745 }
00746 
00747 #endif