Simple interface for Mbed Cloud Client
Embed:
(wiki syntax)
Show/hide line numbers
arm_uc_paal_classic_pal.c
00001 // ---------------------------------------------------------------------------- 00002 // Copyright 2016-2017 ARM Ltd. 00003 // 00004 // SPDX-License-Identifier: Apache-2.0 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); 00007 // you may not use this file except in compliance with the License. 00008 // You may obtain a copy of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, 00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 // See the License for the specific language governing permissions and 00016 // limitations under the License. 00017 // ---------------------------------------------------------------------------- 00018 00019 #include "update-client-paal/arm_uc_paal_update_api.h" 00020 00021 #include "update-client-pal-filesystem/arm_uc_pal_extensions.h" 00022 #include "update-client-common/arm_uc_utilities.h" 00023 #include "update-client-common/arm_uc_metadata_header_v2.h" 00024 #include "arm_uc_pal_filesystem_utils.h" 00025 00026 #include "pal.h" 00027 00028 #include "mbed-trace/mbed_trace.h" 00029 #define TRACE_GROUP "UCPI" 00030 00031 #include <stdio.h> 00032 00033 #define ARM_UC_FIRMWARE_FOLDER_NAME "firmware" 00034 00035 /* pointer to external callback handler */ 00036 static ARM_UC_PAAL_UPDATE_SignalEvent_t arm_uc_pal_external_callback = NULL; 00037 00038 static void arm_uc_pal_classic_signal_callback(uint32_t event) 00039 { 00040 if (arm_uc_pal_external_callback) 00041 { 00042 arm_uc_pal_external_callback(event); 00043 } 00044 } 00045 00046 static void arm_uc_pal_classic_callback(palImageEvents_t event) 00047 { 00048 /* 00049 ARM_UC_PAAL_EVENT_INITIALIZE_DONE, 00050 ARM_UC_PAAL_EVENT_PREPARE_DONE, 00051 ARM_UC_PAAL_EVENT_WRITE_DONE, 00052 ARM_UC_PAAL_EVENT_FINALIZE_DONE, 00053 ARM_UC_PAAL_EVENT_READ_DONE, 00054 ARM_UC_PAAL_EVENT_ACTIVATE_DONE, 00055 ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, 00056 ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, 00057 ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, 00058 ARM_UC_PAAL_EVENT_INITIALIZE_ERROR, 00059 ARM_UC_PAAL_EVENT_PREPARE_ERROR, 00060 ARM_UC_PAAL_EVENT_WRITE_ERROR, 00061 ARM_UC_PAAL_EVENT_FINALIZE_ERROR, 00062 ARM_UC_PAAL_EVENT_READ_ERROR, 00063 ARM_UC_PAAL_EVENT_ACTIVATE_ERROR, 00064 ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR, 00065 ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR, 00066 ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR, 00067 */ 00068 tr_debug("arm_uc_pal_classic_callback"); 00069 00070 switch (event) 00071 { 00072 case PAL_IMAGE_EVENT_INIT: 00073 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); 00074 break; 00075 case PAL_IMAGE_EVENT_PREPARE: 00076 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE); 00077 break; 00078 case PAL_IMAGE_EVENT_WRITE: 00079 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_WRITE_DONE); 00080 break; 00081 case PAL_IMAGE_EVENT_FINALIZE: 00082 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_FINALIZE_DONE); 00083 break; 00084 case PAL_IMAGE_EVENT_READTOBUFFER: 00085 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_READ_DONE); 00086 break; 00087 case PAL_IMAGE_EVENT_ACTIVATE: 00088 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); 00089 break; 00090 default: 00091 break; 00092 } 00093 } 00094 00095 /** 00096 * @brief Initialize the underlying storage and set the callback handler. 00097 * 00098 * @param callback Function pointer to event handler. 00099 * @return Returns ERR_NONE on accept, and signals the event handler with 00100 * either DONE or ERROR when complete. 00101 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00102 */ 00103 arm_uc_error_t ARM_UC_Classic_PAL_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) 00104 { 00105 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00106 00107 if (callback) 00108 { 00109 palStatus_t status1 = pal_imageInitAPI(arm_uc_pal_classic_callback); 00110 arm_uc_error_t status2 = pal_ext_imageInitAPI(arm_uc_pal_classic_signal_callback); 00111 00112 if ((status1 == PAL_SUCCESS) && (status2.error == ERR_NONE)) 00113 { 00114 arm_uc_pal_external_callback = callback; 00115 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); 00116 00117 result.code = ERR_NONE; 00118 } 00119 else 00120 { 00121 result.code = ERR_NOT_READY; 00122 } 00123 } 00124 00125 return result; 00126 } 00127 00128 /** 00129 * @brief Get a bitmap indicating supported features. 00130 * @details The bitmap is used in conjunction with the firmware and 00131 * installer details struct to indicate what fields are supported 00132 * and which values are valid. 00133 * 00134 * @return Capability bitmap. 00135 */ 00136 ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_Classic_PAL_GetCapabilities(void) 00137 { 00138 ARM_UC_PAAL_UPDATE_CAPABILITIES result = { 00139 .installer_arm_hash = 0, 00140 .installer_oem_hash = 0, 00141 .installer_layout = 0, 00142 .firmware_hash = 1, 00143 .firmware_hmac = 0, 00144 .firmware_campaign = 0, 00145 .firmware_version = 1, 00146 .firmware_size = 1 00147 }; 00148 00149 return result; 00150 } 00151 00152 /** 00153 * @brief Get maximum number of supported storage locations. 00154 * 00155 * @return Number of storage locations. 00156 */ 00157 uint32_t ARM_UC_Classic_PAL_GetMaxID(void) 00158 { 00159 return 1; 00160 } 00161 00162 /** 00163 * @brief Prepare the storage layer for a new firmware image. 00164 * @details The storage location is set up to receive an image with 00165 * the details passed in the details struct. 00166 * 00167 * @param location Storage location ID. 00168 * @param details Pointer to a struct with firmware details. 00169 * @param buffer Temporary buffer for formatting and storing metadata. 00170 * @return Returns ERR_NONE on accept, and signals the event handler with 00171 * either DONE or ERROR when complete. 00172 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00173 */ 00174 arm_uc_error_t ARM_UC_Classic_PAL_Prepare(uint32_t location, 00175 const arm_uc_firmware_details_t* details, 00176 arm_uc_buffer_t* buffer) 00177 { 00178 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00179 00180 if (details && buffer) 00181 { 00182 /* encode firmware details in buffer */ 00183 arm_uc_error_t header_status = arm_uc_create_external_header_v2(details, 00184 buffer); 00185 00186 if (header_status.error == ERR_NONE) 00187 { 00188 /* format file name and path */ 00189 char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH] = { 0 }; 00190 00191 result = arm_uc_pal_filesystem_get_path(location, 00192 FIRMWARE_IMAGE_ITEM_HEADER, 00193 file_path, 00194 PAL_MAX_FILE_AND_FOLDER_LENGTH); 00195 00196 if (result.code == ERR_NONE) 00197 { 00198 tr_debug("file_path: %s", file_path); 00199 00200 palFileDescriptor_t file = 0; 00201 00202 /* open file and get file handler */ 00203 palStatus_t status = pal_fsFopen(file_path, 00204 PAL_FS_FLAG_READWRITETRUNC, 00205 &file); 00206 00207 if (status == PAL_SUCCESS) 00208 { 00209 size_t xfer_size = 0; 00210 00211 /* write buffer to file */ 00212 status = pal_fsFwrite(&file, 00213 buffer->ptr, 00214 buffer->size, 00215 &xfer_size); 00216 00217 tr_debug("written: %lu", (unsigned long)xfer_size); 00218 00219 /* call event hadnler and set return code if write was successful */ 00220 if ((status == PAL_SUCCESS) && 00221 (xfer_size == buffer->size)) 00222 { 00223 result.code = ERR_NONE; 00224 00225 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_PREPARE_DONE); 00226 } 00227 00228 /* close file after write */ 00229 status = pal_fsFclose(&file); 00230 00231 if (status != PAL_SUCCESS) 00232 { 00233 tr_error("pal_fsFclose failed: %" PRId32, status); 00234 } 00235 } 00236 else 00237 { 00238 tr_error("pal_fsFopen failed: %" PRId32, status); 00239 } 00240 } 00241 else 00242 { 00243 tr_error("file name and path too long"); 00244 } 00245 } 00246 else 00247 { 00248 tr_error("header too large for buffer"); 00249 } 00250 } 00251 00252 return result; 00253 } 00254 00255 /** 00256 * @brief Write a fragment to the indicated storage location. 00257 * @details The storage location must have been allocated using the Prepare 00258 * call. The call is expected to write the entire fragment before 00259 * signaling completion. 00260 * 00261 * @param location Storage location ID. 00262 * @param offset Offset in bytes to where the fragment should be written. 00263 * @param buffer Pointer to buffer struct with fragment. 00264 * @return Returns ERR_NONE on accept, and signals the event handler with 00265 * either DONE or ERROR when complete. 00266 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00267 */ 00268 arm_uc_error_t ARM_UC_Classic_PAL_Write(uint32_t location, 00269 uint32_t offset, 00270 const arm_uc_buffer_t* buffer) 00271 { 00272 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00273 00274 if (buffer) 00275 { 00276 palStatus_t status = pal_imageWrite(location, 00277 offset, 00278 (palConstBuffer_t*) buffer); 00279 00280 if (status == PAL_SUCCESS) 00281 { 00282 result.code = ERR_NONE; 00283 } 00284 else 00285 { 00286 result.code = ERR_NOT_READY; 00287 } 00288 } 00289 00290 return result; 00291 } 00292 00293 /** 00294 * @brief Close storage location for writing and flush pending data. 00295 * 00296 * @param location Storage location ID. 00297 * @return Returns ERR_NONE on accept, and signals the event handler with 00298 * either DONE or ERROR when complete. 00299 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00300 */ 00301 arm_uc_error_t ARM_UC_Classic_PAL_Finalize(uint32_t location) 00302 { 00303 arm_uc_error_t result = { .code = ERR_NOT_READY }; 00304 00305 palStatus_t status = pal_imageFinalize(location); 00306 00307 if (status == PAL_SUCCESS) 00308 { 00309 result.code = ERR_NONE; 00310 } 00311 00312 return result; 00313 } 00314 00315 /** 00316 * @brief Read a fragment from the indicated storage location. 00317 * @details The function will read until the buffer is full or the end of 00318 * the storage location has been reached. The actual amount of 00319 * bytes read is set in the buffer struct. 00320 * 00321 * @param location Storage location ID. 00322 * @param offset Offset in bytes to read from. 00323 * @param buffer Pointer to buffer struct to store fragment. buffer->size 00324 * contains the intended read size. 00325 * @return Returns ERR_NONE on accept, and signals the event handler with 00326 * either DONE or ERROR when complete. 00327 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00328 * buffer->size contains actual bytes read on return. 00329 */ 00330 arm_uc_error_t ARM_UC_Classic_PAL_Read(uint32_t location, 00331 uint32_t offset, 00332 arm_uc_buffer_t* buffer) 00333 { 00334 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00335 00336 if (buffer) 00337 { 00338 palStatus_t status = pal_imageReadToBuffer(location, 00339 offset, 00340 (palBuffer_t*) buffer); 00341 00342 if (status == PAL_SUCCESS) 00343 { 00344 tr_debug("pal_imageReadToBuffer succeeded: %" PRIX32, buffer->size); 00345 result.code = ERR_NONE; 00346 } 00347 else 00348 { 00349 tr_error("pal_imageReadToBuffer failed"); 00350 result.code = ERR_NOT_READY; 00351 } 00352 } 00353 00354 return result; 00355 } 00356 00357 /** 00358 * @brief Set the firmware image in the slot to be the new active image. 00359 * @details This call is responsible for initiating the process for 00360 * applying a new/different image. Depending on the platform this 00361 * could be: 00362 * * An empty call, if the installer can deduce which slot to 00363 * choose from based on the firmware details. 00364 * * Setting a flag to indicate which slot to use next. 00365 * * Decompressing/decrypting/installing the firmware image on 00366 * top of another. 00367 * 00368 * @param location Storage location ID. 00369 * @return Returns ERR_NONE on accept, and signals the event handler with 00370 * either DONE or ERROR when complete. 00371 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00372 */ 00373 arm_uc_error_t ARM_UC_Classic_PAL_Activate(uint32_t location) 00374 { 00375 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00376 00377 result = pal_ext_imageActivate(location); 00378 00379 return result; 00380 } 00381 00382 /** 00383 * @brief Get firmware details for the actively running firmware. 00384 * @details This call populates the passed details struct with information 00385 * about the currently active firmware image. Only the fields 00386 * marked as supported in the capabilities bitmap will have valid 00387 * values. 00388 * 00389 * @param details Pointer to firmware details struct to be populated. 00390 * @return Returns ERR_NONE on accept, and signals the event handler with 00391 * either DONE or ERROR when complete. 00392 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00393 */ 00394 arm_uc_error_t ARM_UC_Classic_PAL_GetActiveFirmwareDetails(arm_uc_firmware_details_t* details) 00395 { 00396 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00397 00398 if (details) 00399 { 00400 result = pal_ext_imageGetActiveDetails(details); 00401 } 00402 00403 return result; 00404 } 00405 00406 /** 00407 * @brief Get firmware details for the firmware image in the slot passed. 00408 * @details This call populates the passed details struct with information 00409 * about the firmware image in the slot passed. Only the fields 00410 * marked as supported in the capabilities bitmap will have valid 00411 * values. 00412 * 00413 * @param details Pointer to firmware details struct to be populated. 00414 * @return Returns ERR_NONE on accept, and signals the event handler with 00415 * either DONE or ERROR when complete. 00416 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00417 */ 00418 arm_uc_error_t ARM_UC_Classic_PAL_GetFirmwareDetails(uint32_t location, 00419 arm_uc_firmware_details_t* details) 00420 { 00421 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00422 00423 if (details) 00424 { 00425 char file_path[PAL_MAX_FILE_AND_FOLDER_LENGTH+1] = { 0 }; 00426 00427 palStatus_t status = pal_fsGetMountPoint(PAL_FS_PARTITION_PRIMARY, 00428 PAL_MAX_FILE_AND_FOLDER_LENGTH, 00429 file_path); 00430 00431 if (status == PAL_SUCCESS) 00432 { 00433 /* keep track of file and folder length */ 00434 /* add mount point name length */ 00435 int length = arm_uc_strnlen((const uint8_t *)file_path, PAL_MAX_FILE_AND_FOLDER_LENGTH); 00436 00437 /* add slash if needed */ 00438 if (( length == 0) || 00439 ((length < PAL_MAX_FILE_AND_FOLDER_LENGTH) && 00440 (file_path[length - 1] != '/'))) 00441 { 00442 file_path[length] = '/'; 00443 file_path[++length] = 0; 00444 } 00445 00446 00447 /* check that path didn't overrun */ 00448 if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH) 00449 { 00450 /* start snprintf after the mount point name and add length */ 00451 length += snprintf(&file_path[length], 00452 PAL_MAX_FILE_AND_FOLDER_LENGTH - length, 00453 ARM_UC_FIRMWARE_FOLDER_NAME "/header_%" PRIu32 ".bin", 00454 location); 00455 00456 /* check that file path didn't overrun */ 00457 if (length < PAL_MAX_FILE_AND_FOLDER_LENGTH) 00458 { 00459 tr_debug("file_path: %d %s", length, file_path); 00460 00461 palFileDescriptor_t file = 0; 00462 00463 /* open metadata header file if it exists */ 00464 palStatus_t pal_rc = pal_fsFopen(file_path, 00465 PAL_FS_FLAG_READONLY, 00466 &file); 00467 00468 if (pal_rc == PAL_SUCCESS) 00469 { 00470 size_t xfer_size = 0; 00471 00472 /* read metadata header */ 00473 uint8_t read_buffer[ARM_UC_EXTERNAL_HEADER_SIZE_V2] = { 0 }; 00474 00475 pal_rc = pal_fsFread(&file, 00476 read_buffer, 00477 ARM_UC_EXTERNAL_HEADER_SIZE_V2, 00478 &xfer_size); 00479 00480 /* check return code */ 00481 if ((pal_rc == PAL_SUCCESS) && 00482 (xfer_size == ARM_UC_EXTERNAL_HEADER_SIZE_V2)) 00483 { 00484 tr_debug("read bytes: %lu", (unsigned long)xfer_size); 00485 00486 /* read out header magic */ 00487 uint32_t headerMagic = arm_uc_parse_uint32(&read_buffer[0]); 00488 00489 /* read out header magic */ 00490 uint32_t headerVersion = arm_uc_parse_uint32(&read_buffer[4]); 00491 00492 /* choose version to decode */ 00493 if ((headerMagic == ARM_UC_EXTERNAL_HEADER_MAGIC_V2) && 00494 (headerVersion == ARM_UC_EXTERNAL_HEADER_VERSION_V2)) 00495 { 00496 result = arm_uc_parse_external_header_v2(read_buffer, details); 00497 00498 tr_debug("version: %" PRIu64, details->version); 00499 tr_debug("size: %"PRIu64, details->size); 00500 00501 if (result.error == ERR_NONE) 00502 { 00503 arm_uc_pal_classic_signal_callback(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); 00504 } 00505 } 00506 else 00507 { 00508 /* invalid header format */ 00509 tr_error("invalid header in slot %" PRIu32, location); 00510 } 00511 } 00512 else if (xfer_size != ARM_UC_EXTERNAL_HEADER_SIZE_V2) 00513 { 00514 /* invalid header format */ 00515 tr_error("invalid header in slot %" PRIu32, location); 00516 } 00517 else 00518 { 00519 /* unsuccessful read */ 00520 tr_error("pal_fsFread returned 0x%" PRIX32, (uint32_t) pal_rc); 00521 } 00522 00523 /* close file after use */ 00524 pal_rc = pal_fsFclose(&file); 00525 00526 if (pal_rc != PAL_SUCCESS) 00527 { 00528 tr_error("pal_fsFclose failed: %" PRId32, pal_rc); 00529 } 00530 } 00531 else 00532 { 00533 /* header file not present, slot is either invalid or unused. */ 00534 result.code = ERR_NOT_READY; 00535 } 00536 } 00537 } 00538 } 00539 } 00540 00541 return result; 00542 } 00543 00544 /** 00545 * @brief Get details for the component responsible for installation. 00546 * @details This call populates the passed details struct with information 00547 * about the local installer. Only the fields marked as supported 00548 * in the capabilities bitmap will have valid values. The 00549 * installer could be the bootloader, a recovery image, or some 00550 * other component responsible for applying the new firmware 00551 * image. 00552 * 00553 * @param details Pointer to installer details struct to be populated. 00554 * @return Returns ERR_NONE on accept, and signals the event handler with 00555 * either DONE or ERROR when complete. 00556 * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. 00557 */ 00558 arm_uc_error_t ARM_UC_Classic_PAL_GetInstallerDetails(arm_uc_installer_details_t* details) 00559 { 00560 arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; 00561 00562 if (details) 00563 { 00564 result = pal_ext_installerGetDetails(details); 00565 } 00566 00567 return result; 00568 } 00569 00570 const ARM_UC_PAAL_UPDATE ARM_UCP_FILESYSTEM = 00571 { 00572 .Initialize = ARM_UC_Classic_PAL_Initialize, 00573 .GetCapabilities = ARM_UC_Classic_PAL_GetCapabilities, 00574 .GetMaxID = ARM_UC_Classic_PAL_GetMaxID, 00575 .Prepare = ARM_UC_Classic_PAL_Prepare, 00576 .Write = ARM_UC_Classic_PAL_Write, 00577 .Finalize = ARM_UC_Classic_PAL_Finalize, 00578 .Read = ARM_UC_Classic_PAL_Read, 00579 .Activate = ARM_UC_Classic_PAL_Activate, 00580 .GetActiveFirmwareDetails = ARM_UC_Classic_PAL_GetActiveFirmwareDetails, 00581 .GetFirmwareDetails = ARM_UC_Classic_PAL_GetFirmwareDetails, 00582 .GetInstallerDetails = ARM_UC_Classic_PAL_GetInstallerDetails 00583 };
Generated on Tue Jul 12 2022 19:01:32 by 1.7.2