RSS: Add GPT and FIP support

Change RSS from using fixed locations in host flash to loading images
from FIPs (which are at fixed locations). Additionally, add GPT support
(via RSS_GPT_SUPPORT) to support FIPs being at non-fixed locations.

Change-Id: Ia189d2544c6ccee8d6171583e33a54d77746963b
Signed-off-by: Raef Coles <raef.coles@arm.com>
diff --git a/bl1/bl1_2/lib/image.c b/bl1/bl1_2/lib/image.c
index 1a08ed6..be38050 100644
--- a/bl1/bl1_2/lib/image.c
+++ b/bl1/bl1_2/lib/image.c
@@ -16,7 +16,7 @@
 extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
 #endif /* !TFM_BL1_MEMORY_MAPPED_FLASH */
 
-int32_t __WEAK bl1_image_get_flash_offset(uint32_t image_id)
+uint32_t __WEAK bl1_image_get_flash_offset(uint32_t image_id)
 {
     switch (image_id) {
     case 0:
diff --git a/bl1/bl1_2/lib/interface/image.h b/bl1/bl1_2/lib/interface/image.h
index dfb0087..ccf6f2b 100644
--- a/bl1/bl1_2/lib/interface/image.h
+++ b/bl1/bl1_2/lib/interface/image.h
@@ -47,7 +47,7 @@
     } protected_values;
 };
 
-int32_t bl1_image_get_flash_offset(uint32_t image_id);
+uint32_t bl1_image_get_flash_offset(uint32_t image_id);
 
 fih_int bl1_image_copy_to_sram(uint32_t image_id, uint8_t *out);
 
diff --git a/docs/platform/arm/rss/readme.rst b/docs/platform/arm/rss/readme.rst
index fd185f2..d4cb7a6 100644
--- a/docs/platform/arm/rss/readme.rst
+++ b/docs/platform/arm/rss/readme.rst
@@ -78,62 +78,100 @@
 ----------------
 
 To run the built images, they need to be concatenated into binaries that can be
-placed in ROM and flash. To do this, navigate to the TF-M build directory and
-run the following ``srec_cat`` commands::
+placed in ROM and flash. To create the ROM image, navigate to the TF-M build
+directory and run the following ``srec_cat`` command::
 
     srec_cat \
         bl1_1.bin -Binary -offset 0x0 \
         bl1_provisioning_bundle.bin -Binary -offset 0xE000 \
         -o rom.bin -Binary
 
-    srec_cat \
-        bl2_signed.bin -Binary -offset 0x0 \
-        bl2_signed.bin -Binary -offset 0x10000 \
-        tfm_s_ns_signed.bin -Binary -offset 0x020000 \
-        tfm_s_ns_signed.bin -Binary -offset 0x0E0000 \
-        <Host AP BL1 image> -Binary -offset 0x1A0000 \
-        <SCP BL1 image> -Binary -offset 0x220000 \
-        <Host AP BL1 image>  -Binary -offset 0x2A0000 \
-        <SCP BL1 image> -Binary -offset 0x320000 \
-        -o flash.bin -Binary
+For development purposes, the OTP image is included as a provisioning bundle in
+the ROM image and provisioned into OTP by BL1_1.
 
-If XIP mode is enabled, the following ``srec_cat`` command should be run to
+To create the flash image, the following ``fiptool`` command should be run.
+``fiptool`` documentation can be found `here <https://trustedfirmware-a.readthedocs.io/en/latest/getting_started/tools-build.html?highlight=fiptool#building-and-using-the-fip-tool>`_.
+Note that an up-to-date fiptool that supports the RSS UUIDs must be used.::
+
+    fiptool create \
+        --align 8192 --rss-bl2     bl2_signed.bin \
+        --align 8192 --rss-ns      tfm_ns_signed.bin \
+        --align 8192 --rss-s       tfm_s_signed.bin \
+        --align 8192 --rss-scp-bl1 <signed Host SCP BL1 image> \
+        --align 8192 --rss-ap-bl1  <signed Host AP BL1 image> \
+        fip.bin
+
+If you already have a ``fip.bin`` containing host firmware images, RSS FIP
+images can be patched in::
+
+    fiptool update --align 8192 --rss-bl2 bl2_signed.bin fip.bin
+    fiptool update --align 8192 --rss-ns  tfm_ns.bin fip.bin
+    fiptool update --align 8192 --rss-s   tfm_s.bin fip.bin
+
+If XIP mode is enabled, the following ``fiptool`` command should be run to
 create the flash image::
 
-    srec_cat \
-        bl2_signed.bin -Binary -offset 0x0 \
-        bl2_signed.bin -Binary -offset 0x10000 \
-        tfm_s.bin -Binary -offset 0x020000 \
-        tfm_ns.bin -Binary -offset 0x080000 \
-        tfm_s.bin -Binary -offset 0x0E0000 \
-        tfm_ns.bin -Binary -offset 0x140000 \
-        <Host AP BL1 image> -Binary -offset 0x1A0000 \
-        <SCP BL1 image> -Binary -offset 0x220000 \
-        <Host AP BL1 image>  -Binary -offset 0x2A0000 \
-        <SCP BL1 image> -Binary -offset 0x320000 \
-        tfm_s_sic_tables_signed.bin -Binary -offset 0x3A0000 \
-        tfm_ns_sic_tables_signed.bin -Binary -offset 0x3AA000 \
-        tfm_s_sic_tables_signed.bin -Binary -offset 0x3B4000 \
-        tfm_ns_sic_tables_signed.bin -Binary -offset 0x3BE000 \
-        -o flash.bin -Binary
+    fiptool create \
+        --align 8192 --rss-bl2           bl2_signed.bin \
+        --align 8192 --rss-ns            tfm_ns.bin \
+        --align 8192 --rss-s             tfm_s.bin \
+        --align 8192 --rss-sic-tables-ns tfm_ns_sic_tables_signed.bin \
+        --align 8192 --rss-sic-tables-s  tfm_s_sic_tables_signed.bin \
+        --align 8192 --rss-scp-bl1       <signed Host SCP BL1 image> \
+        --align 8192 --rss-ap-bl1        <signed Host AP BL1 image> \
+        fip.bin
 
-Once the flash image is created, it can be combined with the host FIP to create
-a combined host flash image::
+Once the FIP is prepared, a host flash image can be created using ``srec_cat``::
 
     srec_cat \
-            fip-tc.bin -Binary -offset 0x0\
-            flash.bin -Binary -offset 0x02200000 \
+            fip.bin -Binary -offset 0x0 \
             -o host_flash.bin -Binary
 
-For development purposes, the OTP image is included as a provisioning bundle in
-the ROM image and provisioned into OTP by BL1_1. The flash image should include
-the signed host images from the previous section. For each boot image, there is
-a primary and secondary image; if these are different then BL2 will load the one
-with the higher version number.
+If GPT support is enabled, and a host ``fip.bin`` and ``fip_gpt.bin`` has been
+obtained, RSS images can be inserted by first patching the host FIP and then
+inserting that patched FIP into the GPT image::
+
+    sector_size=$(gdisk -l fip_gpt.bin | grep -i "sector size (logical):" | \
+                sed 's/.*logical): \([0-9]*\) bytes/\1/')
+
+    fip_label=" FIP_A$"
+    fip_start_sector=$(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $2}')
+    fip_sector_am=$(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $3 - $2}')
+
+    dd if=fip.bin of=fip_gpt.bin bs=$sector_size seek=$fip_start_sector \
+        count=$fip_sector_am conv=notrunc
+
+    fip_label = " FIP_B$"
+    fip_start_sector = $(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $2}')
+    fip_sector_am = $(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $3 - $2}')
+
+    dd if=fip.bin of=fip_gpt.bin bs=$sector_size seek=$fip_start_sector \
+        count=$fip_sector_am conv=notrunc
+
+To patch a ``fip_gpt.bin`` without having an initial ``fip.bin``, the FIP can be
+extracted from the GPT image using the following commands (and can then be
+patched and reinserted using the above commands)::
+
+    sector_size=$(gdisk -l fip_gpt.bin | grep -i "sector size (logical):" | \
+                sed 's/.*logical): \([0-9]*\) bytes/\1/')
+
+    fip_label=" FIP_A$"
+    fip_start_sector=$(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $2}')
+    fip_sector_am=$(gdisk -l fip_gpt.bin | grep "$fip_label" | awk '{print $3 - $2}')
+
+    dd if=fip_gpt.bin of=fip.bin bs=$sector_size skip=$fip_start_sector \
+        count=$fip_sector_am conv=notrunc
+
+Once the ``fip_gpt.bin`` is prepared, it is placed at the base of the host flash
+image::
+
+    srec_cat \
+            fip_gpt.bin -Binary -offset 0x0 \
+            -o host_flash.bin -Binary
 
 The ROM binary should be placed in RSS ROM at ``0x11000000`` and the host flash
 binary should be placed at the base of the host flash. For the TC platform,
-this is at ``0x08000000``.
+this is at ``0x80000000``.
 
 --------------
 
diff --git a/platform/ext/target/arm/rss/common/CMakeLists.txt b/platform/ext/target/arm/rss/common/CMakeLists.txt
index ee26e60..a71bf1e 100644
--- a/platform/ext/target/arm/rss/common/CMakeLists.txt
+++ b/platform/ext/target/arm/rss/common/CMakeLists.txt
@@ -22,6 +22,7 @@
     INTERFACE
         $<$<BOOL:${RSS_XIP}>:RSS_XIP>
         $<$<BOOL:${RSS_DEBUG_UART}>:RSS_DEBUG_UART>
+        $<$<BOOL:${RSS_GPT_SUPPORT}>:RSS_GPT_SUPPORT>
 )
 
 #========================= Platform common defs ===============================#
@@ -262,6 +263,9 @@
         native_drivers/lcm_drv.c
         otp_lcm.c
         nv_counters.c
