diff options
author | Sherry Zhang <sherry.zhang2@arm.com> | 2021-01-07 14:19:41 +0800 |
---|---|---|
committer | David Hu <david.hu@arm.com> | 2021-03-19 08:03:00 +0100 |
commit | 07b42416f64dab413579ee5a63cbd22f5117cb8e (patch) | |
tree | f01fd5fc27dc060f6072f2dcabdf43e65f466ad1 /interface | |
parent | 973c4f4c51a7998e70a4b92adc20d7a3091a048f (diff) | |
download | trusted-firmware-m-07b42416f64dab413579ee5a63cbd22f5117cb8e.tar.gz |
FWU: Add Firmware Update partition
Firmware Update(FWU) partition provides the functionality
of updating firmware images. This patch implemented the
partition in Library mode.
Change-Id: I736477549b055c64cd8106ad57c3ad7b1b2007ee
Signed-off-by: Sherry Zhang <sherry.zhang2@arm.com>
Diffstat (limited to 'interface')
-rw-r--r-- | interface/include/psa/error.h | 7 | ||||
-rw-r--r-- | interface/include/psa/update.h | 264 | ||||
-rw-r--r-- | interface/include/tfm_fwu_defs.h | 25 | ||||
-rw-r--r-- | interface/src/tfm_firmware_update_func_api.c | 151 |
4 files changed, 445 insertions, 2 deletions
diff --git a/interface/include/psa/error.h b/interface/include/psa/error.h index 439dba4b70..e8903f0445 100644 --- a/interface/include/psa/error.h +++ b/interface/include/psa/error.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Arm Limited. All rights reserved. + * Copyright (c) 2019-2021, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -28,6 +28,8 @@ typedef int32_t psa_status_t; #endif #define PSA_SUCCESS ((psa_status_t)0) +#define PSA_SUCCESS_REBOOT ((psa_status_t)1) +#define PSA_SUCCESS_RESTART ((psa_status_t)2) #define PSA_ERROR_PROGRAMMER_ERROR ((psa_status_t)-129) #define PSA_ERROR_CONNECTION_REFUSED ((psa_status_t)-130) @@ -49,7 +51,8 @@ typedef int32_t psa_status_t; #define PSA_ERROR_STORAGE_FAILURE ((psa_status_t)-146) #define PSA_ERROR_HARDWARE_FAILURE ((psa_status_t)-147) #define PSA_ERROR_INVALID_SIGNATURE ((psa_status_t)-149) - +#define PSA_ERROR_DEPENDENCY_NEEDED ((psa_status_t)-156) +#define PSA_ERROR_CURRENTLY_INSTALLING ((psa_status_t)-157) #ifdef __cplusplus } #endif diff --git a/interface/include/psa/update.h b/interface/include/psa/update.h new file mode 100644 index 0000000000..65d7d2dd60 --- /dev/null +++ b/interface/include/psa/update.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef PSA_UPDATE_H +#define PSA_UPDATE_H + +#include <stddef.h> +#include <stdint.h> + +#include "psa/error.h" +#include "tfm_fwu_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PSA_FWU_MAX_BLOCK_SIZE 1024 +#define TFM_FWU_INVALID_IMAGE_ID 0 + +/* The maximum size of an image digest in bytes. This is dependent + * on the hash algorithm used. + */ +#define PSA_FWU_MAX_DIGEST_SIZE 32 +#define TFM_IMAGE_INFO_INVALID_DIGEST 0xFF + +/* The image ID macros. */ +#define FWU_IMAGE_ID_SLOT_POSITION 0U + +/* The area where the image is running. */ +#define FWU_IMAGE_ID_SLOT_ACTIVE 0x01U + +/* The area to stage the image. */ +#define FWU_IMAGE_ID_SLOT_STAGE 0x02U +#define FWU_IMAGE_ID_SLOT_MASK 0x00FF + +#define FWU_IMAGE_ID_TYPE_POSITION 8U +#define FWU_IMAGE_ID_SPECIFIC_ID_POSITION 16U + +#define FWU_CALCULATE_IMAGE_ID(slot, type, specific_id) \ + ((slot & FWU_IMAGE_ID_SLOT_MASK) | \ + (type << FWU_IMAGE_ID_TYPE_POSITION) | \ + (specific_id << FWU_IMAGE_ID_SPECIFIC_ID_POSITION)) +#define FWU_IMAGE_ID_GET_TYPE(image_id) (image_id >> FWU_IMAGE_ID_TYPE_POSITION) +#define FWU_IMAGE_ID_GET_SLOT(image_id) (image_id & FWU_IMAGE_ID_SLOT_MASK) + +/* Image state macros. */ +#define PSA_IMAGE_UNDEFINED 0 +#define PSA_IMAGE_CANDIDATE 1 +#define PSA_IMAGE_INSTALLED 2 +#define PSA_IMAGE_REJECTED 3 +#define PSA_IMAGE_PENDING_INSTALL 4 +#define PSA_IMAGE_REBOOT_NEEDED 5 + +/* + * image_id[7:0]: slot. + * image_id[15:8]: image type. + * image_id[31:16]: specific image ID. + */ +typedef uint32_t psa_image_id_t; + +typedef struct tfm_image_version_s { + uint8_t iv_major; + uint8_t iv_minor; + uint16_t iv_revision; + uint32_t iv_build_num; +} psa_image_version_t; + +typedef struct tfm_image_info_s { + psa_image_version_t version; + uint8_t state; + uint8_t digest[PSA_FWU_MAX_DIGEST_SIZE]; +} psa_image_info_t; + +typedef struct psa_hash_s { + uint8_t value[PSA_FWU_MAX_DIGEST_SIZE]; +} psa_hash_t; + +/** + * \brief Writes an image to its staging area. + * + * Writes the image data 'block' with length 'block_size' to its staging area. + * If the image size is less than or equal to PSA_FWU_MAX_BLOCK_SIZE, the + * caller can send the entire image in one call. + * If the image size is greater than PSA_FWU_MAX_BLOCK_SIZE, the caller must + * send parts of the image by calling this API multiple times with different + * data blocks. + * + * \param[in] image_id The identifier of the image + * \param[in] block_offset The offset of the block being passed into block, + * in bytes + * \param[in] block A buffer containing a block of image data. This + * might be a complete image or a subset. + * \param[in] block_size Size of block. The size must not be greater than + * PSA_FWU_MAX_BLOCK_SIZE. + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The data in block has been + * successfully stored. + * \retval PSA_ERROR_INVALID_ARGUMENT One of the following error + * conditions occurred: + * The parameter size is greater than + * PSA_FWU_MAX_BLOCK_SIZE; + * The parameter size is 0; + * The combination of offset and size + * is out of bounds. + * + * \retval PSA_ERROR_INSUFFICIENT_MEMORY There is not enough memory to + * process the update + * \retval PSA_ERROR_INSUFFICIENT_STORAGE There is not enough storage to + * process the update + * \retval PSA_ERROR_GENERAL_ERROR A fatal error occurred + * \retval PSA_ERROR_CURRENTLY_INSTALLING The image is currently locked for + * writing. + */ +psa_status_t psa_fwu_write(psa_image_id_t image_id, + size_t block_offset, + const void *block, + size_t block_size); + + +/** + * \brief Starts the installation of an image. + * + * The authenticity and integrity of the image is checked during installation. + * If a reboot is required to complete installation then the implementation + * can choose to defer the authenticity checks to that point. + * + * \param[in] image_id The identifier of the image to install + * \param[out] dependency_uuid If PSA_ERROR_DEPENDENCY_NEEDED is returned, + * this parameter is filled with dependency + * information + * \param[out] dependency_version If PSA_ERROR_DEPENDENCY_NEEDED is returned, + * this parameter is filled with the minimum + * required version for the dependency + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The image was successfully + * installed. The platform does not + * require a reboot. + * \retval PSA_SUCCESS_REBOOT A system reboot is needed to finish + * installation. + * \retval PSA_ERROR_INVALID_ARGUMENT Bad input parameter + * \retval PSA_ERROR_INVALID_SIGNATURE The signature is incorrect + * \retval PSA_ERROR_GENERAL_ERROR A fatal error occurred + * \retval PSA_ERROR_DEPENDENCY_NEEDED A different image requires + * installation first + * \retval PSA_ERROR_STORAGE_FAILURE Some persistent storage could not be + * read or written by the + * implementation + */ +psa_status_t psa_fwu_install(psa_image_id_t image_id, + psa_image_id_t *dependency_uuid, + psa_image_version_t *dependency_version); + +/** + * \brief Aborts an ongoing installation and erases the staging area of the + * image. + * + * \param[in] image_id The identifier of the image to abort installation + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS Installation of the provided image_id + * has been aborted + * \retval PSA_ERROR_INVALID_ARGUMENT No image with the provided image_id + * is currently being installed + * \retval PSA_ERROR_NOT_PERMITTED The caller is not authorized to + * abort an installation + */ +psa_status_t psa_fwu_abort(psa_image_id_t image_id); + +/** + * \brief Returns information for an image of a particular image_id. + * + * \param[in] image_id The image_id of the image to query + * + * \param[out] info Output parameter for image information + * related to the image_id + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS Image information has been returned + * \retval PSA_ERROR_NOT_PERMITTED The caller is not authorized to + * access platform version information + */ +psa_status_t psa_fwu_query(psa_image_id_t image_id, + psa_image_info_t *info); + +/** + * \brief Requests the platform to reboot. On success, the platform initiates + * a reboot, and might not return to the caller. + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The platform will reboot soon + * \retval PSA_ERROR_NOT_PERMITTED The caller is not authorized to + * reboot the platform + */ +psa_status_t psa_fwu_request_reboot(void); + +/** + * \brief Indicates to the implementation that the upgrade was successful. + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The image and its dependencies have + * transitioned into a PSA_IMAGE_INSTALLED + * state + * \retval PSA_ERROR_NOT_SUPPORTED The implementation does not support a + * PSA_IMAGE_PENDING_INSTALL state + * \retval PSA_ERROR_NOT_PERMITTED The caller is not permitted to make + * this call + */ +psa_status_t psa_fwu_accept(void); + +/** + * \brief Stores a manifest object and associates it with a particular image ID. + * + * \param[in] image_id The identifier of the image + * + * \param[in] manifest A pointer to a buffer containing a manifest + * object + * + * \param[in] manifest_size The size of the manifest parameter + * + * \param[in] manifest_dependency Output parameter containing the hash of a + * required manifest when + * PSA_ERROR_DEPENDENCY_NEEDED is returned + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The manifest is persisted + * \retval PSA_ERROR_NOT_PERMITTED The manifest is too old to be + * installed + * \retval PSA_ERROR_WRONG_DEVICE The manifest is not intended for this + * device + * \retval PSA_ERROR_INVALID_SIGNATURE The manifest signature is not valid + * \retval PSA_ERROR_DEPENDENCY_NEEDED A different manifest is needed + * \retval PSA_ERROR_INVALID_ARGUMENT Parameter size is 0 or a pointer + * parameter is NULL + * \retval PSA_ERROR_COMMUNICATION_FAILURE The system could not communicate with + * the installer + * \retval PSA_ERROR_NOT_SUPPORTED This function is not implemented + * \retval PSA_ERROR_CURRENTLY_INSTALLING An existing manifest for image ID is + * currently being installed and is + * locked from writing + * \retval PSA_ERROR_GENERIC_ERROR A fatal error occurred + */ +psa_status_t psa_fwu_set_manifest(psa_image_id_t image_id, + const void *manifest, + size_t manifest_size, + psa_hash_t *manifest_dependency); + + +#ifdef __cplusplus +} +#endif +#endif /* PSA_UPDATE_H */ diff --git a/interface/include/tfm_fwu_defs.h b/interface/include/tfm_fwu_defs.h new file mode 100644 index 0000000000..9041fd3fc1 --- /dev/null +++ b/interface/include/tfm_fwu_defs.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef TFM_FWU_BOOTLOADER_DEFS_H +#define TFM_FWU_BOOTLOADER_DEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Image type identities. When porting a specific bootloader to FWU partition, + * the bootloader specific image types can be defined here. + */ +#define FWU_IMAGE_TYPE_NONSECURE 0x01U +#define FWU_IMAGE_TYPE_SECURE 0x02U +#define FWU_IMAGE_TYPE_FULL 0x03U + +#ifdef __cplusplus +} +#endif +#endif /* TFM_FWU_BOOTLOADER_DEFS_H */ diff --git a/interface/src/tfm_firmware_update_func_api.c b/interface/src/tfm_firmware_update_func_api.c new file mode 100644 index 0000000000..b8d35413b2 --- /dev/null +++ b/interface/src/tfm_firmware_update_func_api.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "psa/update.h" +#include "tfm_api.h" + +#include "tfm_ns_interface.h" +#include "tfm_veneers.h" + +#define IOVEC_LEN(x) (uint32_t)(sizeof(x)/sizeof(x[0])) + +psa_status_t psa_fwu_write(uint32_t image_id, + size_t block_offset, + const void *block, + size_t block_size) +{ + psa_status_t status; + + psa_invec in_vec[] = { + { .base = &image_id, .len = sizeof(image_id) }, + { .base = &block_offset, .len = sizeof(block_offset) }, + { .base = block, .len = block_size } + }; + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_write_req_veneer, + (uint32_t)in_vec, IOVEC_LEN(in_vec), + (uint32_t)NULL, 0); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_install(psa_image_id_t image_id, + psa_image_id_t *dependency_uuid, + psa_image_version_t *dependency_version) +{ + psa_status_t status; + + psa_invec in_vec[] = { + { .base = &image_id, .len = sizeof(image_id) } + }; + + psa_outvec out_vec[] = { + { .base = dependency_uuid, .len = sizeof(*dependency_uuid) }, + { .base = dependency_version, .len = sizeof(*dependency_version)} + }; + + if ((dependency_uuid == NULL) || (dependency_version == NULL)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_install_req_veneer, + (uint32_t)in_vec, IOVEC_LEN(in_vec), + (uint32_t)out_vec, IOVEC_LEN(out_vec)); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_abort(psa_image_id_t image_id) +{ + psa_status_t status; + + psa_invec in_vec[] = { + { .base = &image_id, .len = sizeof(image_id) } + }; + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_abort_req_veneer, + (uint32_t)in_vec, IOVEC_LEN(in_vec), + (uint32_t)NULL, 0); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_query(psa_image_id_t image_id, psa_image_info_t *info) +{ + psa_status_t status; + + psa_invec in_vec[] = { + { .base = &image_id, .len = sizeof(image_id) } + }; + psa_outvec out_vec[] = { + { .base = info, .len = sizeof(*info)} + }; + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_query_req_veneer, + (uint32_t)in_vec, IOVEC_LEN(in_vec), + (uint32_t)out_vec, IOVEC_LEN(out_vec)); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_request_reboot(void) +{ + psa_status_t status; + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_request_reboot_req_veneer, + (uint32_t)NULL, 0, + (uint32_t)NULL, 0); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_accept(void) +{ + psa_status_t status; + + status = tfm_ns_interface_dispatch((veneer_fn)tfm_tfm_fwu_accept_req_veneer, + (uint32_t)NULL, 0, + (uint32_t)NULL, 0); + + if (status == (psa_status_t)TFM_ERROR_INVALID_PARAMETER) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return status; +} + +psa_status_t psa_fwu_set_manifest(psa_image_id_t image_id, + const void *manifest, + size_t manifest_size, + psa_hash_t *manifest_dependency) +{ + psa_status_t status; + + status = PSA_ERROR_NOT_SUPPORTED; + + return status; +} |