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>
diff --git a/bl2/CMakeLists.txt b/bl2/CMakeLists.txt
index bab9901..73deeb8 100644
--- a/bl2/CMakeLists.txt
+++ b/bl2/CMakeLists.txt
@@ -12,6 +12,7 @@
 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 8297316..882585e 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 @@
 
 #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 0000000..10ad041
--- /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 ab6292a..f13d3bf 100644
--- a/cmake/install.cmake
+++ b/cmake/install.cmake
@@ -111,6 +111,13 @@
             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 @@
                 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 ccecc59..fa87e3b 100644
--- a/config/check_config.cmake
+++ b/config/check_config.cmake
@@ -63,3 +63,10 @@
 ####################### 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 100beab..be50f6d 100644
--- a/config/config_default.cmake
+++ b/config/config_default.cmake
@@ -131,6 +131,8 @@
 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 b4059a3..f87e713 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(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 56dd9f3..28f9e6d 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 6289e2a..9343aab 100644
--- a/docs/reference/services/tfm_secure_partition_addition.rst
+++ b/docs/reference/services/tfm_secure_partition_addition.rst
@@ -187,9 +187,10 @@
    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 @@
 
 --------------
 
-*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 439dba4..e8903f0 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 @@
 #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 @@
 #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 0000000..65d7d2d
--- /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 0000000..9041fd3
--- /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 0000000..b8d3541
--- /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 9b45c69..baec32d 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(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 a362c01..2d9f06f 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 364e245..26dbfa2 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -26,6 +26,7 @@
 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 0000000..b3bfe2d
--- /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 0000000..9aa315c
--- /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 0000000..6ad347c
--- /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 0000000..06c3eff
--- /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 0000000..e2db153
--- /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 0000000..3768f65
--- /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 0000000..a4cc83f
--- /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 0000000..19256fa
--- /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 0000000..d7cd92e
--- /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 0000000..815927a
--- /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 f05e0e3..b2115f5 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 @@
  */
 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 27ce6cb..597a6fe 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 @@
  */
 #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 @@
 #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 0966eb9..39ddfec 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*"
+         ]
+      }
     }
   ]
 }