+        fip_parser/fip_parser.c
+        fip_parser/host_flash_atu.c
+        $<$<BOOL:${RSS_GPT_SUPPORT}>:${CMAKE_CURRENT_SOURCE_DIR}/fip_parser/gpt.c>
 )
 
 target_include_directories(platform_bl2
@@ -281,6 +285,7 @@
     PRIVATE
         ${PLATFORM_DIR}/..
         native_drivers
+        ./fip_parser
 )
 
 target_compile_definitions(platform_bl2
@@ -309,9 +314,9 @@
 target_sources(platform_bl1
     PRIVATE
         ./bl1/boot_hal_bl1.c
-        $<$<NOT:$<BOOL:${TFM_BL1_MEMORY_MAPPED_FLASH}>>:${CMAKE_CURRENT_SOURCE_DIR}/cmsis_drivers/Driver_Flash.c>
-        $<$<NOT:$<BOOL:${TFM_BL1_MEMORY_MAPPED_FLASH}>>:${CMAKE_CURRENT_SOURCE_DIR}/native_drivers/cfi_drv.c>
-        $<$<NOT:$<BOOL:${TFM_BL1_MEMORY_MAPPED_FLASH}>>:${CMAKE_CURRENT_SOURCE_DIR}/native_drivers/spi_strataflashj3_flash_lib.c>
+        cmsis_drivers/Driver_Flash.c
+        native_drivers/cfi_drv.c
+        native_drivers/spi_strataflashj3_flash_lib.c
         ./device/source/device_definition.c
         ./device/source/host_device_definition.c
         ./device/source/system_core_init.c
@@ -325,6 +330,9 @@
         ./otp_lcm.c
         ./nv_counters.c
         ./tfm_hal_platform_reset.c
+        ./fip_parser/fip_parser.c
+        ./fip_parser/host_flash_atu.c
+        $<$<BOOL:${RSS_GPT_SUPPORT}>:${CMAKE_CURRENT_SOURCE_DIR}/fip_parser/gpt.c>
 )
 
 target_include_directories(platform_bl1_interface
@@ -335,6 +343,7 @@
         ./device/config
         ./device/include
         ./native_drivers
+        ./fip_parser
 )
 
 target_compile_definitions(platform_bl1
diff --git a/platform/ext/target/arm/rss/common/bl1/boot_hal_bl1.c b/platform/ext/target/arm/rss/common/bl1/boot_hal_bl1.c
index 80ef504..a54ee7e 100644
--- a/platform/ext/target/arm/rss/common/bl1/boot_hal_bl1.c
+++ b/platform/ext/target/arm/rss/common/bl1/boot_hal_bl1.c
@@ -27,17 +27,31 @@
 #endif /* CRYPTO_HW_ACCELERATOR */
 #include <string.h>
 #include "cmsis_compiler.h"
+#include "fip_parser.h"
+#include "host_flash_atu.h"
+#include "plat_def_fip_uuid.h"
 
 extern uint8_t computed_bl1_2_hash[];
 extern uint32_t platform_code_is_bl1_2;
+uint32_t image_offsets[2];
 
-#ifndef TFM_BL1_MEMORY_MAPPED_FLASH
 /* Flash device name must be specified by target */
 extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
-#endif /* !TFM_BL1_MEMORY_MAPPED_FLASH */
 
 REGION_DECLARE(Image$$, ARM_LIB_STACK, $$ZI$$Base);
 
+uint32_t bl1_image_get_flash_offset(uint32_t image_id)
+{
+    switch (image_id) {
+    case 0:
+        return HOST_FLASH0_IMAGE0_BASE_S - FLASH_BASE_ADDRESS + image_offsets[0];
+    case 1:
+        return HOST_FLASH0_IMAGE1_BASE_S - FLASH_BASE_ADDRESS + image_offsets[1];
+    default:
+        FIH_PANIC;
+    }
+}
+
 static int32_t init_atu_regions(void)
 {
     enum atu_error_t err;
@@ -53,26 +67,6 @@
     }
 #endif /* !RSS_DEBUG_UART */
 
-    /* Initialize BL2 slot 0 region */
-    err = atu_initialize_region(&ATU_DEV_S,
-                                0,
-                                HOST_FLASH0_BASE_S + FLASH_AREA_0_OFFSET,
-                                HOST_FLASH0_BASE + FLASH_AREA_0_OFFSET,
-                                FLASH_AREA_0_SIZE);
-    if (err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    /* Initialize BL2 slot 1 region */
-    err = atu_initialize_region(&ATU_DEV_S,
-                                1,
-                                HOST_FLASH0_BASE_S + FLASH_AREA_1_OFFSET,
-                                HOST_FLASH0_BASE + FLASH_AREA_1_OFFSET,
-                                FLASH_AREA_1_SIZE);
-    if (err != ATU_ERR_NONE) {
-        return 1;
-    }
-
     return 0;
 }
 
@@ -101,12 +95,10 @@
     stdio_init();
 #endif /* defined(TFM_BL1_LOGGING) || defined(TEST_BL1_1) || defined(TEST_BL1_2) */
 
-#ifndef TFM_BL1_MEMORY_MAPPED_FLASH
     result = FLASH_DEV_NAME.Initialize(NULL);
     if (result != ARM_DRIVER_OK) {
         return 1;
     }
-#endif /* !TFM_BL1_MEMORY_MAPPED_FLASH */
 
     result = bl1_trng_generate_random(prbg_seed, sizeof(prbg_seed));
     if (result != 0) {
@@ -118,6 +110,11 @@
         return result;
     }
 
+    result = host_flash_atu_init_regions_for_image(UUID_RSS_FIRMWARE_BL2, image_offsets);
+    if (result) {
+        return result;
+    }
+
     if(!platform_code_is_bl1_2) {
         /* Clear boot data area */
         memset((void*)BOOT_TFM_SHARED_DATA_BASE, 0, BOOT_TFM_SHARED_DATA_SIZE);
@@ -173,6 +170,14 @@
     static struct boot_arm_vector_table *vt_cpy;
     int32_t result;
 
+    if (platform_code_is_bl1_2) {
+        result = host_flash_atu_uninit_regions();
+        if (result) {
+            while(1){}
+        }
+    }
+
+
     result = invalidate_hardware_keys();
     if (result) {
         while(1){}
@@ -185,12 +190,10 @@
     }
 #endif /* CRYPTO_HW_ACCELERATOR */
 
-#ifndef TFM_BL1_MEMORY_MAPPED_FLASH
     result = FLASH_DEV_NAME.Uninitialize();
     if (result != ARM_DRIVER_OK) {
         while (1){}
     }
-#endif /* TFM_BL1_MEMORY_MAPPED_FLASH */
 
 #if defined(TFM_BL1_LOGGING) || defined(TEST_BL1_1) || defined(TEST_BL1_2)
     stdio_uninit();
@@ -224,8 +227,6 @@
     /* The KMU requires word alignment */
     uint8_t __ALIGNED(4) tmp_buf[32];
 
-    (void)image_id;
-
     rc = tfm_plat_otp_read(PLAT_OTP_ID_LCS, sizeof(lcs), (uint8_t *)&lcs);
     if (rc) {
         return rc;
diff --git a/platform/ext/target/arm/rss/common/cmsis_drivers/Driver_Flash.c b/platform/ext/target/arm/rss/common/cmsis_drivers/Driver_Flash.c
index b08ccd7..2369c9b 100644
--- a/platform/ext/target/arm/rss/common/cmsis_drivers/Driver_Flash.c
+++ b/platform/ext/target/arm/rss/common/cmsis_drivers/Driver_Flash.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -108,7 +108,7 @@
 #if (RTE_FLASH0)
 static ARM_FLASH_INFO ARM_FLASH0_DEV_DATA = {
     .sector_info    = NULL,     /* Uniform sector layout */
-    .sector_count   = HOST_FLASH0_SIZE / 0x1000,
+    .sector_count   = HOST_ACCESS_SIZE / 0x1000,
     .sector_size    = 0x1000,
     .page_size      = 256U,
     .program_unit   = 1U,
diff --git a/platform/ext/target/arm/rss/common/device/source/host_device_definition.c b/platform/ext/target/arm/rss/common/device/source/host_device_definition.c
index 5f359e3..978d232 100644
--- a/platform/ext/target/arm/rss/common/device/source/host_device_definition.c
+++ b/platform/ext/target/arm/rss/common/device/source/host_device_definition.c
@@ -84,7 +84,10 @@
 
 #if (defined (SPI_STRATAFLASHJ3_S) && defined (CFI_S))
 static const struct cfi_dev_cfg_t CFI_DEV_CFG_S = {
-    .base = HOST_FLASH0_BASE_S
+    /* Define the flash base/size to be the same as the host access area, as the
+     * flash may not be mapped contiguously or predictably within that area.
+     */
+    .base = HOST_ACCESS_BASE_S,
 };
 struct cfi_dev_t CFI_DEV_S = {
     .cfg = &CFI_DEV_CFG_S,
diff --git a/platform/ext/target/arm/rss/common/fip_parser/fip_parser.c b/platform/ext/target/arm/rss/common/fip_parser/fip_parser.c
new file mode 100644
index 0000000..dd8fbc5
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/fip_parser.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "fip_parser.h"
+
+#include "flash_layout.h"
+#include "Driver_Flash.h"
+
+#include <string.h>
+
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+int fip_get_entry_by_uuid(uint32_t fip_base, uint32_t atu_slot_size, uuid_t uuid,
+                          uint64_t *offset, size_t *size)
+{
+    ARM_FLASH_CAPABILITIES DriverCapabilities = FLASH_DEV_NAME.GetCapabilities();
+    /* Valid entries for data item width */
+    uint32_t data_width_byte[] = {
+        sizeof(uint8_t),
+        sizeof(uint16_t),
+        sizeof(uint32_t),
+    };
+    size_t data_width = data_width_byte[DriverCapabilities.data_width];
+    int rc;
+    uint32_t idx = 0;
+    fip_toc_header_t toc_header;
+    fip_toc_entry_t toc_entry;
+    uuid_t null_uuid;
+
+    /* The NULL UUID is all-zeroes */
+    memset(&null_uuid, 0, sizeof(null_uuid));
+
+    rc = FLASH_DEV_NAME.ReadData(fip_base - FLASH_BASE_ADDRESS, &toc_header,
+                                 sizeof(toc_header) / data_width);
+    if (rc != sizeof(toc_header) / data_width) {
+        return rc;
+    }
+
+    if (toc_header.name != TOC_HEADER_NAME) {
+        return 2;
+    }
+
+    idx += sizeof(toc_header);
+
+    do {
+        /* Prevent reading out of bounds */
+        if (idx + sizeof(toc_entry) > atu_slot_size) {
+            return 3;
+        }
+
+        rc = FLASH_DEV_NAME.ReadData(fip_base + idx - FLASH_BASE_ADDRESS,
+                                     &toc_entry, sizeof(toc_entry) / data_width);
+        if (rc != sizeof(toc_entry) / data_width) {
+            return rc;
+        }
+
+        if (!memcmp(&uuid, &toc_entry.uuid, sizeof(uuid))) {
+            *offset = toc_entry.offset_address;
+
+            /* We can't deal with partitions that are greater than UINT32_MAX,
+             * since they aren't wholly mappable into the RSS memory space. This
+             * is in reality bounded by the ATU mappable size, but that'll be
+             * checked once the ATU region is set up, this just allows us to
+             * perform safe type-conversion.
+             */
+            if (toc_entry.size > UINT32_MAX) {
+                return 1;
+            }
+
+            *size = (uint32_t)toc_entry.size;
+
+            return 0;
+        }
+
+        idx += sizeof(toc_entry);
+        /* The FIP's TOC ends in an entry with a NULL UUID. This entry's size is
+         * the size of the whole FIP. */
+    } while (memcmp(&null_uuid, &toc_entry.uuid, sizeof(uuid_t)));
+
+    /* UUID not found, return error. */
+    return 3;
+}
diff --git a/platform/ext/target/arm/rss/common/fip_parser/fip_parser.h b/platform/ext/target/arm/rss/common/fip_parser/fip_parser.h
new file mode 100644
index 0000000..b613a46
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/fip_parser.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __FIP_PARSER_H__
+#define __FIP_PARSER_H__
+
+#include "firmware_image_package.h"
+#include "stddef.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief                    Parse a FIP and retrieve the offset and size of one
+ *                           of the firmware images (specified by UUID).
+ *
+ * \param[in]  fip_base      The RSS address mapped to the FIP base address in
+ *                           host flash.
+ * \param[in]  atu_slot_size The size of the ATU region that was mapped for
+ *                           access to this FIP. This is used to prevent reads
+ *                           outside the mapped region.
+ * \param[in]  uuid          The UUID of the firmware image to get the offset
+ *                           and size of.
+ *
+ * \param[out] offset        The offset in host flash of the firmware image.
+ * \param[out] size          The size of the firmware image.
+ *
+ * \return                   0 if operation completed successfully, another
+ *                           value on error.
+ */
+int fip_get_entry_by_uuid(uint32_t fip_base, uint32_t atu_slot_size, uuid_t uuid,
+                          uint64_t *offset, size_t *size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FIP_PARSER_H__ */
diff --git a/platform/ext/target/arm/rss/common/fip_parser/firmware_image_package.h b/platform/ext/target/arm/rss/common/fip_parser/firmware_image_package.h
new file mode 100644
index 0000000..7f0a618
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/firmware_image_package.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef FIRMWARE_IMAGE_PACKAGE_H
+#define FIRMWARE_IMAGE_PACKAGE_H
+
+#include <stdint.h>
+
+#include "uuid.h"
+
+/* This is used as a signature to validate the blob header */
+#define TOC_HEADER_NAME 0xAA640001
+
+typedef struct fip_toc_header {
+    uint32_t name;
+    uint32_t serial_number;
+    uint64_t flags;
+} fip_toc_header_t;
+
+typedef struct fip_toc_entry {
+    uuid_t   uuid;
+    uint64_t offset_address;
+    uint64_t size;
+    uint64_t flags;
+} fip_toc_entry_t;
+
+#endif /* FIRMWARE_IMAGE_PACKAGE_H */
diff --git a/platform/ext/target/arm/rss/common/fip_parser/gpt.c b/platform/ext/target/arm/rss/common/fip_parser/gpt.c
new file mode 100644
index 0000000..74d157b
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/gpt.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "gpt.h"
+
+#include "flash_layout.h"
+#include "Driver_Flash.h"
+
+#include <string.h>
+
+extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
+
+/* GPT has UTF-16LE strings, but we don't want to support them. FIP partitions
+ * are always labelled using ANSI characters, so this function compares the
+ * digits of the UTF-16LE string to an ANSI string.
+ */
+static int gpt_strncmp(uint16_t *gpt_str, size_t gpt_maxlen, uint8_t *str,
+                       size_t str_len)
+{
+    size_t idx;
+
+    if (str_len > gpt_maxlen) {
+        return 1;
+    }
+
+    for (idx = 0; idx < str_len; idx++) {
+        if (str[idx] != gpt_str[idx]) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+int gpt_get_header(uint32_t table_base, size_t atu_slot_size,
+                   gpt_header_t *header)
+{
+    ARM_FLASH_CAPABILITIES DriverCapabilities = FLASH_DEV_NAME.GetCapabilities();
+    /* Valid entries for data item width */
+    uint32_t data_width_byte[] = {
+        sizeof(uint8_t),
+        sizeof(uint16_t),
+        sizeof(uint32_t),
+    };
+    size_t data_width = data_width_byte[DriverCapabilities.data_width];
+    int rc;
+
+    if (atu_slot_size < sizeof(gpt_header_t)) {
+        return 1;
+    }
+
+    rc = FLASH_DEV_NAME.ReadData(table_base - FLASH_BASE_ADDRESS, header,
+                                 sizeof(gpt_header_t) / data_width);
+    if (rc != sizeof(gpt_header_t) / data_width) {
+        return rc;
+    }
+
+    if (memcmp(header->signature, "EFI PART", sizeof(header->signature))) {
+        return 1;
+    }
+
+    return 0;
+}
+
+int gpt_get_list_entry_by_name(uint32_t list_base, uint32_t list_num_entries,
+                               size_t list_entry_size, uint8_t *name,
+                               size_t name_size, size_t atu_slot_size,
+                               gpt_entry_t *entry)
+{
+    ARM_FLASH_CAPABILITIES DriverCapabilities = FLASH_DEV_NAME.GetCapabilities();
+    /* Valid entries for data item width */
+    uint32_t data_width_byte[] = {
+        sizeof(uint8_t),
+        sizeof(uint16_t),
+        sizeof(uint32_t),
+    };
+    size_t data_width = data_width_byte[DriverCapabilities.data_width];
+    int rc;
+    uint64_t idx;
+
+    /* List entry is using names larger than EFI_NAMELEN_MAX - this is either an
+     * RSS GPT config error or an out-of-spec GPT partition, either way we fail
+     * here.
+     */
+    if (list_entry_size > sizeof(gpt_entry_t)) {
+        return 1;
+    }
+
+    /* Check for overflow */
+    if (list_base + list_num_entries * list_entry_size < list_base ||
+        list_num_entries * list_entry_size > atu_slot_size) {
+        return 1;
+    }
+
+    for (idx = list_base;
+         idx < list_base + list_num_entries * list_entry_size;
+         idx += list_entry_size) {
+        rc = FLASH_DEV_NAME.ReadData(idx - FLASH_BASE_ADDRESS, entry,
+                                     sizeof(gpt_entry_t));
+        if (rc != sizeof(gpt_entry_t) / data_width) {
+            return rc;
+        }
+
+        if (gpt_strncmp(entry->name,
+                        list_entry_size - offsetof(gpt_entry_t, name),
+                        name, name_size)) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
diff --git a/platform/ext/target/arm/rss/common/fip_parser/gpt.h b/platform/ext/target/arm/rss/common/fip_parser/gpt.h
new file mode 100644
index 0000000..b52f3f6
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/gpt.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_H
+#define GPT_H
+
+#include "stdint.h"
+#include "stddef.h"
+#include "uuid.h"
+
+#define PARTITION_TYPE_GPT     0xee
+#define EFI_NAMELEN_MAX        36
+#define GPT_HEADER_OFFSET      PLAT_PARTITION_BLOCK_SIZE
+#define GPT_ENTRY_OFFSET       (GPT_HEADER_OFFSET + PLAT_PARTITION_BLOCK_SIZE)
+#define GPT_SIGNATURE          "EFI PART"
+#define PRIMARY_FIP_GPT_NAME   "FIP_A"
+#define SECONDARY_FIP_GPT_NAME "FIP_B"
+
+typedef struct gpt_entry {
+    struct efi_guid type_uuid;
+    struct efi_guid unique_uuid;
+    uint64_t        first_lba;
+    uint64_t        last_lba;
+    uint64_t        attr;
+    uint16_t        name[EFI_NAMELEN_MAX];
+} gpt_entry_t;
+
+typedef struct gpt_header {
+    uint8_t         signature[8];
+    uint32_t        revision;
+    uint32_t        size;
+    uint32_t        header_crc;
+    uint32_t        reserved;
+    uint64_t        current_lba;
+    uint64_t        backup_lba;
+    uint64_t        first_lba;
+    uint64_t        last_lba;
+    struct efi_guid disk_uuid;
+    /* starting LBA of array of partition entries */
+    uint64_t        list_lba;
+    /* number of partition entries in array */
+    uint32_t        list_num;
+    /* size of a single partition entry (usually 128) */
+    uint32_t        list_entry_size;
+    uint32_t        list_crc;
+} gpt_header_t;
+
+/**
+ * \brief                    Read a GPT header from flash into a struct.
+ *
+ * \param[in]  table_base    The RSS address mapped to the GPT table base in
+ *                           host flash.
+ * \param[in]  atu_slot_size The size of the ATU region that was mapped for
+ *                           access to this FIP. This is used to prevent reads
+ *                           outside the mapped region.
+ * \param[out] header        Pointer to a gpt_header_t struct that will be
+ *                           filled with the header data.
+ * \return                   0 if operation completed successfully, another
+ *                           value on error.
+ */
+int gpt_get_header(uint32_t table_base, size_t atu_slot_size,
+                   gpt_header_t *header);
+
+/**
+ * \brief                       Read a GPT list entry from flash into a struct.
+ *                              Which list entry should be read is determined
+ *                              by matching the name of the partition.
+ *
+ * \param[in]  list_base        The RSS address mapped to the GPT entry list base
+ *                              in host flash.
+ * \param[in]  list_num_entries The number of entries in the GPT entry list, as
+ *                              read from the header.
+ * \param[in]  list_entry_size  The size of entries in the GPT entry list, as
+ *                              read from the header.
+ * \param[in]  name             The name of the partition whose list entry
+ *                              should be read into the struct. Unlike the GPT
+ *                              list entry spec, this must be an ascii-encoded
+ *                              string.
+ * \param[in]  name_size        The size of the name string.
+ * \param[in]  atu_slot_size    The size of the ATU region that was mapped for
+ *                              access to this FIP. This is used to prevent
+ *                              reads outside the mapped region.
+ * \param[out] entry            Pointer to a gpt_entry_t struct that will be
+ *                              filled with the list entry data.
+ * \return                      0 if operation completed successfully, another
+ *                              value on error.
+ */
+int gpt_get_list_entry_by_name(uint32_t list_base, uint32_t list_num_entries,
+                               size_t list_entry_size, uint8_t *name,
+                               size_t name_size, size_t atu_slot_size,
+                               gpt_entry_t *entry);
+
+#endif /* GPT_H */
diff --git a/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.c b/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.c
new file mode 100644
index 0000000..e9098c2
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "host_flash_atu.h"
+
+#include "flash_layout.h"
+#include "device_definition.h"
+#include "gpt.h"
+#include "fip_parser.h"
+#include "plat_def_fip_uuid.h"
+#include "host_base_address.h"
+#include "platform_base_address.h"
+
+#include <string.h>
+
+#define RSS_ATU_REGION_TEMP_SLOT          2
+#define RSS_ATU_REGION_INPUT_IMAGE_SLOT_0 3
+#define RSS_ATU_REGION_INPUT_IMAGE_SLOT_1 4
+#define RSS_ATU_REGION_OUTPUT_IMAGE_SLOT  5
+
+static inline uint32_t round_down(uint32_t num, uint32_t boundary)
+{
+    return num - (num % boundary);
+}
+
+static inline uint32_t round_up(uint32_t num, uint32_t boundary)
+{
+    return (num + boundary - 1) - ((num + boundary - 1) % boundary);
+}
+
+static int setup_aligned_atu_slot(uint64_t physical_address, uint32_t size,
+                           uint32_t boundary, uint32_t atu_slot,
+                           uint32_t logical_address,
+                           uint32_t *alignment_offset,
+                           size_t   *atu_slot_size)
+{
+    uint64_t aligned_physical_address;
+    int err;
+
+    aligned_physical_address = round_down(physical_address, boundary);
+    *atu_slot_size = round_up(physical_address + size, boundary)
+                     - (physical_address);
+
+    *alignment_offset = physical_address - aligned_physical_address;
+
+    /* Sanity check our parameters, as we do _not_ trust them. We can only map
+     * within the host flash, the parameters must not overflow, and we cannot
+     * map further than the bounds of the logical address slot.
+     */
+    if (aligned_physical_address < HOST_FLASH0_BASE
+        || aligned_physical_address + *atu_slot_size > HOST_FLASH0_BASE + HOST_FLASH0_SIZE
+        || aligned_physical_address + *atu_slot_size < aligned_physical_address
+        || aligned_physical_address + *atu_slot_size < *atu_slot_size
+        || *atu_slot_size > 0x100000 /* Max image slot size */
+        || *alignment_offset > boundary) {
+        return 1;
+    }
+
+    err = atu_initialize_region(&ATU_DEV_S, atu_slot, logical_address,
+                                aligned_physical_address, *atu_slot_size);
+    if (err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    return 0;
+}
+
+int host_flash_atu_setup_image_input_slots_from_fip(uint64_t fip_offset,
+                                                    uint32_t slot,
+                                                    uintptr_t logical_address,
+                                                    uuid_t image_uuid,
+                                                    uint32_t *logical_address_offset)
+{
+    enum atu_error_t err;
+    int rc;
+    uint64_t region_offset;
+    size_t region_size;
+    uint64_t physical_address = HOST_FLASH0_BASE + fip_offset;
+    uint32_t alignment_offset;
+    size_t atu_slot_size;
+    size_t page_size = get_page_size(&ATU_DEV_S);
+
+    /* There's no way to tell how big the FIP TOC will be before reading it, so
+     * we just map 0x1000.
+     */
+    rc = setup_aligned_atu_slot(physical_address, 0x1000, page_size,
+                                RSS_ATU_REGION_TEMP_SLOT,
+                                HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
+                                &atu_slot_size);
+    if (rc) {
+        return rc;
+    }
+
+    rc = fip_get_entry_by_uuid(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
+                               atu_slot_size - alignment_offset,
+                               image_uuid, &region_offset, &region_size);
+    if (rc) {
+        return rc;
+    }
+
+    err = atu_uninitialize_region(&ATU_DEV_S, RSS_ATU_REGION_TEMP_SLOT);
+    if (err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    /* Initialize primary input region */
+    rc = setup_aligned_atu_slot(physical_address + region_offset, region_size,
+                                page_size, slot, logical_address,
+                                &alignment_offset, &atu_slot_size);
+    if (rc) {
+        return rc;
+    }
+
+    *logical_address_offset = alignment_offset;
+
+    return 0;
+}
+
+int host_flash_atu_get_fip_offsets(bool fip_found[2], uint64_t fip_offsets[2])
+{
+#ifdef RSS_GPT_SUPPORT
+    int rc;
+    enum atu_error_t err;
+    gpt_header_t header;
+    gpt_entry_t entry;
+    size_t page_size = get_page_size(&ATU_DEV_S);
+    uint64_t physical_address;
+    uint32_t alignment_offset;
+    size_t atu_slot_size;
+#endif /* RSS_GPT_SUPPORT */
+
+#ifdef RSS_GPT_SUPPORT
+    physical_address = HOST_FLASH0_BASE + FLASH_AREA_IMAGE_SECTOR_SIZE;
+    rc = setup_aligned_atu_slot(physical_address, FLASH_AREA_IMAGE_SECTOR_SIZE,
+                                page_size, RSS_ATU_REGION_TEMP_SLOT,
+                                HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
+                                &atu_slot_size);
+    if (rc) {
+        return rc;
+    }
+
+    rc = gpt_get_header(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
+                        atu_slot_size - alignment_offset, &header);
+    if (rc) {
+        return rc;
+    }
+
+    err = atu_uninitialize_region(&ATU_DEV_S,
+                                  RSS_ATU_REGION_TEMP_SLOT);
+    if (err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    physical_address = HOST_FLASH0_BASE
+                       + header.list_lba * FLASH_AREA_IMAGE_SECTOR_SIZE;
+    rc = setup_aligned_atu_slot(physical_address,
+                                header.list_entry_size * header.list_num, page_size,
+                                RSS_ATU_REGION_TEMP_SLOT,
+                                HOST_FLASH0_TEMP_BASE_S, &alignment_offset,
+                                &atu_slot_size);
+    if (rc) {
+        return rc;
+    }
+
+    rc = gpt_get_list_entry_by_name(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
+                                    header.list_num, header.list_entry_size,
+                                    (uint8_t *)PRIMARY_FIP_GPT_NAME,
+                                    sizeof(PRIMARY_FIP_GPT_NAME),
+                                    atu_slot_size - alignment_offset, &entry);
+    if (rc == 0) {
+        fip_found[0] = true;
+        fip_offsets[0] = entry.first_lba * FLASH_AREA_IMAGE_SECTOR_SIZE;
+    } else {
+        fip_found[0] = false;
+    }
+
+    rc = gpt_get_list_entry_by_name(HOST_FLASH0_TEMP_BASE_S + alignment_offset,
+                                    header.list_num, header.list_entry_size,
+                                    (uint8_t *)SECONDARY_FIP_GPT_NAME,
+                                    sizeof(SECONDARY_FIP_GPT_NAME),
+                                    atu_slot_size - alignment_offset, &entry);
+    if (rc == 0) {
+        fip_found[1] = true;
+        fip_offsets[1] = entry.first_lba * FLASH_AREA_IMAGE_SECTOR_SIZE;
+    } else {
+        fip_found[1] = false;
+    }
+
+    err = atu_uninitialize_region(&ATU_DEV_S,
+                                  RSS_ATU_REGION_TEMP_SLOT);
+    if (err != ATU_ERR_NONE) {
+        return 1;
+    }
+#else
+    fip_found[0] = true;
+    fip_offsets[0] = FLASH_FIP_A_OFFSET;
+    fip_found[1] = true;
+    fip_offsets[1] = FLASH_FIP_B_OFFSET;
+#endif /* RSS_GPT_SUPPORT */
+
+    return 0;
+}
+
+static int setup_image_input_slots(uuid_t image_uuid, uint32_t offsets[2])
+{
+    int rc;
+    bool fip_found[2];
+    uint64_t fip_offsets[2];
+    bool fip_mapped[2] = {false};
+
+    rc = host_flash_atu_get_fip_offsets(fip_found, fip_offsets);
+    if (rc) {
+        return rc;
+    }
+
+    /* MCUBoot requires that we map both regions. If we can only have the offset
+     * of one, then map it to both slots.
+     */
+    if (fip_found[0] && !fip_found[1]) {
+        fip_offsets[1] = fip_offsets[0];
+    } else if (fip_found[1] && !fip_found[0]) {
+        fip_offsets[0] = fip_offsets[1];
+    } else if (!fip_found[0] && !fip_found[1]) {
+        return 1;
+    }
+
+    rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[0],
+                                          RSS_ATU_REGION_INPUT_IMAGE_SLOT_0,
+                                          HOST_FLASH0_IMAGE0_BASE_S, image_uuid,
+                                          &offsets[0]);
+    if (rc == 0) {
+        fip_mapped[0] = true;
+    }
+
+    rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[1],
+                                          RSS_ATU_REGION_INPUT_IMAGE_SLOT_1,
+                                          HOST_FLASH0_IMAGE1_BASE_S, image_uuid,
+                                          &offsets[1]);
+    if (rc == 0) {
+        fip_mapped[1] = true;
+    }
+
+
+    /* If one of the mappings failed (more common without GPT support since in
+     * that case we're just hoping there's a FIP at the offset) then map the
+     * other one into the slot. At this stage if a backup map fails then it's an
+     * error since otherwise MCUBoot will attempt to access unmapped ATU space
+     * and fault.
+     */
+    if (fip_mapped[0] && !fip_mapped[1]) {
+        rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[0],
+                                              RSS_ATU_REGION_INPUT_IMAGE_SLOT_1,
+                                              HOST_FLASH0_IMAGE1_BASE_S,
+                                              image_uuid, &offsets[1]);
+        if (rc) {
+            return rc;
+        }
+    } else if (fip_mapped[1] && !fip_mapped[0]) {
+        rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offsets[1],
+                                              RSS_ATU_REGION_INPUT_IMAGE_SLOT_0,
+                                              HOST_FLASH0_IMAGE0_BASE_S,
+                                              image_uuid, &offsets[0]);
+        if (rc) {
+            return rc;
+        }
+    } else if (!fip_mapped[0] && !fip_mapped[1]) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static int setup_image_output_slots(uuid_t image_uuid)
+{
+    uuid_t case_uuid;
+    enum atu_error_t atu_err;
+
+    case_uuid = UUID_RSS_FIRMWARE_SCP_BL1;
+    if (memcmp(&image_uuid, &case_uuid, sizeof(uuid_t)) == 0) {
+        /* Initialize SCP ATU output region */
+        atu_err = atu_initialize_region(&ATU_DEV_S,
+                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
+                                        HOST_BOOT_IMAGE1_LOAD_BASE_S,
+                                        SCP_BL1_SRAM_BASE, SCP_BL1_MAX_SIZE);
+        if (atu_err != ATU_ERR_NONE) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    case_uuid = UUID_RSS_FIRMWARE_AP_BL1;
+    if (memcmp(&image_uuid, &case_uuid, sizeof(uuid_t)) == 0) {
+        /* Initialize AP ATU region */
+        atu_err = atu_initialize_region(&ATU_DEV_S,
+                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
+                                        HOST_BOOT_IMAGE0_LOAD_BASE_S,
+                                        AP_BL1_SRAM_BASE, AP_BL1_MAX_SIZE);
+        if (atu_err != ATU_ERR_NONE) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    return 0;
+}
+
+int host_flash_atu_init_regions_for_image(uuid_t image_uuid, uint32_t offsets[2])
+{
+    int rc;
+
+    rc = setup_image_input_slots(image_uuid, offsets);
+    if (rc) {
+        return rc;
+    }
+
+    rc = setup_image_output_slots(image_uuid);
+    if (rc) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int host_flash_atu_uninit_regions(void)
+{
+    enum atu_error_t atu_err;
+
+    atu_err = atu_uninitialize_region(&ATU_DEV_S,
+                                      RSS_ATU_REGION_INPUT_IMAGE_SLOT_0);
+    if (atu_err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    atu_err = atu_uninitialize_region(&ATU_DEV_S,
+                                      RSS_ATU_REGION_INPUT_IMAGE_SLOT_1);
+    if (atu_err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    atu_err = atu_uninitialize_region(&ATU_DEV_S,
+                                      RSS_ATU_REGION_OUTPUT_IMAGE_SLOT);
+    if (atu_err != ATU_ERR_NONE) {
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.h b/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.h
new file mode 100644
index 0000000..62d65fe
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/host_flash_atu.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __HOST_FLASH_ATU_H__
+#define __HOST_FLASH_ATU_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "uuid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief                  Gets the offsets of the FIPs in host flash. If GPT is
+ *                         supported these are parsed from the GPT partition
+ *                         list, else the hardcoded values are returned.
+ *
+ * \param[out] fip_found   Which fips were found. If fip_found[x] is 0, then the
+ *                         value of fip_offsets[x] is undefined.
+ * \param[out] fip_offsets The FIP offsets.
+ *
+ * \return                 0 on success, non-zero on failure.
+ */
+int host_flash_atu_get_fip_offsets(bool fip_found[2], uint64_t fip_offsets[2]);
+
+/**
+ * \brief                             Set up the input ATU slots so that an
+ *                                    image can be loaded from host flash.
+ *                                    Parses a FIP via an intermediate ATU slot
+ *                                    to find the image offset.
+ *
+ * \param[in] fip_offset              The host flash offset of the FIP that
+ *                                    should be parsed to find the image offset.
+ *
+ * \param[in] slot                    The ATU slot that should be setup as the
+ *                                    image input slot.
+ *
+ * \param[in] logical_address         The address in RSS memory to which the ATU
+ *                                    should map the image.
+ *
+ * \param[in] image_uuid              The UUID of the image that should be have
+ *                                    its slot set up. This is used when parsing
+ *                                    the FIP for the offset.
+ *
+ * \param[out] logical_address_offset The offset that the image has been mapped
+ *                                    at (so the base of the image is
+ *                                    logical_address + logical_address_offset).
+ *                                    This is required because images may not be
+ *                                    aligned to the ATU page size.
+ *
+ * \return                            0 on success, non-zero on failure.
+ */
+int host_flash_atu_setup_image_input_slots_from_fip(uint64_t fip_offset,
+                                                    uint32_t slot,
+                                                    uintptr_t logical_address,
+                                                    uuid_t image_uuid,
+                                                    uint32_t *logical_address_offset);
+
+/**
+ * \brief                             Setup the input and output slots for a
+ *                                    given image. returns the offsets from the
+ *                                    expected logical address that the image
+ *                                    has been mapped to (to account for images
+ *                                    not being aligned to the ATU page size).
+ *
+ * \param[in] image_uuid              The UUID of the image that should be have
+ *                                    its input and output slots set up.
+ *
+ * \param[out] offsets                The offsets that the primary and secondary
+ *                                    images for that particular UUID have been
+ *                                    mapped at (offset from their expected
+ *                                    logical addresses).
+ *
+ * \return                            0 on success, non-zero on failure.
+ */
+int host_flash_atu_init_regions_for_image(uuid_t image_uuid, uint32_t offsets[2]);
+
+/**
+ * \brief                             Teardown all image input and output slots.
+ *                                    Should be called between mapping different
+ *                                    images.
+ *
+ * \return                            0 on success, non-zero on failure.
+ */
+int host_flash_atu_uninit_regions(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HOST_FLASH_ATU_H__ */
diff --git a/platform/ext/target/arm/rss/common/fip_parser/uuid.h b/platform/ext/target/arm/rss/common/fip_parser/uuid.h
new file mode 100644
index 0000000..0ff01bb
--- /dev/null
+++ b/platform/ext/target/arm/rss/common/fip_parser/uuid.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2002 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Portions copyright (c) 2014-2020, ARM Limited and Contributors.
+ * All rights reserved.
+ */
+
+#ifndef UUID_H
+#define UUID_H
+
+/* Length of a node address (an IEEE 802 address). */
+#define _UUID_NODE_LEN  6
+
+/* Length of UUID string including dashes. */
+#define _UUID_STR_LEN   36
+
+/*
+ * See also:
+ *      http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
+ *      http://www.opengroup.org/onlinepubs/009629399/apdxa.htm
+ *
+ * A DCE 1.1 compatible source representation of UUIDs.
+ */
+struct uuid {
+    uint8_t time_low[4];
+    uint8_t time_mid[2];
+    uint8_t time_hi_and_version[2];
+    uint8_t clock_seq_hi_and_reserved;
+    uint8_t clock_seq_low;
+    uint8_t node[_UUID_NODE_LEN];
+};
+
+struct efi_guid {
+    uint32_t time_low;
+    uint16_t time_mid;
+    uint16_t time_hi_and_version;
+    uint8_t clock_seq_and_node[8];
+};
+
+union uuid_helper_t {
+    struct uuid uuid_struct;
+    struct efi_guid efi_guid;
+};
+
+/* XXX namespace pollution? */
+typedef struct uuid uuid_t;
+
+#endif /* UUID_H */
diff --git a/platform/ext/target/arm/rss/common/partition/platform_base_address.h b/platform/ext/target/arm/rss/common/partition/platform_base_address.h
index 17435d0..98f2997 100644
--- a/platform/ext/target/arm/rss/common/partition/platform_base_address.h
+++ b/platform/ext/target/arm/rss/common/partition/platform_base_address.h
@@ -133,16 +133,20 @@
 
 /* Secure Host region */
 #define HOST_ACCESS_BASE_S               0x70000000 /* Can access the Host region based on ATU config */
-#define HOST_ACCESS_LIMIT_S              (HOST_ACCESS_BASE_S + HOST_ACCESS_SIZE - 1)
+#define HOST_ACCESS_LIMIT_S              ((uint32_t)HOST_ACCESS_BASE_S + (uint32_t)HOST_ACCESS_SIZE - 1)
 
 /* ATU regions open in bootloader and runtime */
 #define HOST_UART0_BASE_S                (HOST_ACCESS_BASE_S + 0xFF00000) /* UART 0 Secure base address */
 /* ATU regions open in BL1 */
-#define HOST_FLASH0_BASE_S               (HOST_ACCESS_BASE_S + 0x200000) /* Host flash 0 address */
+#define HOST_FLASH0_TEMP_BASE_S          (HOST_ACCESS_BASE_S + 0x200000) /* Temporary address for mapping host flash areas */
+#define HOST_FLASH0_IMAGE0_BASE_S        (HOST_ACCESS_BASE_S + 0x300000) /* Host flash image 0 input secure address */
+#define HOST_FLASH0_IMAGE1_BASE_S        (HOST_ACCESS_BASE_S + 0x400000) /* Host flash image 1 input secure address */
 /* ATU regions open in BL2 */
-#define HOST_BOOT_IMAGE0_LOAD_BASE_S     (HOST_ACCESS_BASE_S + 0x000000) /* Host boot image 0 output address */
-#define HOST_BOOT_IMAGE1_LOAD_BASE_S     (HOST_ACCESS_BASE_S + 0x100000) /* Host boot image 1 output address */
-#define HOST_FLASH0_BASE_S               (HOST_ACCESS_BASE_S + 0x200000) /* Host flash 0 address */
+#define HOST_BOOT_IMAGE0_LOAD_BASE_S     (HOST_ACCESS_BASE_S + 0x000000) /* Host boot image 0 output secure address */
+#define HOST_BOOT_IMAGE1_LOAD_BASE_S     (HOST_ACCESS_BASE_S + 0x100000) /* Host boot image 1 output secure address */
+#define HOST_FLASH0_TEMP0_BASE_S         (HOST_ACCESS_BASE_S + 0x200000) /* Temporary secure address for mapping host flash areas */
+#define HOST_FLASH0_IMAGE0_BASE_S        (HOST_ACCESS_BASE_S + 0x300000) /* Host flash image 0 input secure address */
+#define HOST_FLASH0_IMAGE1_BASE_S        (HOST_ACCESS_BASE_S + 0x400000) /* Host flash image 1 input secure address */
 /* ATU regions open at runtime */
 #define FWU_HOST_IMAGE_BASE_S            (HOST_ACCESS_BASE_S + 0x000000) /* Region to allow writing new RSS FW images */
 #define HOST_COMMS_MAPPABLE_BASE_S       (HOST_ACCESS_BASE_S + 0x100000) /* Region into which to map host comms pointers */
diff --git a/platform/ext/target/arm/rss/common/target_cfg.c b/platform/ext/target/arm/rss/common/target_cfg.c
index c053d0c..23943df 100644
--- a/platform/ext/target/arm/rss/common/target_cfg.c
+++ b/platform/ext/target/arm/rss/common/target_cfg.c
@@ -36,6 +36,14 @@
 #endif
 
 const struct memory_region_limits memory_regions = {
+#ifdef RSS_XIP
+    .non_secure_code_start = RSS_RUNTIME_NS_XIP_BASE_NS,
+
+    .non_secure_partition_base = RSS_RUNTIME_NS_XIP_BASE_NS,
+
+    .non_secure_partition_limit = RSS_RUNTIME_NS_XIP_BASE_NS +
+                                  NS_PARTITION_SIZE - 1,
+#else
     .non_secure_code_start =
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
         BL2_HEADER_SIZE,
@@ -46,6 +54,7 @@
     .non_secure_partition_limit =
         (uint32_t)&REGION_NAME(Load$$LR$$, LR_NS_PARTITION, $$Base) +
         NS_PARTITION_SIZE - 1,
+#endif /* RSS_XIP */
 
 #ifndef TFM_MULTI_CORE_TOPOLOGY
     .veneer_base = (uint32_t)&REGION_NAME(Image$$, ER_VENEER, $$Base),
diff --git a/platform/ext/target/arm/rss/tc/CMakeLists.txt b/platform/ext/target/arm/rss/tc/CMakeLists.txt
index 59d8709..cf709bb 100644
--- a/platform/ext/target/arm/rss/tc/CMakeLists.txt
+++ b/platform/ext/target/arm/rss/tc/CMakeLists.txt
@@ -28,7 +28,6 @@
     PRIVATE
         bl2/boot_hal_bl2.c
         bl2/flash_map_bl2.c
-        bl2/host_flash_atu.c
         $<$<BOOL:${RSS_XIP}>:${CMAKE_CURRENT_SOURCE_DIR}/bl2/sic_boot.c>
 )
 
diff --git a/platform/ext/target/arm/rss/tc/bl2/boot_hal_bl2.c b/platform/ext/target/arm/rss/tc/bl2/boot_hal_bl2.c
index 3e0a4ec..294c3e2 100644
--- a/platform/ext/target/arm/rss/tc/bl2/boot_hal_bl2.c
+++ b/platform/ext/target/arm/rss/tc/bl2/boot_hal_bl2.c
@@ -28,12 +28,16 @@
 #include "Driver_Flash.h"
 #include "host_flash_atu.h"
 #include "sic_boot.h"
+#include "plat_def_fip_uuid.h"
+#include "flash_map/flash_map.h"
 
 #ifdef FLASH_DEV_NAME
 extern ARM_DRIVER_FLASH FLASH_DEV_NAME;
 #endif /* FLASH_DEV_NAME */
 
 extern struct boot_rsp rsp;
+extern struct flash_area flash_map[];
+extern const int flash_map_entry_num;
 
 int32_t boot_platform_post_init(void)
 {
@@ -86,9 +90,65 @@
     return 0;
 }
 
+static struct flash_area *flash_map_slot_from_flash_area_id(uint32_t area_id)
+{
+    uint32_t idx;
+    for (idx = 0; idx < flash_map_entry_num; idx++) {
+        if (area_id == flash_map[idx].fa_id) {
+            return &flash_map[idx];
+        }
+    }
+    return NULL;
+}
+
 int boot_platform_pre_load(uint32_t image_id)
 {
-    return host_flash_atu_pre_load(image_id);
+    uuid_t uuid;
+    uint32_t offsets[2];
+    struct flash_area *flash_area_primary =
+        flash_map_slot_from_flash_area_id(FLASH_AREA_IMAGE_PRIMARY(image_id));
+    struct flash_area *flash_area_secondary =
+        flash_map_slot_from_flash_area_id(FLASH_AREA_IMAGE_SECONDARY(image_id));
+    int rc;
+
+    if (flash_area_primary == NULL || flash_area_secondary == NULL) {
+        return 1;
+    }
+
+    switch(image_id) {
+    case RSS_BL2_IMAGE_SCP:
+        uuid = UUID_RSS_FIRMWARE_SCP_BL1;
+        break;
+    case RSS_BL2_IMAGE_AP:
+        uuid = UUID_RSS_FIRMWARE_AP_BL1;
+        break;
+    case RSS_BL2_IMAGE_NS:
+#ifndef RSS_XIP
+        uuid = UUID_RSS_FIRMWARE_NS;
+#else
+        uuid = UUID_RSS_SIC_TABLES_NS;
+#endif /* RSS_XIP */
+        break;
+    case RSS_BL2_IMAGE_S:
+#ifndef RSS_XIP
+        uuid = UUID_RSS_FIRMWARE_S;
+#else
+        uuid = UUID_RSS_SIC_TABLES_S;
+#endif /* RSS_XIP */
+        break;
+    default:
+        return 1;
+    }
+
+    rc = host_flash_atu_init_regions_for_image(uuid, offsets);
+    if (rc) {
+        return rc;
+    }
+
+    flash_area_primary->fa_off += offsets[0];
+    flash_area_secondary->fa_off += offsets[1];
+
+    return 0;
 }
 
 int boot_platform_post_load(uint32_t image_id)
@@ -131,7 +191,7 @@
         mhu_v2_x_channel_send(&MHU_RSS_TO_SCP_DEV, 0, 1);
     }
 
-    err = host_flash_atu_post_load(image_id);
+    err = host_flash_atu_uninit_regions();
     if (err) {
         return err;
     }
diff --git a/platform/ext/target/arm/rss/tc/bl2/flash_map_bl2.c b/platform/ext/target/arm/rss/tc/bl2/flash_map_bl2.c
index fdd4693..32919d2 100644
--- a/platform/ext/target/arm/rss/tc/bl2/flash_map_bl2.c
+++ b/platform/ext/target/arm/rss/tc/bl2/flash_map_bl2.c
@@ -22,7 +22,7 @@
 };
 const int flash_driver_entry_num = ARRAY_SIZE(flash_driver);
 
-const struct flash_area flash_map[] = {
+struct flash_area flash_map[] = {
 #ifdef RSS_XIP
     {
         .fa_id = FLASH_AREA_10_ID,
diff --git a/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.c b/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.c
deleted file mode 100644
index 2d9747c..0000000
--- a/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "host_flash_atu.h"
-
-#include "bl2_image_id.h"
-#include "flash_layout.h"
-#include "device_definition.h"
-#include "flash_map/flash_map.h"
-
-#define RSS_ATU_REGION_INPUT_IMAGE_SLOT_0 2
-#define RSS_ATU_REGION_INPUT_IMAGE_SLOT_1 3
-#define RSS_ATU_REGION_OUTPUT_IMAGE_SLOT  4
-
-#define HOST_BOOT_AP_LOAD_BASE_S  HOST_BOOT_IMAGE0_LOAD_BASE_S
-#define HOST_BOOT_SCP_LOAD_BASE_S HOST_BOOT_IMAGE1_LOAD_BASE_S
-
-extern struct flash_area flash_map[];
-extern int flash_map_entry_num;
-
-static struct flash_area *flash_map_slot_from_flash_area_id(uint32_t area_id)
-{
-    uint32_t idx;
-
-    for (idx = 0; idx < flash_map_entry_num; idx++) {
-        if (area_id == flash_map[idx].fa_id) {
-            return &flash_map[idx];
-        }
-    }
-
-    return NULL;
-}
-
-static int setup_image_input_slots(uint32_t image_id)
-{
-    enum atu_error_t err;
-    struct flash_area *flash_area_primary =
-        flash_map_slot_from_flash_area_id(FLASH_AREA_IMAGE_PRIMARY(image_id));
-    struct flash_area *flash_area_secondary =
-        flash_map_slot_from_flash_area_id(FLASH_AREA_IMAGE_SECONDARY(image_id));
-
-    if (flash_area_primary == NULL || flash_area_secondary == NULL) {
-        return 1;
-    }
-
-    /* Initialize primary input region */
-    err = atu_initialize_region(&ATU_DEV_S,
-                                RSS_ATU_REGION_INPUT_IMAGE_SLOT_0,
-                                HOST_FLASH0_BASE_S + flash_area_primary->fa_off,
-                                HOST_FLASH0_BASE + flash_area_primary->fa_off,
-                                flash_area_primary->fa_size);
-    if (err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    /* Initialize secondary input region */
-    err = atu_initialize_region(&ATU_DEV_S,
-                                RSS_ATU_REGION_INPUT_IMAGE_SLOT_1,
-                                HOST_FLASH0_BASE_S + flash_area_secondary->fa_off,
-                                HOST_FLASH0_BASE + flash_area_secondary->fa_off,
-                                flash_area_secondary->fa_size);
-    if (err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    return 0;
-}
-
-int host_flash_atu_pre_load(uint32_t image_id)
-{
-    int err;
-    enum atu_error_t atu_err;
-
-    err = setup_image_input_slots(image_id);
-    if (err != 0) {
-        return err;
-    }
-
-    switch (image_id) {
-    case RSS_BL2_IMAGE_SCP:
-        /* Initialize SCP ATU output region */
-        atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
-                                        HOST_BOOT_SCP_LOAD_BASE_S,
-                                        SCP_BL1_SRAM_BASE, SCP_BL1_MAX_SIZE);
-        if (atu_err != ATU_ERR_NONE) {
-            return 1;
-        }
-        break;
-    case RSS_BL2_IMAGE_AP:
-        /* Initialize AP ATU region */
-        atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
-                                        HOST_BOOT_AP_LOAD_BASE_S,
-                                        AP_BL1_SRAM_BASE, AP_BL1_MAX_SIZE);
-        if (atu_err != ATU_ERR_NONE) {
-            return 1;
-        }
-        break;
-    case RSS_BL2_IMAGE_NS:
-#ifndef RSS_XIP
-        /* Initialize AP ATU region */
-        atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
-                                        HOST_BOOT_AP_LOAD_BASE_S,
-                                        AP_BL1_SRAM_BASE, AP_BL1_MAX_SIZE);
-        if (atu_err != ATU_ERR_NONE) {
-            return 1;
-        }
-#endif /* !RSS_XIP */
-        break;
-    case RSS_BL2_IMAGE_S:
-#ifndef RSS_XIP
-        /* Initialize AP ATU region */
-        atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_REGION_OUTPUT_IMAGE_SLOT,
-                                        HOST_BOOT_AP_LOAD_BASE_S,
-                                        AP_BL1_SRAM_BASE, AP_BL1_MAX_SIZE);
-        if (atu_err != ATU_ERR_NONE) {
-            return 1;
-        }
-#endif /* !RSS_XIP */
-        break;
-    default:
-        return 1;
-    }
-
-    return 0;
-}
-
-int host_flash_atu_post_load(uint32_t image_id)
-{
-    enum atu_error_t atu_err;
-    (void)image_id;
-
-    atu_err = atu_uninitialize_region(&ATU_DEV_S,
-                                      RSS_ATU_REGION_INPUT_IMAGE_SLOT_0);
-    if (atu_err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    atu_err = atu_uninitialize_region(&ATU_DEV_S,
-                                      RSS_ATU_REGION_INPUT_IMAGE_SLOT_1);
-    if (atu_err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    atu_err = atu_uninitialize_region(&ATU_DEV_S,
-                                      RSS_ATU_REGION_OUTPUT_IMAGE_SLOT);
-    if (atu_err != ATU_ERR_NONE) {
-        return 1;
-    }
-
-    return 0;
-}
diff --git a/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.h b/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.h
deleted file mode 100644
index 102e1b7..0000000
--- a/platform/ext/target/arm/rss/tc/bl2/host_flash_atu.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#ifndef __HOST_FLASH_ATU_H__
-#define __HOST_FLASH_ATU_H__
-
-#include <stdint.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief                  Performs ATU setup so that the given image can be
- *                         accessed within the host flash.
- *
- * \param[in]  image_id    The image id to setup the ATU regions for.
- *
- * \return                 0 if The regions have been setup successfully.
- */
-int host_flash_atu_pre_load(uint32_t image_id);
-
-/**
- * \brief                  Performs ATU teardown to disable the regions setup
- *                         for the particular image.
- *
- * \param[in]  image_id    The image id to teardown the ATU regions for.
- *
- * \return                 0 if The regions have been disabled successfully.
- */
-int host_flash_atu_post_load(uint32_t image_id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __HOST_FLASH_ATU_H__ */
diff --git a/platform/ext/target/arm/rss/tc/bl2/sic_boot.c b/platform/ext/target/arm/rss/tc/bl2/sic_boot.c
index 8da41f8..be0d786 100644
--- a/platform/ext/target/arm/rss/tc/bl2/sic_boot.c
+++ b/platform/ext/target/arm/rss/tc/bl2/sic_boot.c
@@ -11,6 +11,10 @@
 #include "bl2_image_id.h"
 #include "region_defs.h"
 #include "tfm_plat_otp.h"
+#include "host_flash_atu.h"
+#include "plat_def_fip_uuid.h"
+
+#include <string.h>
 
 #define RSS_ATU_S_IMAGE_XIP_REGION  0
 #define RSS_ATU_NS_IMAGE_XIP_REGION 1
@@ -20,6 +24,9 @@
 
 #define FLASH_SIC_HTR_SIZE 0x800
 
+uint32_t s_image_offset;
+uint32_t ns_image_offset;
+
 struct rss_xip_htr_table {
     uint32_t fw_revision;
     uint32_t nonce[2];
@@ -51,7 +58,6 @@
 {
     enum sic_error_t sic_err;
     struct rss_xip_htr_table *table;
-    enum atu_error_t atu_err;
     uint32_t key[8];
     enum tfm_plat_err_t plat_err;
     size_t sic_page_size;
@@ -59,31 +65,40 @@
     uint32_t decrypt_region;
     uint32_t xip_region_base_addr;
     uint32_t xip_region_size;
+    uint64_t fip_offsets[2];
+    bool fip_found[2];
+    uint64_t fip_offset;
+    uint32_t atu_region;
+    uuid_t image_uuid;
+    uint32_t *image_offset;
+
+    int rc;
 
     sic_page_size = sic_page_size_get(&SIC_DEV_S);
 
+    rc = host_flash_atu_get_fip_offsets(fip_found, fip_offsets);
+    if (rc) {
+        return rc;
+    }
+
     switch (image_id) {
     case RSS_BL2_IMAGE_NS:
         table = (struct rss_xip_htr_table*)(BL2_XIP_TABLES_START
                                             + FLASH_SIC_TABLE_SIZE
                                             + BL2_HEADER_SIZE);
 
-        if (image_load_offset == FLASH_AREA_11_OFFSET) {
-            atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_NS_IMAGE_XIP_REGION,
-                                        RSS_RUNTIME_NS_XIP_BASE_S,
-                                        HOST_FLASH0_BASE + FLASH_AREA_3_OFFSET,
-                                        FLASH_AREA_3_SIZE);
-            if (atu_err != ATU_ERR_NONE) {
+        if (image_load_offset >= FLASH_AREA_11_OFFSET
+            && image_load_offset < FLASH_AREA_11_OFFSET + FLASH_AREA_11_SIZE) {
+            if (fip_found[0]) {
+                fip_offset = fip_offsets[0];
+            } else {
                 return 1;
             }
-        } else if (image_load_offset == FLASH_AREA_13_OFFSET) {
-            atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_NS_IMAGE_XIP_REGION,
-                                        RSS_RUNTIME_NS_XIP_BASE_S,
-                                        HOST_FLASH0_BASE + FLASH_AREA_5_OFFSET,
-                                        FLASH_AREA_5_SIZE);
-            if (atu_err != ATU_ERR_NONE) {
+        } else if (image_load_offset >= FLASH_AREA_13_OFFSET
+                   && image_load_offset < FLASH_AREA_13_OFFSET + FLASH_AREA_13_SIZE) {
+            if (fip_found[1]) {
+                fip_offset = fip_offsets[1];
+            } else {
                 return 1;
             }
         } else {
@@ -91,40 +106,34 @@
         }
 
         decrypt_key_otp_id = PLAT_OTP_ID_KEY_NON_SECURE_ENCRYPTION;
+        atu_region = RSS_ATU_NS_IMAGE_XIP_REGION;
         decrypt_region = RSS_SIC_NS_IMAGE_DECRYPT_REGION;
         xip_region_base_addr = RSS_RUNTIME_NS_XIP_BASE_S;
         xip_region_size      = NS_CODE_SIZE;
+        image_uuid = UUID_RSS_FIRMWARE_NS;
+        image_offset = &ns_image_offset;
 
         break;
     case RSS_BL2_IMAGE_S:
         table = (struct rss_xip_htr_table*)(BL2_XIP_TABLES_START + BL2_HEADER_SIZE);
 
-        if (image_load_offset == FLASH_AREA_10_OFFSET) {
-            atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_S_IMAGE_XIP_REGION,
-                                        RSS_RUNTIME_S_XIP_BASE_S,
-                                        HOST_FLASH0_BASE + FLASH_AREA_2_OFFSET,
-                                        FLASH_AREA_2_SIZE);
-            if (atu_err != ATU_ERR_NONE) {
-                return 1;
-            }
-        } else if (image_load_offset == FLASH_AREA_12_OFFSET) {
-            atu_err = atu_initialize_region(&ATU_DEV_S,
-                                        RSS_ATU_S_IMAGE_XIP_REGION,
-                                        RSS_RUNTIME_S_XIP_BASE_S,
-                                        HOST_FLASH0_BASE + FLASH_AREA_4_OFFSET,
-                                        FLASH_AREA_4_SIZE);
-            if (atu_err != ATU_ERR_NONE) {
-                return 1;
-            }
+        if (image_load_offset >= FLASH_AREA_10_OFFSET
+            && image_load_offset < FLASH_AREA_10_OFFSET + FLASH_AREA_10_SIZE) {
+            fip_offset = fip_offsets[0];
+        } else if (image_load_offset >= FLASH_AREA_12_OFFSET
+            && image_load_offset < FLASH_AREA_12_OFFSET + FLASH_AREA_12_SIZE) {
+            fip_offset = fip_offsets[1];
         } else {
             return 1;
         }
 
         decrypt_key_otp_id = PLAT_OTP_ID_KEY_SECURE_ENCRYPTION;
+        atu_region = RSS_ATU_S_IMAGE_XIP_REGION;
         decrypt_region = RSS_SIC_S_IMAGE_DECRYPT_REGION;
         xip_region_base_addr = RSS_RUNTIME_S_XIP_BASE_S;
         xip_region_size      = S_CODE_SIZE;
+        image_uuid = UUID_RSS_FIRMWARE_S;
+        image_offset = &s_image_offset;
 
         break;
 
@@ -135,6 +144,25 @@
         return 1;
     }
 
+    rc = host_flash_atu_setup_image_input_slots_from_fip(fip_offset,
+                                                         atu_region,
+                                                         xip_region_base_addr,
+                                                         image_uuid,
+                                                         image_offset);
+    if (rc) {
+        return rc;
+    }
+
+    /* RSS XIP images must be aligned to, at minimum, the SIC authentication
+     * page size and the SIC decrypt page size. Alignments that do not match
+     * the ATU page size cause problems in jumping to NS code, and seem to
+     * cause startup failure in some cases, so 8KiB alignment is required.
+     */
+    if (*image_offset % 0x1000 != 0) {
+        return 1;
+    }
+
+
     sic_err = sic_auth_table_set(&SIC_DEV_S, (uint32_t*)(table->htr),
                                  table->htr_size, (xip_region_base_addr
                                                    - SIC_HOST_BASE_S)
@@ -178,7 +206,7 @@
         return 1;
     }
 
-    *vt_cpy = (struct boot_arm_vector_table *)RSS_RUNTIME_S_XIP_BASE_S;
+    *vt_cpy = (struct boot_arm_vector_table *)(RSS_RUNTIME_S_XIP_BASE_S + s_image_offset);
 
     return 0;
 }
diff --git a/platform/ext/target/arm/rss/tc/flash_layout.h b/platform/ext/target/arm/rss/tc/flash_layout.h
index 644cdf0..df3aec8 100644
--- a/platform/ext/target/arm/rss/tc/flash_layout.h
+++ b/platform/ext/target/arm/rss/tc/flash_layout.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2023, 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.
@@ -18,6 +18,7 @@
 #define __FLASH_LAYOUT_H__
 
 #include "host_base_address.h"
+#include "platform_base_address.h"
 
 /* Flash layout on RSS with XIP mode disabled:
  *
@@ -49,7 +50,6 @@
  * with comment.
  */
 
-
 /* Size of a Secure and of a Non-secure image */
 #define FLASH_BL2_PARTITION_SIZE        (0x10000) /* BL2 partition: 128 KiB */
 #define FLASH_S_PARTITION_SIZE          (0x60000) /* S   partition: 384 KiB */
@@ -69,11 +69,14 @@
 #endif /* RSS_XIP */
 
 /* Sector size of the flash hardware; same as FLASH0_SECTOR_SIZE */
-#define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x1000)    /* 4 KB */
+#define FLASH_AREA_IMAGE_SECTOR_SIZE    (0x200)    /* 1 KiB */
 /* Same as FLASH0_SIZE */
 #define FLASH_TOTAL_SIZE                (0xFC00000)  /* 252 MiB */
 
-#define FLASH_BASE_ADDRESS              (HOST_FLASH0_BASE_S)
+/* Flash offsets are offsets in the host ATU mapping space, to allow host flash
+ * to be mapped at any point in the mapping space.
+ */
+#define FLASH_BASE_ADDRESS              (HOST_ACCESS_BASE_S)
 
 /* Offset and size definitions of the flash partitions that are handled by the
  * bootloader. The image swapping is done between IMAGE_PRIMARY and
@@ -81,78 +84,77 @@
  * swapping.
  */
 
+#ifndef RSS_GPT_SUPPORT
+#define FLASH_FIP_A_OFFSET         0x0
+#define FLASH_FIP_B_OFFSET         (FLASH_FIP_A_OFFSET + 0x800000)
+#endif /* !RSS_GPT_SUPPORT */
+
 /* BL2 primary slot */
 #define FLASH_AREA_0_ID            (1)
-#define FLASH_AREA_0_OFFSET        (0)
+#define FLASH_AREA_0_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_0_SIZE          (FLASH_BL2_PARTITION_SIZE)
 /* BL2 secondary slot */
 #define FLASH_AREA_1_ID            (FLASH_AREA_0_ID + 1)
-#define FLASH_AREA_1_OFFSET        (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE)
+#define FLASH_AREA_1_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_1_SIZE          (FLASH_BL2_PARTITION_SIZE)
 
 /* Secure image primary slot. */
 #define FLASH_AREA_2_ID            (FLASH_AREA_1_ID + 1)
-#define FLASH_AREA_2_OFFSET        (FLASH_AREA_1_OFFSET + FLASH_AREA_1_SIZE)
+#define FLASH_AREA_2_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_2_SIZE          (FLASH_S_PARTITION_SIZE)
 /* Non-secure image primary slot. */
 #define FLASH_AREA_3_ID            (FLASH_AREA_2_ID + 1)
-#define FLASH_AREA_3_OFFSET        (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE)
+#define FLASH_AREA_3_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_3_SIZE          (FLASH_NS_PARTITION_SIZE)
 /* Secure image secondary slot. */
 #define FLASH_AREA_4_ID            (FLASH_AREA_3_ID + 1)
-#define FLASH_AREA_4_OFFSET        (FLASH_AREA_3_OFFSET + FLASH_AREA_3_SIZE)
+#define FLASH_AREA_4_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_4_SIZE          (FLASH_S_PARTITION_SIZE)
 /* Non-secure image secondary slot. */
 #define FLASH_AREA_5_ID            (FLASH_AREA_4_ID + 1)
-#define FLASH_AREA_5_OFFSET        (FLASH_AREA_4_OFFSET + FLASH_AREA_4_SIZE)
+#define FLASH_AREA_5_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_5_SIZE          (FLASH_NS_PARTITION_SIZE)
 
 /* AP image primary slot */
 #define FLASH_AREA_6_ID            (FLASH_AREA_5_ID + 1)
-#define FLASH_AREA_6_OFFSET        (FLASH_AREA_5_OFFSET + FLASH_AREA_5_SIZE)
+#define FLASH_AREA_6_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_6_SIZE          (FLASH_AP_PARTITION_SIZE)
 /* SCP image primary slot */
 #define FLASH_AREA_7_ID            (FLASH_AREA_6_ID + 1)
-#define FLASH_AREA_7_OFFSET        (FLASH_AREA_6_OFFSET + FLASH_AREA_6_SIZE)
+#define FLASH_AREA_7_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_7_SIZE          (FLASH_SCP_PARTITION_SIZE)
 /* AP image secondary slot */
 #define FLASH_AREA_8_ID            (FLASH_AREA_7_ID + 1)
-#define FLASH_AREA_8_OFFSET        (FLASH_AREA_7_OFFSET + FLASH_AREA_7_SIZE)
+#define FLASH_AREA_8_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_8_SIZE          (FLASH_AP_PARTITION_SIZE)
 /* SCP image secondary slot */
 #define FLASH_AREA_9_ID            (FLASH_AREA_8_ID + 1)
-#define FLASH_AREA_9_OFFSET        (FLASH_AREA_8_OFFSET + FLASH_AREA_8_SIZE)
+#define FLASH_AREA_9_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_9_SIZE          (FLASH_SCP_PARTITION_SIZE)
 
 #ifdef RSS_XIP
 /* Secure image SIC tables primary slot */
 #define FLASH_AREA_10_ID            (FLASH_AREA_9_ID + 1)
-#define FLASH_AREA_10_OFFSET        (FLASH_AREA_9_OFFSET + FLASH_AREA_9_SIZE)
+#define FLASH_AREA_10_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_10_SIZE          (FLASH_SIC_TABLE_SIZE)
 /* Non-secure image SIC tables primary slot */
 #define FLASH_AREA_11_ID            (FLASH_AREA_10_ID + 1)
-#define FLASH_AREA_11_OFFSET        (FLASH_AREA_10_OFFSET + FLASH_AREA_10_SIZE)
+#define FLASH_AREA_11_OFFSET        (HOST_FLASH0_IMAGE0_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_11_SIZE          (FLASH_SIC_TABLE_SIZE)
 /* Secure image SIC tables secondary slot */
 #define FLASH_AREA_12_ID            (FLASH_AREA_11_ID + 1)
-#define FLASH_AREA_12_OFFSET        (FLASH_AREA_11_OFFSET + FLASH_AREA_11_SIZE)
+#define FLASH_AREA_12_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_12_SIZE          (FLASH_SIC_TABLE_SIZE)
 /* Non-secure image SIC tables secondary slot */
 #define FLASH_AREA_13_ID            (FLASH_AREA_12_ID + 1)
-#define FLASH_AREA_13_OFFSET        (FLASH_AREA_12_OFFSET + FLASH_AREA_12_SIZE)
+#define FLASH_AREA_13_OFFSET        (HOST_FLASH0_IMAGE1_BASE_S - HOST_ACCESS_BASE_S)
 #define FLASH_AREA_13_SIZE          (FLASH_SIC_TABLE_SIZE)
 #endif /* RSS_XIP */
 
-
 /* Maximum number of image sectors supported by the bootloader. */
 #define MCUBOOT_MAX_IMG_SECTORS    (FLASH_MAX_PARTITION_SIZE / \
                                     FLASH_AREA_IMAGE_SECTOR_SIZE)
 
-/* Check that all the images can fit in the Flash area. */
-#if (FLASH_AREA_9_OFFSET + FLASH_AREA_9_SIZE > FLASH_TOTAL_SIZE)
-#error "Out of Flash memory!"
-#endif
-
 #ifdef RSS_XIP
 #define FLASH_AREA_IMAGE_PRIMARY(x)     (((x) == 0) ? FLASH_AREA_10_ID : \
                                          ((x) == 1) ? FLASH_AREA_11_ID : \
@@ -210,10 +212,8 @@
 /* Flash device name used by BL2
  * Name is defined in flash driver file: Driver_Flash.c
  */
-#ifndef TFM_BL1_MEMORY_MAPPED_FLASH
 #define FLASH_DEV_NAME Driver_FLASH0
 /* Smallest flash programmable unit in bytes */
 #define TFM_HAL_FLASH_PROGRAM_UNIT      (0x1)
-#endif /* !TFM_BL1_MEMORY_MAPPED_FLASH */
 
 #endif /* __FLASH_LAYOUT_H__ */
diff --git a/platform/ext/target/arm/rss/tc/host_base_address.h b/platform/ext/target/arm/rss/tc/host_base_address.h
index 6243560..48c886b 100644
--- a/platform/ext/target/arm/rss/tc/host_base_address.h
+++ b/platform/ext/target/arm/rss/tc/host_base_address.h
@@ -32,15 +32,7 @@
 #define HOST_UART_BASE     0x2A400000UL /* Host UART base address */
 #define HOST_UART_SIZE     0x2000U      /* 8KB */
 
-/* In future HOST_FLASH0_BASE should be set to the _actual_ base of the flash,
- * and we should implement some logic to locate the images (in a FIP, probably).
- * For now, define the base address at an offset large enough that it's not used
- * by the AP firmware images.
- */
-/* #define HOST_FLASH_BASE   0x08000000UL /1* Host flash base address *1/ */
-/* FIP size = 34 MB */
-/* Total boot flash size = 64 MB */
-#define HOST_FLASH0_BASE   0x0A200000UL /* Host flash base address */
-#define HOST_FLASH0_SIZE   0x1E00000    /* 30 MiB */
+#define HOST_FLASH0_BASE   0x08000000UL /* Host flash base address */
+#define HOST_FLASH0_SIZE   0x4000000    /* 64 MiB */
 
 #endif  /* __HOST_BASE_ADDRESS_H__ */
diff --git a/platform/ext/target/arm/rss/tc/plat_def_fip_uuid.h b/platform/ext/target/arm/rss/tc/plat_def_fip_uuid.h
new file mode 100644
index 0000000..b65feaa
--- /dev/null
+++ b/platform/ext/target/arm/rss/tc/plat_def_fip_uuid.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __PLAT_DEF_FIP_UUID__
+#define __PLAT_DEF_FIP_UUID__
+
+#include "uuid.h"
+
+#define UUID_RSS_FIRMWARE_BL1_2 \
+    ((uuid_t){{0x0a, 0xa5, 0xb1, 0xbe}, {0xe7, 0x84}, {0x41, 0xc5}, 0x81, 0xb8, {0x4a, 0x41, 0xcb, 0x4a, 0xd2, 0xdf}})
+#define UUID_RSS_FIRMWARE_BL2 \
+    ((uuid_t){{0xa3, 0xb3, 0xb3, 0x0d}, {0xeb, 0xc9}, {0x40, 0x48}, 0xb4, 0x80, {0x15, 0x53, 0x61, 0xc1, 0x70, 0x48}})
+#define UUID_RSS_FIRMWARE_SCP_BL1 \
+    ((uuid_t){{0xbf, 0xd5, 0x09, 0x8d}, {0xa7, 0x07}, {0x4f, 0x15}, 0x89, 0x1c, {0x37, 0x22, 0x10, 0xcb, 0x51, 0xe2}})
+#define UUID_RSS_FIRMWARE_AP_BL1 \
+    ((uuid_t){{0x12, 0x4c, 0x50, 0xe0}, {0xf2, 0xda}, {0x45, 0xe9}, 0x85, 0xc8, {0xda, 0xd9, 0x60, 0x9b, 0x7a, 0x11}})
+#define UUID_RSS_FIRMWARE_NS \
+    ((uuid_t){{0x8d, 0x95, 0x9f, 0x72}, {0xb8, 0xb1}, {0x42, 0x11}, 0x9a, 0xe6, {0x4b, 0x80, 0x97, 0x47, 0x5a, 0xd9}})
+#define UUID_RSS_FIRMWARE_S \
+    ((uuid_t){{0x22, 0xea, 0x33, 0x85}, {0xf8, 0x6e}, {0x47, 0x93}, 0x96, 0x8a, {0x2f, 0xe3, 0xdd, 0x50, 0x33, 0xcc}})
+#define UUID_RSS_SIC_TABLES_NS \
+    ((uuid_t){{0xd9, 0x10, 0x00, 0x72}, {0x6a, 0x28}, {0x4b, 0xec}, 0xb0, 0xd6, {0x8c, 0xed, 0xc4, 0x15, 0x7c, 0xe0}})
+#define UUID_RSS_SIC_TABLES_S \
+    ((uuid_t){{0xc7, 0x38, 0xd0, 0xde}, {0x8c, 0x26}, {0x48, 0x51}, 0x93, 0x36, {0xf3, 0xdb, 0xe2, 0x96, 0x65, 0x18}})
+
+#endif /* __PLAT_DEF_FIP_UUID__ */