Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
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); 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); 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); 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); 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); 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); 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); 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); 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); 00740 } 00741 } 00742 } 00743 00744 return result; 00745 } 00746 00747 #endif
Generated on Tue Jul 12 2022 19:01:33 by 1.7.2