aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSherry Zhang <sherry.zhang2@arm.com>2021-01-07 14:19:41 +0800
committerDavid Hu <david.hu@arm.com>2021-03-19 08:03:00 +0100
commit07b42416f64dab413579ee5a63cbd22f5117cb8e (patch)
treef01fd5fc27dc060f6072f2dcabdf43e65f466ad1
parent973c4f4c51a7998e70a4b92adc20d7a3091a048f (diff)
downloadtrusted-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>
-rw-r--r--bl2/CMakeLists.txt1
-rw-r--r--bl2/ext/mcuboot/include/mcuboot_config/mcuboot_config.h.in3
-rw-r--r--bl2/src/shared_data.c78
-rw-r--r--cmake/install.cmake14
-rw-r--r--config/check_config.cmake7
-rw-r--r--config/config_default.cmake2
-rw-r--r--config/profile/profile_small.cmake4
-rw-r--r--config/tfm_ipc_config_default.cmake4
-rw-r--r--docs/reference/services/tfm_secure_partition_addition.rst7
-rw-r--r--interface/include/psa/error.h7
-rw-r--r--interface/include/psa/update.h264
-rw-r--r--interface/include/tfm_fwu_defs.h25
-rw-r--r--interface/src/tfm_firmware_update_func_api.c151
-rw-r--r--platform/ext/target/musca_b1/sse_200/config.cmake6
-rw-r--r--platform/ext/target/musca_b1/sse_200/partition/region_defs.h4
-rw-r--r--secure_fw/CMakeLists.txt1
-rw-r--r--secure_fw/partitions/firmware_update/CMakeLists.txt73
-rw-r--r--secure_fw/partitions/firmware_update/bootloader/mcuboot/mcuboot_utilities.cmake40
-rw-r--r--secure_fw/partitions/firmware_update/bootloader/mcuboot/tfm_mcuboot_fwu.c540
-rw-r--r--secure_fw/partitions/firmware_update/bootloader/tfm_bootloader_fwu_abstraction.h155
-rw-r--r--secure_fw/partitions/firmware_update/tfm_firmware_update.yaml107
-rw-r--r--secure_fw/partitions/firmware_update/tfm_fwu.c118
-rw-r--r--secure_fw/partitions/firmware_update/tfm_fwu.h65
-rw-r--r--secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.c268
-rw-r--r--secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.h93
-rw-r--r--secure_fw/partitions/firmware_update/tfm_fwu_secure_api.c173
-rw-r--r--secure_fw/spm/ffm/tfm_boot_data.c3
-rw-r--r--secure_fw/spm/include/tfm_boot_status.h17
-rw-r--r--tools/tfm_manifest_list.yaml15
29 files changed, 2230 insertions, 15 deletions
diff --git a/bl2/CMakeLists.txt b/bl2/CMakeLists.txt
index bab9901858..73deeb81f4 100644
--- a/bl2/CMakeLists.txt
+++ b/bl2/CMakeLists.txt
@@ -12,6 +12,7 @@ project("Bootloader" VERSION 0.1.0 LANGUAGES C ASM)
add_executable(bl2
src/security_cnt.c
src/flash_map.c
+ $<$<BOOL:${MCUBOOT_DATA_SHARING}>:src/shared_data.c>
)
add_subdirectory(ext/mcuboot)
diff --git a/bl2/ext/mcuboot/include/mcuboot_config/mcuboot_config.h.in b/bl2/ext/mcuboot/include/mcuboot_config/mcuboot_config.h.in
index 82973163e5..882585ef23 100644
--- a/bl2/ext/mcuboot/include/mcuboot_config/mcuboot_config.h.in
+++ b/bl2/ext/mcuboot/include/mcuboot_config/mcuboot_config.h.in
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 Open Source Foundries Limited
- * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2019-2021 Arm Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -35,6 +35,7 @@ extern "C" {
#cmakedefine MCUBOOT_HW_ROLLBACK_PROT
#cmakedefine MCUBOOT_MEASURED_BOOT
+#cmakedefine MCUBOOT_DATA_SHARING
/*
* Maximum size of the measured boot record.
diff --git a/bl2/src/shared_data.c b/bl2/src/shared_data.c
new file mode 100644
index 0000000000..10ad0419bd
--- /dev/null
+++ b/bl2/src/shared_data.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <string.h>
+#include "bootutil/boot_record.h"
+#include "bootutil/boot_status.h"
+#include "bootutil/image.h"
+#include "flash_map/flash_map.h"
+#include "sysflash/sysflash.h"
+
+/* Firmware Update specific macros */
+#define TLV_MAJOR_FWU 0x2
+#define MODULE_MASK 0x3F /* 6 bit */
+#define CLAIM_MASK 0x3F /* 6 bit */
+
+#define SET_FWU_MINOR(sw_module, claim) \
+ ((uint16_t)((sw_module & MODULE_MASK) << 6) | \
+ (uint16_t)(claim & CLAIM_MASK))
+
+extern int
+boot_add_data_to_shared_area(uint8_t major_type,
+ uint16_t minor_type,
+ size_t size,
+ const uint8_t *data);
+
+/**
+ * Add application specific data to the shared memory area between the
+ * bootloader and runtime SW.
+ *
+ * @param[in] hdr Pointer to the image header stored in RAM.
+ * @param[in] fap Pointer to the flash area where image is stored.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+int boot_save_shared_data(const struct image_header *hdr,
+ const struct flash_area *fap)
+{
+ uint16_t fwu_minor;
+ struct image_version image_ver;
+ const struct flash_area *temp_fap;
+ uint8_t mcuboot_image_id = 0;
+ uint8_t i;
+
+ if (hdr == NULL || fap == NULL) {
+ return -1;
+ }
+
+ for (i = 0; i < MCUBOOT_IMAGE_NUMBER; i++) {
+ if (flash_area_open(FLASH_AREA_IMAGE_PRIMARY(i),
+ &temp_fap) != 0) {
+ return -1;
+ }
+
+ if (fap == temp_fap) {
+ mcuboot_image_id = i;
+ break;
+ }
+ }
+
+ if (i == MCUBOOT_IMAGE_NUMBER) {
+ return -1;
+ }
+
+ image_ver = hdr->ih_ver;
+
+ /* TODO: add the module identifier into the fwu_minor after the module
+ * arg is supported.
+ */
+ /* Currently hardcode it to 0 which indicates the full image. */
+ fwu_minor = SET_FWU_MINOR(mcuboot_image_id, SW_VERSION);
+ return boot_add_data_to_shared_area(TLV_MAJOR_FWU,
+ fwu_minor,
+ sizeof(image_ver),
+ (const uint8_t *)&image_ver);
+}
diff --git a/cmake/install.cmake b/cmake/install.cmake
index ab6292a198..f13d3bf527 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -111,6 +111,13 @@ if(TFM_PARTITION_PLATFORM OR FORWARD_PROT_MSG)
DESTINATION ${INSTALL_INTERFACE_INC_DIR})
endif()
+if(TFM_PARTITION_FIRMWARE_UPDATE)
+ install(FILES ${INTERFACE_INC_DIR}/psa/update.h
+ DESTINATION ${INSTALL_INTERFACE_INC_DIR}/psa)
+ install(FILES ${INTERFACE_INC_DIR}/tfm_fwu_defs.h
+ DESTINATION ${INSTALL_INTERFACE_INC_DIR})
+endif()
+
####################### export sources #########################################
if (TFM_MULTI_CORE_TOPOLOGY)
@@ -220,3 +227,10 @@ if(BL2)
DESTINATION ${INSTALL_IMAGE_SIGNING_DIR}/keys)
endif()
endif()
+
+if(TFM_PARTITION_FIRMWARE_UPDATE)
+ if(NOT TFM_PSA_API)
+ install(FILES ${INTERFACE_SRC_DIR}/tfm_firmware_update_func_api.c
+ DESTINATION ${INSTALL_INTERFACE_SRC_DIR})
+ endif()
+endif()
diff --git a/config/check_config.cmake b/config/check_config.cmake
index ccecc59a15..fa87e3b659 100644
--- a/config/check_config.cmake
+++ b/config/check_config.cmake
@@ -63,3 +63,10 @@ tfm_invalid_config(TFM_CODE_SHARING STREQUAL "OFF" AND TFM_CODE_SHARING_PATH)
####################### SP META Pointer ########################################
tfm_invalid_config(TFM_SP_META_PTR_ENABLE AND NOT TFM_PSA_API)
+
+####################### Firmware Update Parttion ###############################
+
+tfm_invalid_config(TFM_PARTITION_FIRMWARE_UPDATE AND NOT TFM_PARTITION_PLATFORM)
+tfm_invalid_config((MCUBOOT_UPGRADE_STRATEGY STREQUAL "DIRECT_XIP" OR MCUBOOT_UPGRADE_STRATEGY STREQUAL "RAM_LOAD") AND TFM_PARTITION_FIRMWARE_UPDATE)
+tfm_invalid_config(TFM_PARTITION_FIRMWARE_UPDATE AND NOT MCUBOOT_DATA_SHARING)
+tfm_invalid_config(TFM_PARTITION_FIRMWARE_UPDATE AND TFM_PSA_API)
diff --git a/config/config_default.cmake b/config/config_default.cmake
index 100beabbfb..be50f6d236 100644
--- a/config/config_default.cmake
+++ b/config/config_default.cmake
@@ -131,6 +131,8 @@ set(TFM_PARTITION_PLATFORM ON CACHE BOOL "Enable Plat
set(TFM_PARTITION_AUDIT_LOG ON CACHE BOOL "Enable Audit Log partition")
set(FORWARD_PROT_MSG OFF CACHE BOOL "Whether to forward all PSA RoT messages to a Secure Enclave")
+set(TFM_PARTITION_FIRMWARE_UPDATE OFF CACHE BOOL "Enable firmware update partition")
+set(TFM_FWU_BOOTLOADER_LIB ${CMAKE_SOURCE_DIR}/secure_fw/partitions/firmware_update/bootloader/mcuboot/mcuboot_utilities.cmake CACHE FILEPATH "Bootloader configure file for Firmware Update partition")
################################## Tests #######################################
diff --git a/config/profile/profile_small.cmake b/config/profile/profile_small.cmake
index b4059a3a1a..f87e713290 100644
--- a/config/profile/profile_small.cmake
+++ b/config/profile/profile_small.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -25,6 +25,8 @@ set(SYMMETRIC_INITIAL_ATTESTATION ON CACHE BOOL "Use symmetr
set(TFM_PARTITION_PLATFORM OFF CACHE BOOL "Enable Platform partition")
+set(TFM_PARTITION_FIRMWARE_UPDATE OFF CACHE BOOL "Enable firmware update partition")
+
set(TFM_PARTITION_AUDIT_LOG OFF CACHE BOOL "Enable Audit Log partition")
################################## Tests #######################################
diff --git a/config/tfm_ipc_config_default.cmake b/config/tfm_ipc_config_default.cmake
index 56dd9f3fd3..28f9e6d47b 100644
--- a/config/tfm_ipc_config_default.cmake
+++ b/config/tfm_ipc_config_default.cmake
@@ -1,5 +1,5 @@
#-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -8,3 +8,5 @@
############################ Partitions ########################################
set(TFM_PARTITION_AUDIT_LOG OFF CACHE BOOL "Enable Audit Log partition")
+set(TFM_PARTITION_FIRMWARE_UPDATE OFF CACHE BOOL "Enable firmware update partition")
+set(MCUBOOT_DATA_SHARING OFF CACHE BOOL "Add sharing of application specific data using the same shared data area as for the measured boot")
diff --git a/docs/reference/services/tfm_secure_partition_addition.rst b/docs/reference/services/tfm_secure_partition_addition.rst
index 6289e2ada9..9343aab2d4 100644
--- a/docs/reference/services/tfm_secure_partition_addition.rst
+++ b/docs/reference/services/tfm_secure_partition_addition.rst
@@ -187,9 +187,10 @@ Here is the RoT Service ID table used in TF-M.
audit_logging 0x00000 0x000-0x01F
initial_attestation 0x00000 0x020-0x03F
platform 0x00000 0x040-0x05F
- protected_storage 0x00000 0x060-0x07F
+ protected_storage 0x00000 0x060-0x06F
+ internal_trusted_storage 0x00000 0x070-0x07F
crypto 0x00000 0x080-0x09F
- internal_trusted_storage 0x00000 0x0A0-0x0BF
+ firmware_update 0x00000 0x0A0-0x0BF
test_secure_service 0x0000F 0x000-0x01F
core_test 0x0000F 0x020-0x03F
core_test_2 0x0000F 0x040-0x05F
@@ -463,4 +464,4 @@ Reference
--------------
-*Copyright (c) 2019-2020, Arm Limited. All rights reserved.*
+*Copyright (c) 2019-2021, Arm Limited. All rights reserved.*
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;
+}
diff --git a/platform/ext/target/musca_b1/sse_200/config.cmake b/platform/ext/target/musca_b1/sse_200/config.cmake
index 9b45c6913c..baec32d552 100644
--- a/platform/ext/target/musca_b1/sse_200/config.cmake
+++ b/platform/ext/target/musca_b1/sse_200/config.cmake
@@ -14,6 +14,12 @@ if (NOT FORWARD_PROT_MSG)
if(CRYPTO_HW_ACCELERATOR_OTP_STATE STREQUAL "ENABLED")
set(PLATFORM_DUMMY_CRYPTO_KEYS FALSE CACHE BOOL "Use dummy crypto keys. Should not be used in production.")
endif()
+
+ # Currently, Firmware Update Partition is not supported in IPC mode.
+ if(NOT TFM_PSA_API)
+ set(MCUBOOT_DATA_SHARING ON CACHE BOOL "Add sharing of application specific data using the same shared data area as for the measured boot")
+ set(TFM_PARTITION_FIRMWARE_UPDATE ON CACHE BOOL "Enable firmware update partition")
+ endif()
set(BL0 OFF)
else()
set(MCUBOOT_IMAGE_NUMBER 1 CACHE STRING "Whether to combine S and NS into either 1 image, or sign each seperately")
diff --git a/platform/ext/target/musca_b1/sse_200/partition/region_defs.h b/platform/ext/target/musca_b1/sse_200/partition/region_defs.h
index a362c01ba4..2d9f06f297 100644
--- a/platform/ext/target/musca_b1/sse_200/partition/region_defs.h
+++ b/platform/ext/target/musca_b1/sse_200/partition/region_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2020 Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2021 Arm Limited. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,7 +83,7 @@
#define IMAGE_NS_CODE_SIZE \
(FLASH_NS_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
-#define CMSE_VENEER_REGION_SIZE (0x340)
+#define CMSE_VENEER_REGION_SIZE (0x360)
/* Alias definitions for secure and non-secure areas*/
#define S_ROM_ALIAS(x) (S_ROM_ALIAS_BASE + (x))
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index 364e2454db..26dbfa20ea 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -26,6 +26,7 @@ add_subdirectory(partitions/protected_storage)
add_subdirectory(partitions/internal_trusted_storage)
add_subdirectory(partitions/platform)
add_subdirectory(partitions/psa_proxy)
+add_subdirectory(partitions/firmware_update)
add_subdirectory(spm)
target_include_directories(secure_fw
diff --git a/secure_fw/partitions/firmware_update/CMakeLists.txt b/secure_fw/partitions/firmware_update/CMakeLists.txt
new file mode 100644
index 0000000000..b3bfe2df32
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/CMakeLists.txt
@@ -0,0 +1,73 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+if (NOT TFM_PARTITION_FIRMWARE_UPDATE)
+ return()
+endif()
+
+cmake_minimum_required(VERSION 3.15)
+cmake_policy(SET CMP0079 NEW)
+
+add_library(tfm_psa_rot_partition_fwu STATIC)
+
+target_include_directories(tfm_psa_rot_partition_fwu
+ PRIVATE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ ${CMAKE_BINARY_DIR}/generated/secure_fw/partitions/firmware_update
+)
+
+target_sources(tfm_psa_rot_partition_fwu
+ PRIVATE
+ tfm_fwu_req_mngr.c
+ tfm_fwu.c
+)
+
+# Include the bootloader specific configuration.
+if ((NOT TFM_FWU_BOOTLOADER_LIB) OR (NOT EXISTS ${TFM_FWU_BOOTLOADER_LIB}))
+ message(FATAL_ERROR "TFM_FWU_BOOTLOADER_LIB invalid")
+endif()
+
+include(${TFM_FWU_BOOTLOADER_LIB})
+
+target_link_libraries(tfm_psa_rot_partition_fwu
+ PRIVATE
+ tfm_secure_api
+ psa_interface
+ platform_s
+ tfm_sprt
+)
+
+target_compile_definitions(tfm_psa_rot_partition_fwu
+ PRIVATE
+ $<$<BOOL:${TFM_PSA_API}>:TFM_PSA_API>
+)
+
+############################ Secure API ########################################
+
+target_sources(tfm_secure_api
+ INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/tfm_fwu_secure_api.c
+)
+
+# The veneers give warnings about not being properly declared so they get hidden
+# to not overshadow _real_ warnings.
+set_source_files_properties(tfm_fwu_secure_api.c
+ PROPERTIES
+ COMPILE_FLAGS -Wno-implicit-function-declaration
+)
+
+############################ Partition Defs ####################################
+
+target_link_libraries(tfm_partitions
+ INTERFACE
+ tfm_psa_rot_partition_fwu
+)
+
+target_compile_definitions(tfm_partition_defs
+ INTERFACE
+ TFM_PARTITION_FIRMWARE_UPDATE
+)
diff --git a/secure_fw/partitions/firmware_update/bootloader/mcuboot/mcuboot_utilities.cmake b/secure_fw/partitions/firmware_update/bootloader/mcuboot/mcuboot_utilities.cmake
new file mode 100644
index 0000000000..9aa315c4e7
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/bootloader/mcuboot/mcuboot_utilities.cmake
@@ -0,0 +1,40 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+add_library(tfm_fwu_mcuboot_util INTERFACE)
+
+target_sources(tfm_fwu_mcuboot_util
+ INTERFACE
+ ${MCUBOOT_PATH}/boot/bootutil/src/bootutil_misc.c
+ ${CMAKE_SOURCE_DIR}/bl2/src/flash_map.c
+ ${CMAKE_SOURCE_DIR}/bl2/ext/mcuboot/flash_map_extended.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/bootloader/mcuboot/tfm_mcuboot_fwu.c
+)
+
+target_include_directories(tfm_fwu_mcuboot_util
+ INTERFACE
+ ${CMAKE_BINARY_DIR}/bl2/ext/mcuboot
+ ${CMAKE_SOURCE_DIR}/bl2/ext/mcuboot/include
+ ${MCUBOOT_PATH}/boot/bootutil/include
+ ${MCUBOOT_PATH}/boot/bootutil/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/bootloader
+)
+
+target_link_libraries(tfm_fwu_mcuboot_util
+ INTERFACE
+ platform_region_defs
+)
+
+target_link_libraries(tfm_psa_rot_partition_fwu
+ PRIVATE
+ tfm_fwu_mcuboot_util
+)
+
+target_compile_definitions(tfm_psa_rot_partition_fwu
+ PRIVATE
+ MCUBOOT_${MCUBOOT_UPGRADE_STRATEGY}
+)
diff --git a/secure_fw/partitions/firmware_update/bootloader/mcuboot/tfm_mcuboot_fwu.c b/secure_fw/partitions/firmware_update/bootloader/mcuboot/tfm_mcuboot_fwu.c
new file mode 100644
index 0000000000..6ad347c8c8
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/bootloader/mcuboot/tfm_mcuboot_fwu.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa/crypto.h"
+#include "log/tfm_log.h"
+#include "bootutil_priv.h"
+#include "bootutil/bootutil.h"
+#include "bootutil/image.h"
+#include "flash_map_backend/flash_map_backend.h"
+#include "sysflash/sysflash.h"
+#include "tfm_bootloader_fwu_abstraction.h"
+#include "tfm_fwu_req_mngr.h"
+#include "tfm_boot_status.h"
+#include "service_api.h"
+#include "tfm_memory_utils.h"
+#include "tfm_secure_api.h"
+
+#if (MCUBOOT_IMAGE_NUMBER == 1)
+#define MAX_IMAGE_INFO_LENGTH (sizeof(struct image_version) + \
+ SHARED_DATA_ENTRY_HEADER_SIZE)
+#else
+#define MAX_IMAGE_INFO_LENGTH 2 * (sizeof(struct image_version) + \
+ SHARED_DATA_ENTRY_HEADER_SIZE)
+#endif
+#define TFM_MCUBOOT_FWU_INVALID_IMAGE_ID 0xFF
+/*
+ * \struct fwu_image_info_data
+ *
+ * \brief Contains the received boot status information from bootloader
+ *
+ * \details This is a redefinition of \ref tfm_boot_data to allocate the
+ * appropriate, service dependent size of \ref boot_data.
+ */
+typedef struct fwu_image_info_data_s {
+ struct shared_data_tlv_header header;
+ uint8_t data[MAX_IMAGE_INFO_LENGTH];
+} fwu_image_info_data_t;
+
+typedef struct tfm_fwu_mcuboot_ctx_s {
+ /* The flash area corresponding to mcuboot_image_id. */
+ const struct flash_area *fap;
+ uint8_t mcuboot_image_id;
+
+ /* The size of the downloaded data in the FWU process. */
+ size_t loaded_size;
+} tfm_fwu_mcuboot_ctx_t;
+
+static tfm_fwu_mcuboot_ctx_t mcuboot_ctx[TFM_FWU_MAX_IMAGES];
+static fwu_image_info_data_t boot_shared_data;
+
+static int convert_id_from_bl_to_mcuboot(bl_image_id_t bl_image_id,
+ uint8_t *mcuboot_image_id)
+{
+#if (MCUBOOT_IMAGE_NUMBER == 1)
+ /* Only full image upgrade is supported in this case. */
+ if (bl_image_id != FWU_IMAGE_TYPE_FULL) {
+ LOG_MSG("TFM FWU: multi-image is not supported in current mcuboot configuration.");
+ return -1;
+ }
+
+ /* The image id in mcuboot. 0: the full image. */
+ *mcuboot_image_id = 0;
+#else
+ if (bl_image_id == FWU_IMAGE_TYPE_SECURE) {
+ /* The image id in mcuboot. 0: the secure image. */
+ *mcuboot_image_id = 0;
+ } else if (bl_image_id == FWU_IMAGE_TYPE_NONSECURE) {
+ /* The image id in mcuboot. 1: the non-secure image. */
+ *mcuboot_image_id = 1;
+ } else {
+ LOG_MSG("TFM FWU: invalid image_type: %d", bl_image_id);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+static int convert_id_from_mcuboot_to_bl(uint8_t mcuboot_image_id,
+ bl_image_id_t *bl_image_id)
+{
+ uint8_t image_type;
+
+ if (bl_image_id == NULL) {
+ return -1;
+ }
+
+#if (MCUBOOT_IMAGE_NUMBER == 1)
+ /* Only full image upgrade is supported in this case. */
+ if (mcuboot_image_id != 0) {
+ LOG_MSG("TFM FWU: multi-image is not supported in current mcuboot configuration.\n\r");
+ return -1;
+ }
+
+ /* The image id in mcuboot. 0: the full image. */
+ image_type = FWU_IMAGE_TYPE_FULL;
+#else
+ if (mcuboot_image_id == 0) {
+ /* The image id in mcuboot. 0: the secure image. */
+ image_type = FWU_IMAGE_TYPE_SECURE;
+ } else if (mcuboot_image_id == 1) {
+ /* The image id in mcuboot. 1: the non-secure image. */
+ image_type = FWU_IMAGE_TYPE_NONSECURE;
+ } else {
+ LOG_MSG("TFM FWU: invalid mcuboot image id\n\r: %d",
+ mcuboot_image_id);
+ return -1;
+ }
+#endif
+ *bl_image_id = image_type;
+ return 0;
+}
+
+
+/*
+ * Get the flash area of the image mcuboot_image_id.
+ */
+static bool get_flash_image_index(uint8_t mcuboot_image_id, uint8_t *index)
+{
+ for (uint8_t i = 0; i < TFM_FWU_MAX_IMAGES; i++) {
+ if (mcuboot_ctx[i].mcuboot_image_id == mcuboot_image_id) {
+ *index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool get_next_free_index(uint8_t *index)
+{
+ for (uint8_t i = 0; i < TFM_FWU_MAX_IMAGES; i++) {
+ if (mcuboot_ctx[i].fap == NULL) {
+ *index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+static int fwu_bootloader_get_shared_data(void)
+{
+ return tfm_core_get_boot_data(TLV_MAJOR_FWU,
+ (struct tfm_boot_data *)&boot_shared_data,
+ sizeof(boot_shared_data));
+}
+
+psa_status_t fwu_bootloader_init(void)
+{
+ if (fwu_bootloader_get_shared_data() != TFM_SUCCESS) {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t fwu_bootloader_staging_area_init(bl_image_id_t bootloader_image_id)
+{
+ uint8_t mcuboot_image_id = 0;
+ uint8_t index;
+ const struct flash_area *fap;
+
+ if (convert_id_from_bl_to_mcuboot(bootloader_image_id,
+ &mcuboot_image_id) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (flash_area_open(FLASH_AREA_IMAGE_SECONDARY(mcuboot_image_id),
+ &fap) != 0) {
+ LOG_MSG("TFM FWU: opening flash failed.\r\n");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ if (get_flash_image_index(mcuboot_image_id, &index) ||
+ get_next_free_index(&index)) {
+ mcuboot_ctx[index].mcuboot_image_id = mcuboot_image_id;
+ mcuboot_ctx[index].fap = fap;
+
+ /* Reset the loaded_size. */
+ mcuboot_ctx[index].loaded_size = 0;
+ } else {
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+ }
+
+ if (flash_area_erase(fap, 0, fap->fa_size) != 0) {
+ LOG_MSG("TFM FWU: erasing flash failed.\r\n");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ return PSA_SUCCESS;
+}
+
+psa_status_t fwu_bootloader_load_image(bl_image_id_t bootloader_image_id,
+ size_t block_offset,
+ const void *block,
+ size_t block_size)
+{
+ uint8_t mcuboot_image_id = 0;
+ uint8_t index;
+ const struct flash_area *fap;
+
+ if (block == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (convert_id_from_bl_to_mcuboot(bootloader_image_id,
+ &mcuboot_image_id) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* The image should already be added into the mcuboot_ctx. */
+ if (get_flash_image_index(mcuboot_image_id, &index)) {
+ fap = mcuboot_ctx[index].fap;
+ } else {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (flash_area_write(fap, block_offset, block, block_size) != 0) {
+ LOG_MSG("TFM FWU: write flash failed.\r\n");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ /* The overflow check has been done in flash_area_write. */
+ mcuboot_ctx[index].loaded_size += block_size;
+ return PSA_SUCCESS;
+}
+
+static bool check_image_dependency(uint8_t mcuboot_image_id,
+ uint8_t *dependency,
+ psa_image_version_t *version)
+{
+ bool found = false;
+
+ if ((dependency == NULL || version == NULL)) {
+ return found;
+ }
+
+ /* Currently only single image update is supported. So no dependency is
+ * required.
+ */
+ /* TODO: Add the dependency check to support multiple image update.*/
+ *dependency = TFM_MCUBOOT_FWU_INVALID_IMAGE_ID;
+ *version = (psa_image_version_t){.iv_major = 0, .iv_minor = 0,
+ .iv_revision = 0, .iv_build_num = 0};
+
+ return found;
+}
+
+psa_status_t fwu_bootloader_install_image(bl_image_id_t bootloader_image_id,
+ bl_image_id_t *dependency,
+ psa_image_version_t *dependency_version)
+{
+ uint8_t mcuboot_image_id = 0;
+ uint8_t dependency_mcuboot;
+ bl_image_id_t dependency_bl;
+ psa_image_version_t version;
+ const struct flash_area *fap;
+ uint8_t index;
+
+ if ((dependency == NULL || dependency_version == NULL)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (convert_id_from_bl_to_mcuboot(bootloader_image_id,
+ &mcuboot_image_id) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* The image should already be added into the mcuboot_ctx. */
+ if (get_flash_image_index(mcuboot_image_id, &index)) {
+ fap = mcuboot_ctx[index].fap;
+ } else {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (check_image_dependency(mcuboot_image_id,
+ &dependency_mcuboot,
+ &version)) {
+ if (convert_id_from_mcuboot_to_bl(dependency_mcuboot,
+ &dependency_bl) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *dependency = dependency_bl;
+ *dependency_version = version;
+
+ /* PSA_ERROR_DEPENDENCY_NEEDED indicates that a dependency is
+ * required. See the function description in
+ * tfm_bootloader_fwu_abstraction.h.
+ */
+ return PSA_ERROR_DEPENDENCY_NEEDED;
+ } else {
+ /* Write the magic in the image trailer so that this image will be set
+ * taken as a candidate.
+ */
+ if (boot_write_magic(fap) != 0) {
+ return PSA_ERROR_GENERIC_ERROR;
+ } else {
+ /* System reboot is always required. */
+ return PSA_SUCCESS_REBOOT;
+ }
+ }
+}
+
+psa_status_t fwu_bootloader_mark_image_accepted(void)
+{
+ /* As DIRECT_XIP, RAM_LOAD and OVERWRITE_ONLY do not support image revert.
+ * So there is nothing to do in these three upgrade strategies. Image
+ * revert is only supported in SWAP upgrade strategy. In this case, the
+ * image need to be set as a permanent image, so that the next time reboot
+ * up, the image will still be the running image, otherwise, the image will
+ * be reverted and the original image will be chosen as the running image.
+ */
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) && \
+ !defined(MCUBOOT_OVERWRITE_ONLY)
+ if (boot_set_confirmed() != 0) {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+#endif
+ return PSA_SUCCESS;
+}
+
+psa_status_t fwu_bootloader_abort(bl_image_id_t bootloader_image_id)
+{
+ uint8_t mcuboot_image_id = 0;
+ const struct flash_area *fap;
+ uint8_t index;
+
+ if (convert_id_from_bl_to_mcuboot(bootloader_image_id,
+ &mcuboot_image_id) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ /* The image should already be added into the mcuboot_ctx. */
+ if (get_flash_image_index(mcuboot_image_id, &index)) {
+ fap = mcuboot_ctx[index].fap;
+ } else {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ flash_area_erase(fap, 0, fap->fa_size);
+ flash_area_close(fap);
+ mcuboot_ctx[index].fap = NULL;
+ mcuboot_ctx[index].loaded_size = 0;
+ return PSA_SUCCESS;
+}
+
+
+static psa_status_t util_img_hash(const struct flash_area *fap,
+ size_t data_size,
+ uint8_t *hash_result,
+ size_t buf_size,
+ size_t *hash_size)
+{
+ psa_hash_operation_t handle = psa_hash_operation_init();
+ psa_status_t status;
+ uint8_t tmpbuf[BOOT_TMPBUF_SZ];
+ uint32_t tmp_buf_sz = BOOT_TMPBUF_SZ;
+ uint32_t blk_sz;
+ uint32_t off;
+
+ /* Setup the hash object for the desired hash. */
+ status = psa_hash_setup(&handle, PSA_ALG_SHA_256);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ for (off = 0; off < data_size; off += blk_sz) {
+ blk_sz = data_size - off;
+ if (blk_sz > tmp_buf_sz) {
+ blk_sz = tmp_buf_sz;
+ }
+
+ if (flash_area_read(fap, off, tmpbuf, blk_sz)) {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+ status = psa_hash_update(&handle, tmpbuf, blk_sz);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ }
+
+ status = psa_hash_finish(&handle, hash_result, buf_size, hash_size);
+
+ return status;
+}
+
+static psa_status_t get_secondary_image_info(uint8_t image_id,
+ psa_image_info_t *info)
+{
+ const struct flash_area *fap = NULL;
+ struct image_header hdr = {0};
+ uint8_t hash[PSA_FWU_MAX_DIGEST_SIZE] = {0};
+ size_t hash_size = 0;
+ psa_status_t ret = PSA_SUCCESS;
+ uint8_t index;
+ size_t data_size;
+
+ if (info == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if ((flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_id),
+ &fap)) != 0) {
+ LOG_MSG("TFM FWU: opening flash failed.\r\n");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ if (flash_area_read(fap, 0, &hdr, sizeof(hdr)) != 0) {
+ flash_area_close(fap);
+ LOG_MSG("TFM FWU: reading flash failed.\r\n");
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+
+ /* Check if the image is in a FWU process. */
+ if (get_flash_image_index(image_id, &index)) {
+
+ /* Calculate hash on the downloaded data. */
+ data_size = mcuboot_ctx[index].loaded_size;
+ } else {
+ /* Check if a valid image exists on the staging area.
+ * If a valid image exists, the FWU partition has no information on the
+ * image size downloaded as the image is copied from the running slot
+ * during the reboot. So in this case when calculating the image hash,
+ * the range starts from the image header till the end of the protected
+ * TLV area.
+ */
+ if (hdr.ih_magic == IMAGE_MAGIC) {
+ info->version.iv_major = hdr.ih_ver.iv_major;
+ info->version.iv_minor = hdr.ih_ver.iv_minor;
+ info->version.iv_revision = hdr.ih_ver.iv_revision;
+ info->version.iv_build_num = hdr.ih_ver.iv_build_num;
+ LOG_MSG("version= %d., %d., %d.,+ %d\n\r",
+ info->version.iv_major,
+ info->version.iv_minor,
+ info->version.iv_revision,
+ info->version.iv_build_num);
+
+ /* Calculate hash on from the image header to the protected TLV. */
+ data_size = hdr.ih_hdr_size + hdr.ih_img_size +
+ hdr.ih_protect_tlv_size;
+ } else {
+ /* No image in the staging area. */
+ return PSA_ERROR_DOES_NOT_EXIST;
+ }
+ }
+
+ if (util_img_hash(fap, data_size, hash, (size_t)PSA_FWU_MAX_DIGEST_SIZE,
+ &hash_size) == PSA_SUCCESS) {
+ tfm_memcpy(info->digest, hash, hash_size);
+ ret = PSA_SUCCESS;
+ } else {
+ ret = PSA_ERROR_GENERIC_ERROR;
+ }
+
+ /* The actual image state will be filled in the tfm_fwu_req_mngr.c where
+ * the image state is maintained.
+ */
+ info->state = PSA_IMAGE_UNDEFINED;
+ flash_area_close(fap);
+ return ret;
+}
+
+psa_status_t fwu_bootloader_get_image_info(bl_image_id_t bootloader_image_id,
+ bool active_image,
+ psa_image_info_t *info)
+{
+ struct image_version image_ver = { 0 };
+ struct shared_data_tlv_entry tlv_entry;
+ uint8_t *tlv_end;
+ uint8_t *tlv_curr;
+ bool found = false;
+ uint8_t mcuboot_image_id = 0;
+
+ if (info == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (convert_id_from_bl_to_mcuboot(bootloader_image_id,
+ &mcuboot_image_id) != 0) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ memset(info, 0, sizeof(psa_image_info_t));
+ memset(info->digest, TFM_IMAGE_INFO_INVALID_DIGEST, sizeof(info->digest));
+
+ if (active_image) {
+ /* Set the image state as accepted. */
+ /* TODO: check the image state by reading the image_ok flag in SWAP
+ * case.
+ */
+ info->state = PSA_IMAGE_INSTALLED;
+
+ /* When getting the primary image information, read it from the
+ * shared memory.
+ */
+ if (boot_shared_data.header.tlv_magic != SHARED_DATA_TLV_INFO_MAGIC) {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+
+ tlv_end = (uint8_t *)&boot_shared_data +
+ boot_shared_data.header.tlv_tot_len;
+ tlv_curr = boot_shared_data.data;
+
+ while (tlv_curr < tlv_end) {
+ (void)memcpy(&tlv_entry, tlv_curr, SHARED_DATA_ENTRY_HEADER_SIZE);
+ if ((GET_FWU_CLAIM(tlv_entry.tlv_type) == SW_VERSION) &&
+ (GET_FWU_MODULE(tlv_entry.tlv_type) == mcuboot_image_id)) {
+ if (tlv_entry.tlv_len != sizeof(struct image_version)) {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+ memcpy(&image_ver,
+ tlv_curr + SHARED_DATA_ENTRY_HEADER_SIZE,
+ tlv_entry.tlv_len);
+ found = true;
+ break;
+ }
+ tlv_curr += SHARED_DATA_ENTRY_HEADER_SIZE + tlv_entry.tlv_len;
+ }
+ if (found) {
+ info->version.iv_major = image_ver.iv_major;
+ info->version.iv_minor = image_ver.iv_minor;
+ info->version.iv_revision = image_ver.iv_revision;
+ info->version.iv_build_num = image_ver.iv_build_num;
+
+ /* The image in the primary slot is verified by the bootloader.
+ * The image digest in the primary slot should not be exposed to
+ * nonsecure.
+ */
+ return PSA_SUCCESS;
+ } else {
+ return PSA_ERROR_GENERIC_ERROR;
+ }
+ } else {
+ return get_secondary_image_info(mcuboot_image_id, info);
+ }
+}
diff --git a/secure_fw/partitions/firmware_update/bootloader/tfm_bootloader_fwu_abstraction.h b/secure_fw/partitions/firmware_update/bootloader/tfm_bootloader_fwu_abstraction.h
new file mode 100644
index 0000000000..06c3eff22b
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/bootloader/tfm_bootloader_fwu_abstraction.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_BOOTLOADER_FWU_ABSTRACTION_H__
+#define __TFM_BOOTLOADER_FWU_ABSTRACTION_H__
+
+#include "stdbool.h"
+#include "psa/update.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint8_t bl_image_id_t;
+
+/**
+ * Bootloader related initialization for firmware update, such as reading
+ * some necessary shared data from the memory if needed.
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_GENERIC_ERROR On failure
+ */
+psa_status_t fwu_bootloader_init(void);
+
+/**
+ * \brief Initialize the staging area of the image with given ID.
+ *
+ * Prepare the staging area of the image with given ID for image download.
+ * For example, initialize the staging area, open the flash area, and so on.
+ * The image will be written into the staging area later.
+ *
+ * \param[in] bootloader_image_id The identifier of the target image in
+ * bootloader
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_INVALID_ARGUMENT Invalid input parameter
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ *
+ */
+psa_status_t fwu_bootloader_staging_area_init(bl_image_id_t
+ bootloader_image_id);
+
+/**
+ * \brief Load the image into the target device.
+ *
+ * Prepare the staging area of the image with given ID for image download.
+ * For example, initialize the staging area, open the flash area, and so on.
+ * The image will be written into the staging area later.
+ *
+ * \param[in] bootloader_image_id The identifier of the target image in
+ * bootloader
+ * \param[in] block_offset The offset of the image 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.
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_INVALID_ARGUMENT Invalid input parameter
+ * PSA_ERROR_INSUFFICIENT_MEMORY There is no enough memory to
+ * process the update
+ * PSA_ERROR_INSUFFICIENT_STORAGE There is no enough storage to
+ * process the update
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ *
+ */
+psa_status_t fwu_bootloader_load_image(bl_image_id_t bootloader_image_id,
+ size_t block_offset,
+ const void *block,
+ size_t block_size);
+
+/**
+ * \brief Starts the installation of an image.
+ *
+ * Check the authenticity and integrity of the image.
+ *
+ * If a reboot is required to complete the check, then mark this image as a
+ * candidate so that the next time bootloader runs it will take this image
+ * as a candidate one to bootup. Return the error code PSA_SUCCESS_REBOOT.
+ *
+ * \param[in] bootloader_image_id The identifier of the target image in
+ * bootloader
+ * \param[out] dependency Bootloader image ID of dependency if needed
+ * \param[out] dependency_version Bootloader image version of dependency if
+ * needed
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_SUCCESS_REBOOT A system reboot is needed to finish installation
+ * TFM_SUCCESS_RESTART A restart of the updated component is required
+ * to complete the update
+ * PSA_ERROR_DEPENDENCY_NEEDED Another image needs to be installed to
+ * finish installation
+ * PSA_ERROR_INVALID_ARGUMENT Invalid input parameter
+ * PSA_ERROR_INVALID_SIGNATURE The signature is incorrect
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ * TFM_ERROR_ROLLBACK_DETECTED The image is too old to be installed.
+ * If the image metadata contains a
+ * timestamp and it has expired, then
+ * this error is also returned.
+ */
+psa_status_t fwu_bootloader_install_image(bl_image_id_t bootloader_image_id,
+ bl_image_id_t *dependency,
+ psa_image_version_t *dependency_version);
+
+/**
+ * \brief Marks the image in the primary slot as confirmed.
+ *
+ * Call this API to mark the running images as permanent/accepted to avoid
+ * revert when next time bootup. Usually, this API is called after the running
+ * images have been verified as valid.
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ */
+psa_status_t fwu_bootloader_mark_image_accepted(void);
+
+/**
+ * \brief Abort the current image download process.
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_INVALID_ARGUMENT Invalid input parameter
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ */
+psa_status_t fwu_bootloader_abort(bl_image_id_t bootloader_image_id);
+
+/**
+ * \brief Get the image information.
+ *
+ * Get the image information of the given bootloader_image_id in staging area
+ * or the running area.
+ *
+ * \param[in] bootloader_image_id The identifier of the target image in
+ * bootloader
+ * \param[in] active_image Indicates image location
+ * True: the running image.
+ * False: the image in the passive(or staging)
+ * slot.
+ * \param[out] info Buffer containing return the image
+ * information
+ *
+ * \return PSA_SUCCESS On success
+ * PSA_ERROR_INVALID_ARGUMENT Invalid input parameter
+ * PSA_ERROR_GENERIC_ERROR A fatal error occurred
+ */
+psa_status_t fwu_bootloader_get_image_info(bl_image_id_t bootloader_image_id,
+ bool active_image,
+ psa_image_info_t *info);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TFM_BOOTLOADER_FWU_ABSTRACTION_H__ */
diff --git a/secure_fw/partitions/firmware_update/tfm_firmware_update.yaml b/secure_fw/partitions/firmware_update/tfm_firmware_update.yaml
new file mode 100644
index 0000000000..e2db153117
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_firmware_update.yaml
@@ -0,0 +1,107 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+ "psa_framework_version": 1.0,
+ "name": "TFM_SP_FWU",
+ "type": "PSA-ROT",
+ "priority": "NORMAL",
+ "entry_point": "tfm_fwu_init",
+ "stack_size": "0x2000",
+ "secure_functions": [
+ {
+ "name": "TFM_FWU_WRITE",
+ "signal": "TFM_FWU_WRITE_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_INSTALL",
+ "signal": "TFM_FWU_INSTALL_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_ABORT",
+ "signal": "TFM_FWU_ABORT_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_QUERY",
+ "signal": "TFM_FWU_QUERY_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_REQUEST_REBOOT",
+ "signal": "TFM_FWU_REQUEST_REBOOT_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_ACCEPT",
+ "signal": "TFM_FWU_ACCEPT_REQ",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ ],
+ "services" : [
+ {
+ "name": "TFM_FWU_WRITE",
+ "sid": "0x000000A0",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_INSTALL",
+ "sid": "0x000000A1",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_ABORT",
+ "sid": "0x000000A2",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_QUERY",
+ "sid": "0x000000A3",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_REQUEST_REBOOT",
+ "sid": "0x000000A4",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ },
+ {
+ "name": "TFM_FWU_ACCEPT",
+ "sid": "0x000000A5",
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ }
+ ],
+ "dependencies": [
+ "TFM_CRYPTO",
+ "TFM_SP_PLATFORM_SYSTEM_RESET"
+ ]
+} \ No newline at end of file
diff --git a/secure_fw/partitions/firmware_update/tfm_fwu.c b/secure_fw/partitions/firmware_update/tfm_fwu.c
new file mode 100644
index 0000000000..3768f65362
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_fwu.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include "log/tfm_log.h"
+#include "tfm_platform_api.h"
+#include "tfm_fwu.h"
+
+psa_status_t tfm_internal_fwu_initialize(psa_image_id_t image_id)
+{
+ uint8_t image_type = (uint8_t)FWU_IMAGE_ID_GET_TYPE(image_id);
+ uint8_t slot_id = (uint8_t)FWU_IMAGE_ID_GET_SLOT(image_id);
+
+ /* Check the image slot, the target should be the staging slot. */
+ if (slot_id != FWU_IMAGE_ID_SLOT_STAGE) {
+ LOG_MSG("TFM FWU: invalid slot_id: %d", slot_id);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return fwu_bootloader_staging_area_init(image_type);
+}
+
+psa_status_t tfm_internal_fwu_write(psa_image_id_t image_id,
+ size_t block_offset,
+ const void *block,
+ size_t block_size)
+{
+ uint8_t image_type = (uint8_t)FWU_IMAGE_ID_GET_TYPE(image_id);
+ uint8_t slot_id = (uint8_t)FWU_IMAGE_ID_GET_SLOT(image_id);
+
+ if ((block == NULL) || (slot_id != FWU_IMAGE_ID_SLOT_STAGE)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return fwu_bootloader_load_image(image_type,
+ block_offset,
+ block,
+ block_size);
+}
+
+psa_status_t tfm_internal_fwu_install(psa_image_id_t image_id,
+ psa_image_id_t *dependency,
+ psa_image_version_t *dependency_version)
+{
+ uint8_t image_type = (uint8_t)FWU_IMAGE_ID_GET_TYPE(image_id);
+ uint8_t slot_id = (uint8_t)FWU_IMAGE_ID_GET_SLOT(image_id);
+ bl_image_id_t dependency_bl;
+ psa_image_version_t version;
+ psa_status_t result;
+
+ /* Check the image slot, the target should be the staging slot. */
+ if (slot_id != FWU_IMAGE_ID_SLOT_STAGE) {
+ LOG_MSG("TFM FWU: invalid slot_id: %d", slot_id);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ result = fwu_bootloader_install_image(image_type,
+ &dependency_bl,
+ &version);
+ if (result == PSA_ERROR_DEPENDENCY_NEEDED) {
+ if (dependency == NULL || dependency_version == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ *dependency = (psa_image_id_t)FWU_CALCULATE_IMAGE_ID(FWU_IMAGE_ID_SLOT_STAGE,
+ dependency_bl,
+ 0);
+ *dependency_version = version;
+ }
+
+ return result;
+}
+
+psa_status_t tfm_internal_fwu_abort(psa_image_id_t image_id)
+{
+ uint8_t image_type = (uint8_t)FWU_IMAGE_ID_GET_TYPE(image_id);
+ uint8_t slot_id = (uint8_t)FWU_IMAGE_ID_GET_SLOT(image_id);
+
+ if (slot_id != FWU_IMAGE_ID_SLOT_STAGE) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return fwu_bootloader_abort(image_type);
+}
+
+/* The image version of the given image. */
+psa_status_t tfm_internal_fwu_query(psa_image_id_t image_id,
+ psa_image_info_t *info)
+{
+ uint8_t image_type = (uint8_t)FWU_IMAGE_ID_GET_TYPE(image_id);
+ uint8_t slot_id = (uint8_t)FWU_IMAGE_ID_GET_SLOT(image_id);
+ bool active_image = 0;
+
+ if (slot_id == FWU_IMAGE_ID_SLOT_STAGE) {
+ active_image = false;
+ } else if (slot_id == FWU_IMAGE_ID_SLOT_ACTIVE) {
+ active_image = true;
+ } else {
+ LOG_MSG("TFM FWU: invalid slot_id: %d", slot_id);
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ return fwu_bootloader_get_image_info(image_type, active_image, info);
+}
+
+void tfm_internal_fwu_request_reboot(void)
+{
+ tfm_platform_system_reset();
+}
+
+psa_status_t tfm_internal_fwu_accept(void)
+{
+ return fwu_bootloader_mark_image_accepted();
+}
diff --git a/secure_fw/partitions/firmware_update/tfm_fwu.h b/secure_fw/partitions/firmware_update/tfm_fwu.h
new file mode 100644
index 0000000000..a4cc83fe2d
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_fwu.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_FWU_H__
+#define __TFM_FWU_H__
+
+#include <stddef.h>
+
+#include "psa/update.h"
+#include "tfm_bootloader_fwu_abstraction.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Initialization for starting a firmware update with image_id.
+ */
+psa_status_t tfm_internal_fwu_initialize(psa_image_id_t image_id);
+
+psa_status_t tfm_internal_fwu_write(psa_image_id_t image_id,
+ size_t block_offset,
+ const void *block,
+ size_t block_size);
+
+/*
+ * Starts the installation of an image with image_id. Check the authenticity
+ * and integrity of the image. Error code PSA_SUCCESS_REBOOT is returned if a
+ * reboot is needed to complete the check.
+ */
+psa_status_t tfm_internal_fwu_install(psa_image_id_t image_id,
+ psa_image_id_t *dependency_uuid,
+ psa_image_version_t *dependency_version);
+
+/*
+ * Abort the firmware update process.
+ */
+psa_status_t tfm_internal_fwu_abort(psa_image_id_t image_id);
+
+/*
+ * Get the image information of the given image_id in staging area
+ * or the running area.
+ */
+psa_status_t tfm_internal_fwu_query(psa_image_id_t image_id,
+ psa_image_info_t *info);
+
+/*
+ * Request a reboot.
+ */
+void tfm_internal_fwu_request_reboot(void);
+
+/*
+ * Marks the image in the primary slot as confirmed.
+ */
+psa_status_t tfm_internal_fwu_accept(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_FWU_H__ */
diff --git a/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.c b/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.c
new file mode 100644
index 0000000000..19256fa6c4
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "tfm_fwu_req_mngr.h"
+#include "tfm_fwu.h"
+#include "psa/update.h"
+#include "service_api.h"
+#include "tfm_api.h"
+
+#ifdef TFM_PSA_API
+#include "psa/service.h"
+#include "psa_manifest/tfm_firmware_update.h"
+#endif
+
+typedef struct tfm_fwu_ctx_s {
+ psa_image_id_t image_id;
+ uint8_t image_state;
+ bool in_use;
+} tfm_fwu_ctx_t;
+
+/**
+ * \brief The context of FWU service.
+ */
+static tfm_fwu_ctx_t fwu_ctx[TFM_FWU_MAX_IMAGES];
+
+/**
+ * \brief Check if the image is in FWU process, return the index if it is.
+ */
+static bool get_image_index(psa_image_id_t image_id, uint8_t *index)
+{
+ if (!index) {
+ return false;
+ }
+
+ for (uint8_t i = 0; i < TFM_FWU_MAX_IMAGES; i++) {
+ if (fwu_ctx[i].in_use && (fwu_ctx[i].image_id == image_id)) {
+ *index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * \brief The the next free index in fwu_ctx.
+ */
+static bool get_next_free_index(uint8_t *index)
+{
+ for (uint8_t i = 0; i < TFM_FWU_MAX_IMAGES; i++) {
+ if (!fwu_ctx[i].in_use) {
+ *index = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifndef TFM_PSA_API
+psa_status_t tfm_fwu_write_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ psa_image_id_t image_id;
+ size_t block_offset;
+ uint8_t *p_data;
+ size_t data_length;
+ psa_status_t status = PSA_SUCCESS;
+ uint8_t image_index;
+
+ (void)out_vec;
+
+ /* Check input parameters. */
+ if (in_vec[0].len != sizeof(image_id) ||
+ in_vec[1].len != sizeof(block_offset)) {
+ /* The size of one of the arguments is incorrect */
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ p_data = (uint8_t * const)in_vec[2].base;
+
+ if (p_data == NULL) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ block_offset = *((size_t *)in_vec[1].base);
+ data_length = in_vec[2].len;
+ image_id = *((psa_image_id_t *)in_vec[0].base);
+
+ if (get_image_index(image_id, &image_index)) {
+ /* The image is in FWU process. */
+ if ((fwu_ctx[image_index].image_state != PSA_IMAGE_CANDIDATE) &&
+ (fwu_ctx[image_index].image_state != PSA_IMAGE_REJECTED)) {
+ return PSA_ERROR_CURRENTLY_INSTALLING;
+ }
+ } else {
+ /* The image is not in FWU process. */
+ if (get_next_free_index(&image_index)) {
+ /* Get a free index. Start the FWU process of this image. */
+ status = tfm_internal_fwu_initialize(image_id);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+ fwu_ctx[image_index].in_use = true;
+ fwu_ctx[image_index].image_id = image_id;
+ fwu_ctx[image_index].image_state = PSA_IMAGE_CANDIDATE;
+ } else {
+ /* No more resource can be used. */
+ return PSA_ERROR_INSUFFICIENT_MEMORY;
+ }
+ }
+
+ return tfm_internal_fwu_write(image_id,
+ block_offset,
+ p_data,
+ data_length);
+}
+
+psa_status_t tfm_fwu_install_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ psa_image_id_t image_id;
+ psa_image_id_t *dependency_id;
+ psa_image_version_t *dependency_version;
+ psa_status_t status;
+ uint8_t image_index;
+
+ /* Check input/output parameters. */
+ if (in_vec[0].len != sizeof(image_id) ||
+ out_vec[0].len != sizeof(*dependency_id) ||
+ out_vec[1].len != sizeof(*dependency_version)) {
+ /* The size of one of the arguments is incorrect. */
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ image_id = *((psa_image_id_t *)in_vec[0].base);
+ dependency_id = out_vec[0].base;
+ dependency_version = out_vec[1].base;
+
+ if ((!get_image_index(image_id, &image_index)) ||
+ (fwu_ctx[image_index].image_state != PSA_IMAGE_CANDIDATE)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ } else {
+ status = tfm_internal_fwu_install(image_id,
+ dependency_id,
+ dependency_version);
+ if (status == PSA_SUCCESS) {
+ fwu_ctx[image_index].image_state = PSA_IMAGE_INSTALLED;
+
+ /* The image has been successfully installed, free the index. */
+ fwu_ctx[image_index].in_use = false;
+ } else if (status == PSA_SUCCESS_REBOOT) {
+ fwu_ctx[image_index].image_state = PSA_IMAGE_REBOOT_NEEDED;
+ } else {
+ fwu_ctx[image_index].image_state = PSA_IMAGE_REJECTED;
+ }
+
+ return status;
+ }
+}
+
+psa_status_t tfm_fwu_query_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ psa_image_id_t image_id;
+ psa_image_info_t *info_p;
+ psa_status_t result = 0;
+ uint8_t image_index;
+
+ if ((in_vec[0].len != sizeof(image_id)) ||
+ (out_vec[0].len != sizeof(*info_p))) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ image_id = *((psa_image_id_t *)in_vec[0].base);
+ info_p = (psa_image_info_t *)out_vec[0].base;
+ result = tfm_internal_fwu_query(image_id, info_p);
+ if (result == PSA_SUCCESS) {
+ /* Fill the image state if the query image is not the running image. */
+ if (info_p->state == PSA_IMAGE_UNDEFINED) {
+ if (get_image_index(image_id, &image_index)) {
+ /* The queried image is the currently updating image. */
+ info_p->state = fwu_ctx[image_index].image_state;
+ }
+ }
+ }
+
+ return result;
+}
+
+psa_status_t tfm_fwu_request_reboot_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ (void)in_vec;
+ (void)out_vec;
+ (void)in_len;
+ (void)out_len;
+
+ tfm_internal_fwu_request_reboot();
+
+ /* If it goes here, then the reboot fails. */
+ return PSA_ERROR_SERVICE_FAILURE;
+}
+
+psa_status_t tfm_fwu_accept_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ (void)in_vec;
+ (void)out_vec;
+ (void)in_len;
+ (void)out_len;
+
+ /* This operation set the running image to INSTALLED state, the images
+ * in the staging area does not impact this operation.
+ */
+ return tfm_internal_fwu_accept();
+}
+
+/* Abort the currently running FWU. */
+psa_status_t tfm_fwu_abort_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len)
+{
+ psa_image_id_t image_id;
+ psa_status_t status;
+ uint8_t image_index;
+
+ (void)out_vec;
+
+ if (in_vec[0].len != sizeof(image_id)) {
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+
+ image_id = *((psa_image_id_t *)in_vec[0].base);
+ if (get_image_index(image_id, &image_index)) {
+ /* The image is in FWU process. */
+ if ((fwu_ctx[image_index].image_state == PSA_IMAGE_CANDIDATE) ||
+ (fwu_ctx[image_index].image_state == PSA_IMAGE_REBOOT_NEEDED) ||
+ (fwu_ctx[image_index].image_state == PSA_IMAGE_REJECTED)) {
+ status = tfm_internal_fwu_abort(image_id);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ fwu_ctx[image_index].image_state = PSA_IMAGE_UNDEFINED;
+ fwu_ctx[image_index].in_use = false;
+ fwu_ctx[image_index].image_id = TFM_FWU_INVALID_IMAGE_ID;
+ return PSA_SUCCESS;
+ } else {
+ /* If the image is in INSTALLED state or UNDEFINED, it should not in
+ * a FWU process.
+ */
+ return PSA_ERROR_PROGRAMMER_ERROR;
+ }
+ } else {
+ /* No image with the provided image_id is not in FWU process. */
+ return PSA_ERROR_INVALID_ARGUMENT;
+ }
+}
+#endif
+
+psa_status_t tfm_fwu_init(void)
+{
+ return fwu_bootloader_init();
+}
diff --git a/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.h b/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.h
new file mode 100644
index 0000000000..d7cd92ecc9
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_fwu_req_mngr.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_FWU_REQ_MNGR_H__
+#define __TFM_FWU_REQ_MNGR_H__
+
+#include <stddef.h>
+
+#include "psa/client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The maxinum of images that TF-M support to update concurrently. */
+#define TFM_FWU_MAX_IMAGES 2
+
+/**
+ * \brief Handles the write request.
+ *
+ * \param[in] in_vec Pointer to the input vector which contains the input
+ * parameters.
+ * \param[in] in_len Number of input parameters in the input vector.
+ * \param[out] out_vec Pointer to the output vector which contains the output
+ * parameters.
+ * \param[in] out_len Number of output parameters in the output vector.
+ *
+ * \return A status indicating the success/failure of the operation as
+ * specified in \ref psa_status_t
+ */
+psa_status_t tfm_fwu_write_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Handles the install request.
+ *
+ * \param[in] in_vec Pointer to the input vector which contains the input
+ * parameters.
+ * \param[in] in_len Number of input parameters in the input vector.
+ * \param[out] out_vec Pointer to the output vector which contains the output
+ * parameters.
+ * \param[in] out_len Number of output parameters in the output vector.
+ *
+ * \return A status indicating the success/failure of the operation as
+ * specified in \ref psa_status_t
+ */
+psa_status_t tfm_fwu_install_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Handles the abort request.
+ *
+ * \param[in] in_vec Pointer to the input vector which contains the input
+ * parameters.
+ * \param[in] in_len Number of input parameters in the input vector.
+ * \param[out] out_vec Pointer to the output vector which contains the output
+ * parameters.
+ * \param[in] out_len Number of output parameters in the output vector.
+ *
+ * \return A status indicating the success/failure of the operation as
+ * specified in \ref psa_status_t
+ */
+psa_status_t tfm_fwu_abort_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len);
+
+/**
+ * \brief Query the infor of the primary slot.
+ *
+ * \param[in] in_vec Pointer to the input vector which contains the input
+ * parameters.
+ * \param[in] in_len Number of input parameters in the input vector.
+ * \param[out] out_vec Pointer to the output vector which contains the output
+ * parameters.
+ * \param[in] out_len Number of output parameters in the output vector.
+ *
+ * \return A status indicating the success/failure of the operation as
+ * specified in \ref psa_status_t
+ */
+
+psa_status_t tfm_fwu_query_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len);
+
+psa_status_t tfm_fwu_request_reboot_req(psa_invec *in_vec, size_t in_len,
+ psa_outvec *out_vec, size_t out_len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TFM_FWU_REQ_MNGR_H__ */
diff --git a/secure_fw/partitions/firmware_update/tfm_fwu_secure_api.c b/secure_fw/partitions/firmware_update/tfm_fwu_secure_api.c
new file mode 100644
index 0000000000..815927a72d
--- /dev/null
+++ b/secure_fw/partitions/firmware_update/tfm_fwu_secure_api.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "psa/update.h"
+#include "tfm_api.h"
+
+#ifdef TFM_PSA_API
+#include "psa/client.h"
+#include "psa_manifest/sid.h"
+#else
+#include "tfm_veneers.h"
+#endif
+
+#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_tfm_fwu_write_req_veneer(in_vec,
+ IOVEC_LEN(in_vec),
+ NULL,
+ 0);
+
+ /* A parameter with a buffer pointer where its data length is longer than
+ * maximum permitted, it is treated as a secure violation.
+ * TF-M framework rejects the request with TFM_ERROR_INVALID_PARAMETER.
+ * The firmware update secure PSA implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+ 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_tfm_fwu_install_req_veneer(in_vec, IOVEC_LEN(in_vec),
+ out_vec, IOVEC_LEN(out_vec));
+
+ /* A parameter with a buffer pointer where its data length is longer than
+ * maximum permitted, it is treated as a secure violation.
+ * TF-M framework rejects the request with TFM_ERROR_INVALID_PARAMETER.
+ * The firmware update secure PSA implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+ 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_tfm_fwu_abort_req_veneer(in_vec, IOVEC_LEN(in_vec),
+ NULL, 0);
+
+ /* A parameter with a buffer pointer where its data length is longer than
+ * maximum permitted, it is treated as a secure violation.
+ * TF-M framework rejects the request with TFM_ERROR_INVALID_PARAMETER.
+ * The firmware update secure PSA implementation returns
+ * PSA_ERROR_INVALID_ARGUMENT in that case.
+ */
+ 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_tfm_fwu_query_req_veneer(in_vec, IOVEC_LEN(in_vec),
+ 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_tfm_fwu_request_reboot_req_veneer(NULL,
+ 0,
+ 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_tfm_fwu_accept_req_veneer(NULL,
+ 0,
+ 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;
+}
diff --git a/secure_fw/spm/ffm/tfm_boot_data.c b/secure_fw/spm/ffm/tfm_boot_data.c
index f05e0e3aa5..b2115f5e62 100644
--- a/secure_fw/spm/ffm/tfm_boot_data.c
+++ b/secure_fw/spm/ffm/tfm_boot_data.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -68,6 +68,7 @@ struct boot_data_access_policy {
*/
static const struct boot_data_access_policy access_policy_table[] = {
{TFM_SP_INITIAL_ATTESTATION, TLV_MAJOR_IAS},
+ {TFM_SP_FWU, TLV_MAJOR_FWU},
};
/*!
diff --git a/secure_fw/spm/include/tfm_boot_status.h b/secure_fw/spm/include/tfm_boot_status.h
index 27ce6cb89e..597a6fe3a6 100644
--- a/secure_fw/spm/include/tfm_boot_status.h
+++ b/secure_fw/spm/include/tfm_boot_status.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -21,6 +21,7 @@ extern "C" {
*/
#define TLV_MAJOR_CORE 0x0
#define TLV_MAJOR_IAS 0x1
+#define TLV_MAJOR_FWU 0x2
/**
* The shared data between boot loader and runtime SW is TLV encoded. The
@@ -149,17 +150,25 @@ extern "C" {
#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS)
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
-/* Initial attestation specific macros */
+/* Initial attenstation and Firmware Update common macros */
#define MODULE_POS 6 /* 6 bit */
+#define MODULE_MASK 0x3F /* 6 bit */
#define CLAIM_MASK 0x3F /* 6 bit */
+
+/* Initial attestation specific macros */
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS)
-#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
+#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim))
-
#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \
MEASUREMENT_CLAIM_POS)
+/* Firmware Update specific macros */
+#define SET_FWU_MINOR(sw_module, claim) \
+ ((uint16_t)((sw_module & MODULE_MASK) << 6) | \
+ (uint16_t)(claim & CLAIM_MASK))
+#define GET_FWU_CLAIM(tlv_type) ((uint16_t)GET_MINOR(tlv_type) & CLAIM_MASK)
+#define GET_FWU_MODULE(tlv_type) ((uint16_t)GET_MINOR(tlv_type) >> MODULE_POS)
/* Magic value which marks the beginning of shared data area in memory */
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
diff --git a/tools/tfm_manifest_list.yaml b/tools/tfm_manifest_list.yaml
index 0966eb9cb5..39ddfecefd 100644
--- a/tools/tfm_manifest_list.yaml
+++ b/tools/tfm_manifest_list.yaml
@@ -244,6 +244,21 @@
"*tfm_*partition_psa_proxy.*"
]
}
+ },
+ {
+ "name": "TFM Firmware Update Service",
+ "short_name": "TFM_SP_FWU",
+ "manifest": "secure_fw/partitions/firmware_update/tfm_firmware_update.yaml",
+ "tfm_partition_ipc": true,
+ "conditional": "TFM_PARTITION_FIRMWARE_UPDATE",
+ "version_major": 0,
+ "version_minor": 1,
+ "pid": 271,
+ "linker_pattern": {
+ "library_list": [
+ "*tfm_*partition_fwu*"
+ ]
+ }
}
]
}