Core: separate IPC and veneer fn-based code

Improve separation of IPC and veneer function-based code in the
source tree for memory optimization and better readability of source:
- Do not compile unused SVC handler functions if using IPC messaging
- Avoid activation of MPU regions not needed in selected build
  configuration
- Flag error if a service veneer function is called when running IPC
  messaging
- Do not include memory bounds for partitions in SPM database if
  level 1 isolation and veneer functions are used to save memory

Signed-off-by: Miklos Balint <miklos.balint@arm.com>
Change-Id: Iaef91e69061b639a71ec8cb638b6393762d10761
diff --git a/platform/ext/common/armclang/tfm_common_s.sct b/platform/ext/common/armclang/tfm_common_s.sct
index bef75d5..be87a0b 100644
--- a/platform/ext/common/armclang/tfm_common_s.sct
+++ b/platform/ext/common/armclang/tfm_common_s.sct
@@ -157,15 +157,10 @@
         .ANY (+RW +ZI)
     }
 
-#if TFM_LVL == 1
-#ifdef TFM_PSA_API
-    TFM_SECURE_STACK +0 ALIGN 128 EMPTY 0x0200 {
-    }
-#else
+#if (TFM_LVL == 1) && !defined(TFM_PSA_API)
     TFM_SECURE_STACK +0 ALIGN 128 EMPTY 0x2000 {
     }
-#endif /* TFM_PSA_API */
-#endif /* TFM_LVL == 1 */
+#endif /* (TFM_LVL == 1) && !defined(TFM_PSA_API) */
 
     TFM_UNPRIV_DATA +0 ALIGN 32 {
         tfm_spm_services.o (+RW +ZI)
@@ -177,10 +172,7 @@
         device_definition.o (+RW +ZI)
     }
 
-#ifdef TFM_PSA_API
-    TFM_UNPRIV_SCRATCH +0 ALIGN 32 EMPTY 0x0 {
-    }
-#else
+#if !defined(TFM_PSA_API)
     TFM_UNPRIV_SCRATCH +0 ALIGN 32 EMPTY 0x400 {
     }
 #endif /* TFM_PSA_API */
@@ -197,36 +189,52 @@
         *tfm_storage* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_STORAGE_STACK +0 ALIGN 128 EMPTY 0x1800 {
     }
+#endif
 
     TFM_SP_AUDIT_LOG_DATA +0 ALIGN 32 {
         *tfm_audit* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API)
+    TFM_SP_AUDIT_LOG_STACK +0 ALIGN 128 EMPTY 0 {
+    }
+#elif TFM_LVL != 1
     TFM_SP_AUDIT_LOG_STACK +0 ALIGN 128 EMPTY 0x0200 {
     }
+#endif
 
     TFM_SP_CRYPTO_DATA +0 ALIGN 32 {
         *tfm_crypto* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_CRYPTO_STACK +0 ALIGN 128 EMPTY 0x2000 {
     }
+#endif
 
     TFM_SP_PLATFORM_DATA +0 ALIGN 32 {
         *tfm_platform* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API)
+    TFM_SP_PLATFORM_STACK +0 ALIGN 128 EMPTY 0 {
+    }
+#elif TFM_LVL != 1
     TFM_SP_PLATFORM_STACK +0 ALIGN 128 EMPTY 0x0400 {
     }
+#endif
 
     TFM_SP_INITIAL_ATTESTATION_DATA +0 ALIGN 32 {
         *tfm_attest* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_INITIAL_ATTESTATION_STACK +0 ALIGN 128 EMPTY 0x0A00 {
     }
+#endif
 
 #ifdef TFM_PARTITION_TEST_SECURE_SERVICES
     TFM_SP_SECURE_TEST_PARTITION_DATA +0 ALIGN 32 {
@@ -240,8 +248,10 @@
         *attestation_s_interface_testsuite.* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_SECURE_TEST_PARTITION_STACK +0 ALIGN 128 EMPTY 0x0C00 {
     }
+#endif
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
 #ifdef TFM_PSA_API
@@ -249,8 +259,10 @@
         *ipc_service_test.* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_IPC_SERVICE_TEST_STACK +0 ALIGN 128 EMPTY 0x0200 {
     }
+#endif
 #endif /* TFM_PSA_API */
 
     /*
@@ -273,8 +285,10 @@
         *tfm_ss_core_test.* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_CORE_TEST_STACK +0 ALIGN 128 EMPTY 0x0300 {
     }
+#endif
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_CORE
@@ -282,8 +296,10 @@
         *tfm_ss_core_test_2.* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_CORE_TEST_2_STACK +0 ALIGN 128 EMPTY 0x0200 {
     }
+#endif
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PSA_API
@@ -291,8 +307,10 @@
         *ipc_client_test.* (+RW +ZI)
     }
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     TFM_SP_IPC_CLIENT_TEST_STACK +0 ALIGN 128 EMPTY 0x0200 {
     }
+#endif
 #endif /* TFM_PSA_API */
 
     /*
diff --git a/platform/ext/common/armclang/tfm_common_s.sct.template b/platform/ext/common/armclang/tfm_common_s.sct.template
index 5ff6546..5b86230 100644
--- a/platform/ext/common/armclang/tfm_common_s.sct.template
+++ b/platform/ext/common/armclang/tfm_common_s.sct.template
@@ -138,15 +138,10 @@
         .ANY (+RW +ZI)
     }
 
-#if TFM_LVL == 1
-#ifdef TFM_PSA_API
-    TFM_SECURE_STACK +0 ALIGN 128 EMPTY 0x0200 {
-    }
-#else
+#if (TFM_LVL == 1) && !defined(TFM_PSA_API)
     TFM_SECURE_STACK +0 ALIGN 128 EMPTY 0x2000 {
     }
-#endif /* TFM_PSA_API */
-#endif /* TFM_LVL == 1 */
+#endif /* (TFM_LVL == 1) && !defined(TFM_PSA_API) */
 
     TFM_UNPRIV_DATA +0 ALIGN 32 {
         tfm_spm_services.o (+RW +ZI)
@@ -158,10 +153,7 @@
         device_definition.o (+RW +ZI)
     }
 
-#ifdef TFM_PSA_API
-    TFM_UNPRIV_SCRATCH +0 ALIGN 32 EMPTY 0x0 {
-    }
-#else
+#if !defined(TFM_PSA_API)
     TFM_UNPRIV_SCRATCH +0 ALIGN 32 EMPTY 0x400 {
     }
 #endif /* TFM_PSA_API */
@@ -192,8 +184,20 @@
     {% endif %}
     }
 
+    {% if manifest.manifest.tfm_partition_ipc %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY {{manifest.manifest.stack_size}} {
     }
+#endif
+    {% else %}
+#if defined (TFM_PSA_API)
+    {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY 0 {
+    }
+#elif TFM_LVL != 1
+    {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY {{manifest.manifest.stack_size}} {
+    }
+#endif
+    {% endif %}
     {% if manifest.attr.conditional %}
 #endif /* {{manifest.attr.conditional}} */
     {% endif %}
@@ -233,8 +237,20 @@
     {% endif %}
     }
 
+    {% if manifest.manifest.tfm_partition_ipc %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY {{manifest.manifest.stack_size}} {
     }
+#endif
+    {% else %}
+#if defined (TFM_PSA_API)
+    {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY 0 {
+    }
+#elif TFM_LVL != 1
+    {{manifest.manifest.name}}_STACK +0 ALIGN 128 EMPTY {{manifest.manifest.stack_size}} {
+    }
+#endif
+    {% endif %}
     {% if manifest.attr.conditional %}
 #endif /* {{manifest.attr.conditional}} */
     {% endif %}
diff --git a/platform/ext/common/gcc/tfm_common_s.ld b/platform/ext/common/gcc/tfm_common_s.ld
index 7a57ff1..fa31129 100644
--- a/platform/ext/common/gcc/tfm_common_s.ld
+++ b/platform/ext/common/gcc/tfm_common_s.ld
@@ -117,6 +117,7 @@
         __zero_table_start__ = .;
         LONG (ADDR(.TFM_BSS))
         LONG (SIZEOF(.TFM_BSS))
+#if !defined(TFM_PSA_API)
 #if TFM_LVL == 1
         LONG (ADDR(.TFM_SECURE_STACK))
         LONG (SIZEOF(.TFM_SECURE_STACK))
@@ -124,58 +125,81 @@
         LONG (ADDR(.TFM_UNPRIV_BSS))
         LONG (SIZEOF(.TFM_UNPRIV_BSS))
 #endif /* TFM_LVL == 1 */
+#endif /* !defined(TFM_PSA_API) */
         LONG (ADDR(.TFM_SP_STORAGE_BSS))
         LONG (SIZEOF(.TFM_SP_STORAGE_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_STORAGE_STACK))
         LONG (SIZEOF(.TFM_SP_STORAGE_STACK))
+#endif
         LONG (ADDR(.TFM_SP_AUDIT_LOG_BSS))
         LONG (SIZEOF(.TFM_SP_AUDIT_LOG_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_AUDIT_LOG_STACK))
         LONG (SIZEOF(.TFM_SP_AUDIT_LOG_STACK))
+#endif
         LONG (ADDR(.TFM_SP_CRYPTO_BSS))
         LONG (SIZEOF(.TFM_SP_CRYPTO_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_CRYPTO_STACK))
         LONG (SIZEOF(.TFM_SP_CRYPTO_STACK))
+#endif
         LONG (ADDR(.TFM_SP_PLATFORM_BSS))
         LONG (SIZEOF(.TFM_SP_PLATFORM_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_PLATFORM_STACK))
         LONG (SIZEOF(.TFM_SP_PLATFORM_STACK))
+#endif
         LONG (ADDR(.TFM_SP_INITIAL_ATTESTATION_BSS))
         LONG (SIZEOF(.TFM_SP_INITIAL_ATTESTATION_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_INITIAL_ATTESTATION_STACK))
         LONG (SIZEOF(.TFM_SP_INITIAL_ATTESTATION_STACK))
+#endif
 #ifdef TFM_PARTITION_TEST_CORE
         LONG (ADDR(.TFM_SP_CORE_TEST_BSS))
         LONG (SIZEOF(.TFM_SP_CORE_TEST_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_CORE_TEST_STACK))
         LONG (SIZEOF(.TFM_SP_CORE_TEST_STACK))
+#endif
 #endif /* TFM_PARTITION_TEST_CORE */
 #ifdef TFM_PARTITION_TEST_CORE
         LONG (ADDR(.TFM_SP_CORE_TEST_2_BSS))
         LONG (SIZEOF(.TFM_SP_CORE_TEST_2_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_CORE_TEST_2_STACK))
         LONG (SIZEOF(.TFM_SP_CORE_TEST_2_STACK))
+#endif
 #endif /* TFM_PARTITION_TEST_CORE */
 #ifdef TFM_PARTITION_TEST_SECURE_SERVICES
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_BSS))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK))
         LONG (SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK))
+#endif
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 #ifdef TFM_PSA_API
         LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS))
         LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK))
         LONG (SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK))
+#endif
 #endif /* TFM_PSA_API */
 #ifdef TFM_PSA_API
         LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS))
         LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK))
         LONG (SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK))
+#endif
 #endif /* TFM_PSA_API */
+#if !defined(TFM_PSA_API)
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
+#endif /* !defined(TFM_PSA_API) */
         __zero_table_end__ = .;
     } > FLASH
 
@@ -429,16 +453,14 @@
 
 #if TFM_LVL == 1
 
+#if !defined(TFM_PSA_API)
     .TFM_SECURE_STACK : ALIGN(128)
     {
-#ifdef TFM_PSA_API
-        . += 0x0200;
-#else
         . += 0x2000;
-#endif /* TFM_PSA_API */
     } > RAM
     Image$$TFM_SECURE_STACK$$ZI$$Base = ADDR(.TFM_SECURE_STACK);
     Image$$TFM_SECURE_STACK$$ZI$$Limit = ADDR(.TFM_SECURE_STACK) + SIZEOF(.TFM_SECURE_STACK);
+#endif /* !defined(TFM_PSA_API) */
 
     .heap : ALIGN(8)
     {
@@ -486,16 +508,14 @@
     Image$$TFM_UNPRIV_DATA$$ZI$$Limit = ADDR(.TFM_UNPRIV_BSS) + SIZEOF(.TFM_UNPRIV_BSS);
 #endif /* TFM_LVL == 1 */
 
+#if !defined(TFM_PSA_API)
     .TFM_UNPRIV_SCRATCH : ALIGN(32)
     {
-#ifdef TFM_PSA_API
-        . += 0x0;
-#else
         . += 0x400;
-#endif /* TFM_PSA_API */
     } > RAM
     Image$$TFM_UNPRIV_SCRATCH$$ZI$$Base = ADDR(.TFM_UNPRIV_SCRATCH);
     Image$$TFM_UNPRIV_SCRATCH$$ZI$$Limit = ADDR(.TFM_UNPRIV_SCRATCH) + SIZEOF(.TFM_UNPRIV_SCRATCH);
+#endif /* !defined(TFM_PSA_API) */
 
     /**** PSA RoT DATA start here */
     Image$$TFM_PSA_RW_STACK_START$$Base = .;
@@ -517,12 +537,15 @@
     Image$$TFM_SP_STORAGE_DATA$$ZI$$Base = ADDR(.TFM_SP_STORAGE_BSS);
     Image$$TFM_SP_STORAGE_DATA$$ZI$$Limit = ADDR(.TFM_SP_STORAGE_BSS) + SIZEOF(.TFM_SP_STORAGE_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_STORAGE_STACK : ALIGN(128)
     {
         . += 0x1800;
     } > RAM
     Image$$TFM_SP_STORAGE_STACK$$ZI$$Base = ADDR(.TFM_SP_STORAGE_STACK);
     Image$$TFM_SP_STORAGE_STACK$$ZI$$Limit = ADDR(.TFM_SP_STORAGE_STACK) + SIZEOF(.TFM_SP_STORAGE_STACK);
+#endif
+
 
     .TFM_SP_AUDIT_LOG_DATA : ALIGN(32)
     {
@@ -541,12 +564,17 @@
     Image$$TFM_SP_AUDIT_LOG_DATA$$ZI$$Base = ADDR(.TFM_SP_AUDIT_LOG_BSS);
     Image$$TFM_SP_AUDIT_LOG_DATA$$ZI$$Limit = ADDR(.TFM_SP_AUDIT_LOG_BSS) + SIZEOF(.TFM_SP_AUDIT_LOG_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_AUDIT_LOG_STACK : ALIGN(128)
     {
+#if !defined(TFM_PSA_API)
         . += 0x0200;
+#endif
     } > RAM
     Image$$TFM_SP_AUDIT_LOG_STACK$$ZI$$Base = ADDR(.TFM_SP_AUDIT_LOG_STACK);
     Image$$TFM_SP_AUDIT_LOG_STACK$$ZI$$Limit = ADDR(.TFM_SP_AUDIT_LOG_STACK) + SIZEOF(.TFM_SP_AUDIT_LOG_STACK);
+#endif
+
 
     .TFM_SP_CRYPTO_DATA : ALIGN(32)
     {
@@ -565,12 +593,15 @@
     Image$$TFM_SP_CRYPTO_DATA$$ZI$$Base = ADDR(.TFM_SP_CRYPTO_BSS);
     Image$$TFM_SP_CRYPTO_DATA$$ZI$$Limit = ADDR(.TFM_SP_CRYPTO_BSS) + SIZEOF(.TFM_SP_CRYPTO_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_CRYPTO_STACK : ALIGN(128)
     {
         . += 0x2000;
     } > RAM
     Image$$TFM_SP_CRYPTO_STACK$$ZI$$Base = ADDR(.TFM_SP_CRYPTO_STACK);
     Image$$TFM_SP_CRYPTO_STACK$$ZI$$Limit = ADDR(.TFM_SP_CRYPTO_STACK) + SIZEOF(.TFM_SP_CRYPTO_STACK);
+#endif
+
 
     .TFM_SP_PLATFORM_DATA : ALIGN(32)
     {
@@ -589,12 +620,17 @@
     Image$$TFM_SP_PLATFORM_DATA$$ZI$$Base = ADDR(.TFM_SP_PLATFORM_BSS);
     Image$$TFM_SP_PLATFORM_DATA$$ZI$$Limit = ADDR(.TFM_SP_PLATFORM_BSS) + SIZEOF(.TFM_SP_PLATFORM_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_PLATFORM_STACK : ALIGN(128)
     {
+#if !defined(TFM_PSA_API)
         . += 0x0400;
+#endif
     } > RAM
     Image$$TFM_SP_PLATFORM_STACK$$ZI$$Base = ADDR(.TFM_SP_PLATFORM_STACK);
     Image$$TFM_SP_PLATFORM_STACK$$ZI$$Limit = ADDR(.TFM_SP_PLATFORM_STACK) + SIZEOF(.TFM_SP_PLATFORM_STACK);
+#endif
+
 
     .TFM_SP_INITIAL_ATTESTATION_DATA : ALIGN(32)
     {
@@ -613,12 +649,15 @@
     Image$$TFM_SP_INITIAL_ATTESTATION_DATA$$ZI$$Base = ADDR(.TFM_SP_INITIAL_ATTESTATION_BSS);
     Image$$TFM_SP_INITIAL_ATTESTATION_DATA$$ZI$$Limit = ADDR(.TFM_SP_INITIAL_ATTESTATION_BSS) + SIZEOF(.TFM_SP_INITIAL_ATTESTATION_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_INITIAL_ATTESTATION_STACK : ALIGN(128)
     {
         . += 0x0A00;
     } > RAM
     Image$$TFM_SP_INITIAL_ATTESTATION_STACK$$ZI$$Base = ADDR(.TFM_SP_INITIAL_ATTESTATION_STACK);
     Image$$TFM_SP_INITIAL_ATTESTATION_STACK$$ZI$$Limit = ADDR(.TFM_SP_INITIAL_ATTESTATION_STACK) + SIZEOF(.TFM_SP_INITIAL_ATTESTATION_STACK);
+#endif
+
 
 #ifdef TFM_PARTITION_TEST_SECURE_SERVICES
     .TFM_SP_SECURE_TEST_PARTITION_DATA : ALIGN(32)
@@ -659,12 +698,15 @@
     Image$$TFM_SP_SECURE_TEST_PARTITION_DATA$$ZI$$Base = ADDR(.TFM_SP_SECURE_TEST_PARTITION_BSS);
     Image$$TFM_SP_SECURE_TEST_PARTITION_DATA$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_BSS) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_SECURE_TEST_PARTITION_STACK : ALIGN(128)
     {
         . += 0x0C00;
     } > RAM
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Base = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK);
     Image$$TFM_SP_SECURE_TEST_PARTITION_STACK$$ZI$$Limit = ADDR(.TFM_SP_SECURE_TEST_PARTITION_STACK) + SIZEOF(.TFM_SP_SECURE_TEST_PARTITION_STACK);
+#endif
+
 #endif /* TFM_PARTITION_TEST_SECURE_SERVICES */
 
 #ifdef TFM_PSA_API
@@ -685,12 +727,15 @@
     Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS);
     Image$$TFM_SP_IPC_SERVICE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_BSS) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_IPC_SERVICE_TEST_STACK : ALIGN(128)
     {
         . += 0x0200;
     } > RAM
     Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK);
     Image$$TFM_SP_IPC_SERVICE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_SERVICE_TEST_STACK) + SIZEOF(.TFM_SP_IPC_SERVICE_TEST_STACK);
+#endif
+
 #endif /* TFM_PSA_API */
 
     /**** PSA RoT DATA end here */
@@ -717,12 +762,15 @@
     Image$$TFM_SP_CORE_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_CORE_TEST_BSS);
     Image$$TFM_SP_CORE_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_CORE_TEST_BSS) + SIZEOF(.TFM_SP_CORE_TEST_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_CORE_TEST_STACK : ALIGN(128)
     {
         . += 0x0300;
     } > RAM
     Image$$TFM_SP_CORE_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_CORE_TEST_STACK);
     Image$$TFM_SP_CORE_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_CORE_TEST_STACK) + SIZEOF(.TFM_SP_CORE_TEST_STACK);
+#endif
+
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PARTITION_TEST_CORE
@@ -743,12 +791,15 @@
     Image$$TFM_SP_CORE_TEST_2_DATA$$ZI$$Base = ADDR(.TFM_SP_CORE_TEST_2_BSS);
     Image$$TFM_SP_CORE_TEST_2_DATA$$ZI$$Limit = ADDR(.TFM_SP_CORE_TEST_2_BSS) + SIZEOF(.TFM_SP_CORE_TEST_2_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_CORE_TEST_2_STACK : ALIGN(128)
     {
         . += 0x0200;
     } > RAM
     Image$$TFM_SP_CORE_TEST_2_STACK$$ZI$$Base = ADDR(.TFM_SP_CORE_TEST_2_STACK);
     Image$$TFM_SP_CORE_TEST_2_STACK$$ZI$$Limit = ADDR(.TFM_SP_CORE_TEST_2_STACK) + SIZEOF(.TFM_SP_CORE_TEST_2_STACK);
+#endif
+
 #endif /* TFM_PARTITION_TEST_CORE */
 
 #ifdef TFM_PSA_API
@@ -769,12 +820,15 @@
     Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS);
     Image$$TFM_SP_IPC_CLIENT_TEST_DATA$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_BSS) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_BSS);
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .TFM_SP_IPC_CLIENT_TEST_STACK : ALIGN(128)
     {
         . += 0x0200;
     } > RAM
     Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Base = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK);
     Image$$TFM_SP_IPC_CLIENT_TEST_STACK$$ZI$$Limit = ADDR(.TFM_SP_IPC_CLIENT_TEST_STACK) + SIZEOF(.TFM_SP_IPC_CLIENT_TEST_STACK);
+#endif
+
 #endif /* TFM_PSA_API */
 
     /**** APPLICATION RoT DATA end here */
diff --git a/platform/ext/common/gcc/tfm_common_s.ld.template b/platform/ext/common/gcc/tfm_common_s.ld.template
index b985d83..4f0395d 100644
--- a/platform/ext/common/gcc/tfm_common_s.ld.template
+++ b/platform/ext/common/gcc/tfm_common_s.ld.template
@@ -88,6 +88,7 @@
         __zero_table_start__ = .;
         LONG (ADDR(.TFM_BSS))
         LONG (SIZEOF(.TFM_BSS))
+#if !defined(TFM_PSA_API)
 #if TFM_LVL == 1
         LONG (ADDR(.TFM_SECURE_STACK))
         LONG (SIZEOF(.TFM_SECURE_STACK))
@@ -95,20 +96,25 @@
         LONG (ADDR(.TFM_UNPRIV_BSS))
         LONG (SIZEOF(.TFM_UNPRIV_BSS))
 #endif /* TFM_LVL == 1 */
+#endif /* !defined(TFM_PSA_API) */
 {% for manifest in manifests %}
     {% if manifest.attr.conditional %}
 #ifdef {{manifest.attr.conditional}}
     {% endif %}
         LONG (ADDR(.{{manifest.manifest.name}}_BSS))
         LONG (SIZEOF(.{{manifest.manifest.name}}_BSS))
+#if defined(TFM_PSA_API) || (TFM_LVL != 1)
         LONG (ADDR(.{{manifest.manifest.name}}_STACK))
         LONG (SIZEOF(.{{manifest.manifest.name}}_STACK))
-    {% if manifest.attr.conditional %}
+#endif
+        {% if manifest.attr.conditional %}
 #endif /* {{manifest.attr.conditional}} */
     {% endif %}
 {% endfor %}
+#if !defined(TFM_PSA_API)
         LONG (ADDR(.TFM_UNPRIV_SCRATCH))
         LONG (SIZEOF(.TFM_UNPRIV_SCRATCH))
+#endif /* !defined(TFM_PSA_API) */
         __zero_table_end__ = .;
     } > FLASH
 
@@ -282,16 +288,14 @@
 
 #if TFM_LVL == 1
 
+#if !defined(TFM_PSA_API)
     .TFM_SECURE_STACK : ALIGN(128)
     {
-#ifdef TFM_PSA_API
-        . += 0x0200;
-#else
         . += 0x2000;
-#endif /* TFM_PSA_API */
     } > RAM
     Image$$TFM_SECURE_STACK$$ZI$$Base = ADDR(.TFM_SECURE_STACK);
     Image$$TFM_SECURE_STACK$$ZI$$Limit = ADDR(.TFM_SECURE_STACK) + SIZEOF(.TFM_SECURE_STACK);
+#endif /* !defined(TFM_PSA_API) */
 
     .heap : ALIGN(8)
     {
@@ -339,16 +343,14 @@
     Image$$TFM_UNPRIV_DATA$$ZI$$Limit = ADDR(.TFM_UNPRIV_BSS) + SIZEOF(.TFM_UNPRIV_BSS);
 #endif /* TFM_LVL == 1 */
 
+#if !defined(TFM_PSA_API)
     .TFM_UNPRIV_SCRATCH : ALIGN(32)
     {
-#ifdef TFM_PSA_API
-        . += 0x0;
-#else
         . += 0x400;
-#endif /* TFM_PSA_API */
     } > RAM
     Image$$TFM_UNPRIV_SCRATCH$$ZI$$Base = ADDR(.TFM_UNPRIV_SCRATCH);
     Image$$TFM_UNPRIV_SCRATCH$$ZI$$Limit = ADDR(.TFM_UNPRIV_SCRATCH) + SIZEOF(.TFM_UNPRIV_SCRATCH);
+#endif /* !defined(TFM_PSA_API) */
 
     /**** PSA RoT DATA start here */
     Image$$TFM_PSA_RW_STACK_START$$Base = .;
@@ -394,12 +396,29 @@
     Image$${{manifest.manifest.name}}_DATA$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_BSS);
     Image$${{manifest.manifest.name}}_DATA$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_BSS) + SIZEOF(.{{manifest.manifest.name}}_BSS);
 
+    {% if manifest.manifest.tfm_partition_ipc %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .{{manifest.manifest.name}}_STACK : ALIGN(128)
     {
         . += {{manifest.manifest.stack_size}};
     } > RAM
     Image$${{manifest.manifest.name}}_STACK$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_STACK);
     Image$${{manifest.manifest.name}}_STACK$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_STACK) + SIZEOF(.{{manifest.manifest.name}}_STACK);
+#endif
+    {% else %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
+    .{{manifest.manifest.name}}_STACK : ALIGN(128)
+    {
+        {# Note: Don't allocate stack for partition when using TFM_PSA_API if tfm_partition_ipc is false #}
+#if !defined(TFM_PSA_API)
+        . += {{manifest.manifest.stack_size}};
+#endif
+    } > RAM
+    Image$${{manifest.manifest.name}}_STACK$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_STACK);
+    Image$${{manifest.manifest.name}}_STACK$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_STACK) + SIZEOF(.{{manifest.manifest.name}}_STACK);
+#endif
+    {% endif %}
+
     {% if manifest.attr.conditional %}
 #endif /* {{manifest.attr.conditional}} */
     {% endif %}
@@ -453,12 +472,29 @@
     Image$${{manifest.manifest.name}}_DATA$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_BSS);
     Image$${{manifest.manifest.name}}_DATA$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_BSS) + SIZEOF(.{{manifest.manifest.name}}_BSS);
 
+    {% if manifest.manifest.tfm_partition_ipc %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
     .{{manifest.manifest.name}}_STACK : ALIGN(128)
     {
         . += {{manifest.manifest.stack_size}};
     } > RAM
     Image$${{manifest.manifest.name}}_STACK$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_STACK);
     Image$${{manifest.manifest.name}}_STACK$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_STACK) + SIZEOF(.{{manifest.manifest.name}}_STACK);
+#endif
+    {% else %}
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
+    .{{manifest.manifest.name}}_STACK : ALIGN(128)
+    {
+        {# Note: Don't allocate stack for partition when using TFM_PSA_API if tfm_partition_ipc is false #}
+#if !defined(TFM_PSA_API)
+        . += {{manifest.manifest.stack_size}};
+#endif
+    } > RAM
+    Image$${{manifest.manifest.name}}_STACK$$ZI$$Base = ADDR(.{{manifest.manifest.name}}_STACK);
+    Image$${{manifest.manifest.name}}_STACK$$ZI$$Limit = ADDR(.{{manifest.manifest.name}}_STACK) + SIZEOF(.{{manifest.manifest.name}}_STACK);
+#endif
+    {% endif %}
+
     {% if manifest.attr.conditional %}
 #endif /* {{manifest.attr.conditional}} */
     {% endif %}
diff --git a/platform/ext/target/mps2/an519/spm_hal.c b/platform/ext/target/mps2/an519/spm_hal.c
index 2ebac2e..a8c4ec5 100644
--- a/platform/ext/target/mps2/an519/spm_hal.c
+++ b/platform/ext/target/mps2/an519/spm_hal.c
@@ -63,8 +63,10 @@
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
+#ifndef TFM_PSA_API
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif
 #if TFM_LVL == 2
 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
@@ -275,6 +277,7 @@
     return SPM_ERR_OK;
 }
 
+#if !defined(TFM_PSA_API)
 /**
  * Set share region to which the partition needs access
  */
@@ -328,7 +331,7 @@
 
     return res;
 }
-
+#endif /* !defined(TFM_PSA_API) */
 #endif /* TFM_LVL != 1 */
 
 void tfm_spm_hal_setup_isolation_hw(void)
diff --git a/platform/ext/target/mps2/an521/spm_hal.c b/platform/ext/target/mps2/an521/spm_hal.c
index ecb244b..6a8d7be 100644
--- a/platform/ext/target/mps2/an521/spm_hal.c
+++ b/platform/ext/target/mps2/an521/spm_hal.c
@@ -63,8 +63,10 @@
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
+#ifndef TFM_PSA_API
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif
 #if TFM_LVL == 2
 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
@@ -275,6 +277,7 @@
     return SPM_ERR_OK;
 }
 
+#if !defined(TFM_PSA_API)
 /**
  * Set share region to which the partition needs access
  */
@@ -328,7 +331,7 @@
 
     return res;
 }
-
+#endif /* !defined(TFM_PSA_API) */
 #endif /* TFM_LVL != 1 */
 
 void tfm_spm_hal_setup_isolation_hw(void)
diff --git a/platform/ext/target/musca_a/spm_hal.c b/platform/ext/target/musca_a/spm_hal.c
index 85c4d76..11f618d 100644
--- a/platform/ext/target/musca_a/spm_hal.c
+++ b/platform/ext/target/musca_a/spm_hal.c
@@ -63,8 +63,10 @@
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
+#ifndef TFM_PSA_API
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif
 #if TFM_LVL == 2
 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
@@ -275,6 +277,7 @@
     return SPM_ERR_OK;
 }
 
+#if !defined(TFM_PSA_API)
 /**
  * Set share region to which the partition needs access
  */
@@ -328,7 +331,7 @@
 
     return res;
 }
-
+#endif /* !defined(TFM_PSA_API) */
 #endif /* TFM_LVL != 1 */
 
 void tfm_spm_hal_setup_isolation_hw(void)
diff --git a/platform/ext/target/musca_a/target_cfg.c b/platform/ext/target/musca_a/target_cfg.c
index bd12d31..f02518a 100644
--- a/platform/ext/target/musca_a/target_cfg.c
+++ b/platform/ext/target/musca_a/target_cfg.c
@@ -231,10 +231,6 @@
     SAU->RLAR = (PERIPHERALS_BASE_NS_END & SAU_RLAR_LADDR_Msk)
                 | SAU_RLAR_ENABLE_Msk;
 
-    /* FIXME: Secondary image partition info comes from BL2. Configure SAU
-     * based on those limits.
-     */
-
     /* Allows SAU to define the code region as a NSC */
     struct spctrl_def* spctrl = CMSDK_SPCTRL;
     spctrl->nsccfg |= NSCCFG_CODENSC;
diff --git a/platform/ext/target/musca_b1/spm_hal.c b/platform/ext/target/musca_b1/spm_hal.c
index 2d8f678..858c4d1 100644
--- a/platform/ext/target/musca_b1/spm_hal.c
+++ b/platform/ext/target/musca_b1/spm_hal.c
@@ -63,8 +63,10 @@
 REGION_DECLARE(Image$$, TFM_UNPRIV_CODE, $$RO$$Limit);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$RW$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_DATA, $$ZI$$Limit);
+#ifndef TFM_PSA_API
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif
 #if TFM_LVL == 2
 REGION_DECLARE(Image$$, TFM_APP_CODE_START, $$Base);
 REGION_DECLARE(Image$$, TFM_APP_CODE_END, $$Base);
@@ -275,6 +277,7 @@
     return SPM_ERR_OK;
 }
 
+#if !defined(TFM_PSA_API)
 /**
  * Set share region to which the partition needs access
  */
@@ -328,7 +331,7 @@
 
     return res;
 }
-
+#endif /* !defined(TFM_PSA_API) */
 #endif /* TFM_LVL != 1 */
 
 void tfm_spm_hal_setup_isolation_hw(void)
diff --git a/platform/include/tfm_spm_hal.h b/platform/include/tfm_spm_hal.h
index f1a82a0..3ce0b29 100644
--- a/platform/include/tfm_spm_hal.h
+++ b/platform/include/tfm_spm_hal.h
@@ -28,6 +28,7 @@
  */
 struct tfm_spm_partition_platform_data_t;
 
+#if defined (TFM_PSA_API) || (TFM_LVL != 1)
 /**
  * \brief Holds SPM db fields that define the memory regions used by a
  *        partition.
@@ -57,6 +58,7 @@
     uint32_t stack_bottom; /*!< The bottom of the stack for the partition. */
     uint32_t stack_top;    /*!< The top of the stack for the partition. */
 };
+#endif
 
 /**
  * \brief This function initialises the HW used for isolation, and sets the
@@ -145,7 +147,7 @@
 uint32_t tfm_spm_hal_get_ns_entry_point(void);
 
 
-#if TFM_LVL != 1
+#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
 /**
  * \brief Configure the sandbox for a partition.
  *
diff --git a/secure_fw/CMakeLists.txt b/secure_fw/CMakeLists.txt
index d3a3214..75a0a5e 100644
--- a/secure_fw/CMakeLists.txt
+++ b/secure_fw/CMakeLists.txt
@@ -165,12 +165,10 @@
 			#partition is present.
 			#FIXME Remove the explicit load and the above comment once the secure client
 			#test partition uses the generated veneers.
-			if(${COMPILER} STREQUAL "ARMCLANG")
+			if((${COMPILER} STREQUAL "ARMCLANG") AND (NOT TFM_PSA_API))
 				target_link_libraries(${EXE_NAME} tfm_attest tfm_secure_tests tfm_attest tfm_crypto tfm_storage tfm_audit tfm_platform $<TARGET_LINKER_FILE:tfm_secure_tests>\(*veneers.o\) tfm_attest)
-			elseif(${COMPILER} STREQUAL "GNUARM")
-				target_link_libraries(${EXE_NAME} tfm_attest tfm_secure_tests tfm_attest tfm_crypto tfm_storage tfm_audit tfm_platform tfm_attest)
 			else()
-				message(FATAL_ERROR "unknown compiler" )
+				target_link_libraries(${EXE_NAME} tfm_attest tfm_secure_tests tfm_attest tfm_crypto tfm_storage tfm_audit tfm_platform tfm_attest)
 			endif()
 		else()
 			target_link_libraries(${EXE_NAME} tfm_attest tfm_crypto tfm_storage tfm_audit tfm_platform tfm_secure_tests tfm_attest)
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index 0b290d5..c9bfbb7 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -34,6 +34,7 @@
 		"${SS_CORE_DIR}/tfm_core.c"
 		"${SS_CORE_DIR}/tfm_handler.c"
 		"${SS_CORE_DIR}/tfm_secure_api.c"
+		"${SS_CORE_DIR}/tfm_func_api.c"
 		"${SS_CORE_DIR}/tfm_spm_services.c"
 		"${SS_CORE_DIR}/tfm_nspm.c"
 		"${SS_CORE_DIR}/tfm_boot_data.c"
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index 1c53071..fc060f3 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -48,6 +48,7 @@
 #error Only TFM_LVL 1, 2 and 3 are supported!
 #endif
 
+#ifndef TFM_PSA_API
 /* Macros to pick linker symbols and allow to form the partition data base */
 #define REGION(a, b, c) a##b##c
 #define REGION_NAME(a, b, c) REGION(a, b, c)
@@ -55,6 +56,7 @@
 
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif
 
 void configure_ns_code(void)
 {
@@ -108,11 +110,20 @@
     /* Enable secure peripherals interrupts */
     nvic_interrupt_enable();
 
+#ifdef TFM_PSA_API
+    /* FixMe: In case of IPC messaging, scratch area must not be referenced
+     * These variables should be removed when all obsolete references are
+     * removed from the codebase
+     */
+    tfm_scratch_area = NULL;
+    tfm_scratch_area_size = 0;
+#else
     tfm_scratch_area =
         (uint8_t *)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
     tfm_scratch_area_size =
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit) -
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+#endif
     return 0;
 }
 
diff --git a/secure_fw/core/tfm_func_api.c b/secure_fw/core/tfm_func_api.c
new file mode 100644
index 0000000..aeaf5f2
--- /dev/null
+++ b/secure_fw/core/tfm_func_api.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <arm_cmse.h>
+#include "tfm_secure_api.h"
+#include "tfm_nspm.h"
+#include "secure_utilities.h"
+#include "uart_stdout.h"
+#include "secure_fw/spm/spm_api.h"
+#include "region_defs.h"
+#include "tfm_api.h"
+
+#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
+
+#ifndef TFM_LVL
+#error TFM_LVL is not defined!
+#endif
+
+/* Macros to pick linker symbols and allow references to sections */
+#define REGION(a, b, c) a##b##c
+#define REGION_NAME(a, b, c) REGION(a, b, c)
+#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
+
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+
+#if TFM_LVL == 1
+REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+#endif
+
+/* This is the "Big Lock" on the secure side, to guarantee single entry
+ * to SPE
+ */
+extern int32_t tfm_secure_lock;
+static int32_t tfm_secure_api_initializing = 1;
+
+static int32_t is_iovec_api_call(void)
+{
+    uint32_t current_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const struct spm_partition_runtime_data_t *curr_part_data =
+            tfm_spm_partition_get_runtime_data(current_partition_idx);
+    return curr_part_data->iovec_api;
+}
+
+static uint32_t *prepare_partition_ctx(
+            const struct tfm_exc_stack_t *svc_ctx,
+            const struct tfm_sfn_req_s *desc_ptr,
+            uint32_t *dst)
+{
+    /* XPSR  = as was when called, but make sure it's thread mode */
+    *(--dst) = svc_ctx->XPSR & 0xFFFFFE00U;
+    /* ReturnAddress = resume veneer in new context */
+    *(--dst) = svc_ctx->RetAddr;
+    /* LR = sfn address */
+    *(--dst) = (uint32_t)desc_ptr->sfn;
+    /* R12 = don't care */
+    *(--dst) = 0;
+
+    /* R0-R3 = sfn arguments */
+    int32_t i = 4;
+
+    while (i > 0) {
+        i--;
+        *(--dst) = (uint32_t)desc_ptr->args[i];
+    }
+    return dst;
+}
+
+static uint32_t *prepare_partition_iovec_ctx(
+                             const struct tfm_exc_stack_t *svc_ctx,
+                             const struct tfm_sfn_req_s *desc_ptr,
+                             const struct iovec_args_t *iovec_args,
+                             uint32_t *dst)
+{
+    /* XPSR  = as was when called, but make sure it's thread mode */
+    *(--dst) = svc_ctx->XPSR & 0xFFFFFE00U;
+    /* ReturnAddress = resume veneer in new context */
+    *(--dst) = svc_ctx->RetAddr;
+    /* LR = sfn address */
+    *(--dst) = (uint32_t)desc_ptr->sfn;
+    /* R12 = don't care */
+    *(--dst) = 0U;
+
+    /* R0-R3 = sfn arguments */
+    *(--dst) = iovec_args->out_len;
+    *(--dst) = (uint32_t)iovec_args->out_vec;
+    *(--dst) = iovec_args->in_len;
+    *(--dst) = (uint32_t)iovec_args->in_vec;
+
+    return dst;
+}
+
+static void restore_caller_ctx(
+            const struct tfm_exc_stack_t *svc_ctx,
+            struct tfm_exc_stack_t *target_ctx)
+{
+    /* ReturnAddress = resume veneer after second SVC */
+    target_ctx->RetAddr = svc_ctx->RetAddr;
+
+    /* R0 = function return value */
+    target_ctx->R0 = svc_ctx->R0;
+
+    return;
+}
+
+/** \brief Check whether the iovec parameters are valid, and the memory ranges
+ *         are in the posession of the calling partition
+ *
+ * \param[in] desc_ptr  The secure function request descriptor
+ *
+ * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
+ *         otherwise as in /ref tfm_status_e
+ */
+static int32_t tfm_core_check_sfn_parameters(
+                                           const struct tfm_sfn_req_s *desc_ptr)
+{
+    struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
+    size_t in_len;
+    struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
+    size_t out_len;
+
+    uint32_t i;
+
+    if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
+        return TFM_ERROR_INVALID_PARAMETER;
+    }
+
+    in_len = (size_t)(desc_ptr->args[1]);
+    out_len = (size_t)(desc_ptr->args[3]);
+
+    /* The number of vectors are within range. Extra checks to avoid overflow */
+    if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
+        (in_len + out_len > PSA_MAX_IOVEC)) {
+        return TFM_ERROR_INVALID_PARAMETER;
+    }
+
+    /* Check whether the caller partition has at write access to the iovec
+     * structures themselves. Use the TT instruction for this.
+     */
+    if (in_len > 0) {
+        if ((in_vec == NULL) ||
+            (tfm_core_has_write_access_to_region(in_vec,
+                            sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+            return TFM_ERROR_INVALID_PARAMETER;
+        }
+    } else {
+        if (in_vec != NULL) {
+            return TFM_ERROR_INVALID_PARAMETER;
+        }
+    }
+    if (out_len > 0) {
+        if ((out_vec == NULL) ||
+            (tfm_core_has_write_access_to_region(out_vec,
+                            sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+            return TFM_ERROR_INVALID_PARAMETER;
+        }
+    } else {
+        if (out_vec != NULL) {
+            return TFM_ERROR_INVALID_PARAMETER;
+        }
+    }
+
+    /* Check whether the caller partition has access to the data inside the
+     * iovecs
+     */
+    for (i = 0; i < in_len; ++i) {
+        if (in_vec[i].len > 0) {
+            if ((in_vec[i].base == NULL) ||
+                (tfm_core_has_read_access_to_region(in_vec[i].base,
+                            in_vec[i].len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+                return TFM_ERROR_INVALID_PARAMETER;
+            }
+        }
+    }
+    for (i = 0; i < out_len; ++i) {
+        if (out_vec[i].len > 0) {
+            if ((out_vec[i].base == NULL) ||
+                (tfm_core_has_write_access_to_region(out_vec[i].base,
+                            out_vec[i].len, desc_ptr->ns_caller,
+                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
+                return TFM_ERROR_INVALID_PARAMETER;
+            }
+        }
+    }
+
+    return TFM_SUCCESS;
+}
+
+static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
+                               const struct iovec_args_t *source)
+{
+    size_t i;
+
+    target->in_len = source->in_len;
+    for (i = 0; i < source->in_len; ++i) {
+        target->in_vec[i].base = source->in_vec[i].base;
+        target->in_vec[i].len = source->in_vec[i].len;
+    }
+    target->out_len = source->out_len;
+    for (i = 0; i < source->out_len; ++i) {
+        target->out_vec[i].base = source->out_vec[i].base;
+        target->out_vec[i].len = source->out_vec[i].len;
+    }
+}
+
+static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
+{
+    int i;
+
+    args->in_len = 0;
+    for (i = 0; i < PSA_MAX_IOVEC; ++i) {
+        args->in_vec[i].base = NULL;
+        args->in_vec[i].len = 0;
+    }
+    args->out_len = 0;
+    for (i = 0; i < PSA_MAX_IOVEC; ++i) {
+        args->out_vec[i].base = NULL;
+        args->out_vec[i].len = 0;
+    }
+}
+
+static int32_t tfm_start_partition(const struct tfm_sfn_req_s *desc_ptr,
+                                                             uint32_t excReturn)
+{
+    uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
+    const struct spm_partition_runtime_data_t *curr_part_data;
+    uint32_t caller_flags;
+    register uint32_t partition_idx;
+    uint32_t psp;
+    uint32_t partition_psp, partition_psplim;
+    uint32_t partition_state;
+    uint32_t partition_flags;
+    struct tfm_exc_stack_t *svc_ctx;
+    uint32_t caller_partition_id;
+    int32_t client_id;
+    struct iovec_args_t *iovec_args;
+
+    psp = __get_PSP();
+    svc_ctx = (struct tfm_exc_stack_t *)psp;
+    caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
+
+    /* Check partition state consistency */
+    if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
+        != (!desc_ptr->ns_caller)) {
+        /* Partition state inconsistency detected */
+        return TFM_SECURE_LOCK_FAILED;
+    }
+
+    if ((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) {
+        /* Disable NS exception handling while secure service is running.
+         * FixMe:
+         * This restriction is applied to limit the number of possible attack
+         * vectors.
+         * To be removed when pre-emption and context management issues have
+         * been analysed and resolved.
+         */
+        TFM_NS_EXC_DISABLE();
+    }
+
+    partition_idx = get_partition_idx(desc_ptr->sp_id);
+
+    curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
+    partition_state = curr_part_data->partition_state;
+    partition_flags = tfm_spm_partition_get_flags(partition_idx);
+    caller_partition_id = tfm_spm_partition_get_partition_id(
+                                                          caller_partition_idx);
+
+    if (tfm_secure_api_initializing) {
+#if TFM_LVL != 1
+        /* Make thread mode unprivileged while untrusted partition init is
+         * executed
+         */
+        if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
+            tfm_spm_partition_change_privilege(
+                                        TFM_PARTITION_UNPRIVILEGED_MODE);
+        }
+#endif
+    } else if (partition_state == SPM_PARTITION_STATE_RUNNING ||
+        partition_state == SPM_PARTITION_STATE_SUSPENDED ||
+        partition_state == SPM_PARTITION_STATE_BLOCKED) {
+        /* Recursion is not permitted! */
+        return TFM_ERROR_PARTITION_NON_REENTRANT;
+    } else if (partition_state != SPM_PARTITION_STATE_IDLE) {
+        /* The partition to be called is not in a proper state */
+        return TFM_SECURE_LOCK_FAILED;
+    }
+
+#if TFM_LVL == 1
+    /* Prepare switch to shared secure partition stack */
+    /* In case the call is coming from the non-secure world, we save the iovecs
+     * on the stop of the stack. So the memory area, that can actually be used
+     * as stack by the partitions starts at a lower address
+     */
+    partition_psp =
+        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
+        sizeof(struct iovec_args_t);
+    partition_psplim =
+        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+#else
+    partition_psp = curr_part_data->stack_ptr;
+    partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
+#endif
+    /* Store the context for the partition call */
+    tfm_spm_partition_set_caller_partition_idx(partition_idx,
+                                               caller_partition_idx);
+    tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
+
+    if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
+        tfm_spm_partition_set_caller_client_id(partition_idx,
+                                               caller_partition_id);
+    } else {
+        client_id = tfm_nspm_get_current_client_id();
+        if (client_id >= 0) {
+            return TFM_SECURE_LOCK_FAILED;
+        }
+        tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
+    }
+
+#if (TFM_LVL != 1) && (TFM_LVL != 2)
+    /* Dynamic partitioning is only done is TFM level 3 */
+    tfm_spm_partition_sandbox_deconfig(caller_partition_idx);
+
+    /* Configure partition execution environment */
+    if (tfm_spm_partition_sandbox_config(partition_idx) != SPM_ERR_OK) {
+        ERROR_MSG("Failed to configure sandbox for partition!");
+        tfm_secure_api_error_handler();
+    }
+#endif
+
+    /* Default share to scratch area in case of partition to partition calls
+     * this way partitions always get default access to input buffers
+     */
+    /* FixMe: return value/error handling TBD */
+    tfm_spm_partition_set_share(partition_idx, desc_ptr->ns_caller ?
+        TFM_BUFFER_SHARE_NS_CODE : TFM_BUFFER_SHARE_SCRATCH);
+
+#if TFM_LVL == 1
+    /* In level one, only switch context and return from exception if in
+     * handler mode
+     */
+    if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
+        if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
+            /* Save the iovecs on the common stack. The vectors had been sanity
+             * checked already, and since then the interrupts have been kept
+             * disabled. So we can be sure that the vectors haven't been
+             * tampered with since the check.
+             */
+            iovec_args = (struct iovec_args_t *)
+                ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
+                     sizeof(struct iovec_args_t));
+            if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
+                SPM_ERR_OK) {
+                return TFM_ERROR_GENERIC;
+            }
+            tfm_copy_iovec_parameters(iovec_args,
+                                      &(curr_part_data->iovec_args));
+
+            /* Prepare the partition context, update stack ptr */
+            psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
+                                                        iovec_args,
+                                                     (uint32_t *)partition_psp);
+        } else {
+            /* Prepare the partition context, update stack ptr */
+            psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
+                                                  (uint32_t *)partition_psp);
+        }
+        __set_PSP(psp);
+        __set_PSPLIM(partition_psplim);
+    }
+#else
+    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
+        /* Save the iovecs on the stack of the partition. The vectors had been
+         * sanity checked already, and since then the interrupts have been kept
+         * disabled. So we can be sure that the vectors haven't been tampered
+         * with since the check.
+         */
+        iovec_args =
+        (struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) -
+        sizeof(struct iovec_args_t));
+        if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
+            SPM_ERR_OK) {
+            return TFM_ERROR_GENERIC;
+        }
+        tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
+
+        /* Prepare the partition context, update stack ptr */
+        psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
+                                                    iovec_args,
+                                                    (uint32_t *)partition_psp);
+    } else {
+        /* Prepare the partition context, update stack ptr */
+        psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
+                                              (uint32_t *)partition_psp);
+    }
+    __set_PSP(psp);
+    __set_PSPLIM(partition_psplim);
+#endif
+
+    tfm_spm_partition_set_state(caller_partition_idx,
+                                SPM_PARTITION_STATE_BLOCKED);
+    tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
+    tfm_secure_lock++;
+
+    return TFM_SUCCESS;
+}
+
+static int32_t tfm_return_from_partition(uint32_t *excReturn)
+{
+    uint32_t current_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
+    uint32_t current_partition_flags;
+    uint32_t return_partition_idx;
+    uint32_t return_partition_flags;
+    uint32_t psp = __get_PSP();
+    size_t i;
+    struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
+    struct iovec_args_t *iovec_args;
+
+    if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
+        return TFM_SECURE_UNLOCK_FAILED;
+    }
+
+    curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
+    return_partition_idx = curr_part_data->caller_partition_idx;
+
+    if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
+        return TFM_SECURE_UNLOCK_FAILED;
+    }
+
+    ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
+
+    return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
+    current_partition_flags = tfm_spm_partition_get_flags(
+            current_partition_idx);
+
+    tfm_secure_lock--;
+
+    if ((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) {
+        /* Re-enable NS exceptions when secure service returns to NS client.
+         * FixMe:
+         * To be removed when pre-emption and context management issues have
+         * been analysed and resolved.
+         */
+        TFM_NS_EXC_ENABLE();
+    }
+
+#if (TFM_LVL != 1) && (TFM_LVL != 2)
+    /* Deconfigure completed partition environment */
+    tfm_spm_partition_sandbox_deconfig(current_partition_idx);
+    if (tfm_secure_api_initializing) {
+        /* Restore privilege for thread mode during TF-M init. This is only
+         * have to be done if the partition is not trusted.
+         */
+        if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
+            tfm_spm_partition_change_privilege(TFM_PARTITION_PRIVILEGED_MODE);
+        }
+    } else {
+        /* Configure the caller partition environment in case this was a
+         * partition to partition call and returning to untrusted partition
+         */
+        if (tfm_spm_partition_sandbox_config(return_partition_idx)
+            != SPM_ERR_OK) {
+            ERROR_MSG("Failed to configure sandbox for partition!");
+            tfm_secure_api_error_handler();
+        }
+        if (return_partition_flags & SPM_PART_FLAG_APP_ROT) {
+            /* Restore share status */
+            tfm_spm_partition_set_share(
+                return_partition_idx,
+                tfm_spm_partition_get_runtime_data(
+                    return_partition_idx)->share);
+        }
+    }
+#endif
+
+#if TFM_LVL == 1
+    if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
+        (tfm_secure_api_initializing)) {
+        /* In TFM level 1 context restore is only done when
+         * returning to NS or after initialization
+         */
+        /* Restore caller context */
+        restore_caller_ctx(svc_ctx,
+            (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
+        *excReturn = ret_part_data->lr;
+        __set_PSP(ret_part_data->stack_ptr);
+        extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
+        uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
+       __set_PSPLIM(psp_stack_bottom);
+
+        /* FIXME: The condition should be removed once all the secure service
+         *        calls are done via the iovec veneers
+         */
+        if (curr_part_data->iovec_api) {
+            iovec_args = (struct iovec_args_t *)
+               ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit) -
+               sizeof(struct iovec_args_t));
+
+            for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
+                curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
+            }
+            tfm_clear_iovec_parameters(iovec_args);
+        }
+    }
+#else
+    /* Restore caller context */
+    restore_caller_ctx(svc_ctx,
+        (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
+    *excReturn = ret_part_data->lr;
+    __set_PSP(ret_part_data->stack_ptr);
+    __set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
+    /* Clear the context entry before returning */
+    tfm_spm_partition_set_stack(
+                current_partition_idx, psp + sizeof(struct tfm_exc_stack_t));
+
+    /* FIXME: The condition should be removed once all the secure service
+     *        calls are done via the iovec veneers */
+    if (curr_part_data->iovec_api) {
+        iovec_args = (struct iovec_args_t *)
+                     (tfm_spm_partition_get_stack_top(current_partition_idx) -
+                     sizeof(struct iovec_args_t));
+
+        for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
+            curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
+        }
+        tfm_clear_iovec_parameters(iovec_args);
+    }
+#endif
+
+    tfm_spm_partition_cleanup_context(current_partition_idx);
+
+    tfm_spm_partition_set_state(current_partition_idx,
+                                SPM_PARTITION_STATE_IDLE);
+    tfm_spm_partition_set_state(return_partition_idx,
+                                SPM_PARTITION_STATE_RUNNING);
+
+    return TFM_SUCCESS;
+}
+
+static int32_t tfm_check_sfn_req_integrity(const struct tfm_sfn_req_s *desc_ptr)
+{
+    if ((desc_ptr == NULL) ||
+        (desc_ptr->sp_id == 0) ||
+        (desc_ptr->sfn == NULL)) {
+        /* invalid parameter */
+        return TFM_ERROR_INVALID_PARAMETER;
+    }
+    return TFM_SUCCESS;
+}
+
+static int32_t tfm_core_check_sfn_req_rules(
+        const struct tfm_sfn_req_s *desc_ptr)
+{
+    /* Check partition idx validity */
+    if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
+        return TFM_ERROR_NO_ACTIVE_PARTITION;
+    }
+
+    if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
+        /* Secure domain is already locked!
+         * This should only happen if caller is secure partition!
+         * FixMe: This scenario is a potential security breach
+         * Take appropriate action!
+         */
+        return TFM_ERROR_SECURE_DOMAIN_LOCKED;
+    }
+
+    if (tfm_secure_api_initializing) {
+        int32_t id =
+            tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
+
+        if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
+            /* Invalid request during system initialization */
+            ERROR_MSG("Invalid service request during initialization!");
+            return TFM_ERROR_NOT_INITIALIZED;
+        }
+    }
+
+    return TFM_SUCCESS;
+}
+
+void tfm_secure_api_init_done(void)
+{
+    tfm_secure_api_initializing = 0;
+#if TFM_LVL != 1
+    if (tfm_spm_partition_sandbox_config(TFM_SP_NON_SECURE_ID) != SPM_ERR_OK) {
+        ERROR_MSG("Failed to configure sandbox for partition!");
+        tfm_secure_api_error_handler();
+    }
+#endif
+}
+
+int32_t tfm_core_sfn_request_handler(
+                             struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
+{
+    int32_t res;
+
+    res = tfm_check_sfn_req_integrity(desc_ptr);
+    if (res != TFM_SUCCESS) {
+        ERROR_MSG("Invalid service request!");
+        tfm_secure_api_error_handler();
+    }
+
+    __disable_irq();
+
+    desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
+
+    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
+        res = tfm_core_check_sfn_parameters(desc_ptr);
+        if (res != TFM_SUCCESS) {
+            /* The sanity check of iovecs failed. */
+            __enable_irq();
+            tfm_secure_api_error_handler();
+        }
+    }
+
+    res = tfm_core_check_sfn_req_rules(desc_ptr);
+    if (res != TFM_SUCCESS) {
+        /* FixMe: error compartmentalization TBD */
+        tfm_spm_partition_set_state(
+            desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
+        __enable_irq();
+        ERROR_MSG("Unauthorized service request!");
+        tfm_secure_api_error_handler();
+    }
+
+    res = tfm_start_partition(desc_ptr, excReturn);
+    if (res != TFM_SUCCESS) {
+        /* FixMe: consider possible fault scenarios */
+        __enable_irq();
+        ERROR_MSG("Failed to process service request!");
+        tfm_secure_api_error_handler();
+    }
+
+    __enable_irq();
+
+    return res;
+}
+
+#if TFM_LVL == 1
+int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
+{
+    int32_t res;
+    int32_t *args;
+    int32_t retVal;
+
+    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
+        res = tfm_core_check_sfn_parameters(desc_ptr);
+        if (res != TFM_SUCCESS) {
+            /* The sanity check of iovecs failed. */
+            return res;
+        }
+    }
+
+    /* No excReturn value is needed as no exception handling is used */
+    res = tfm_core_sfn_request_handler(desc_ptr, 0);
+
+    if (res != TFM_SUCCESS) {
+        tfm_secure_api_error_handler();
+    }
+
+    /* Secure partition to secure partition call in TFM level 1 */
+    args = desc_ptr->args;
+    retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
+
+    /* return handler should restore original exc_return value... */
+    res = tfm_return_from_partition(NULL);
+    if (res == TFM_SUCCESS) {
+        /* If unlock successful, pass SS return value to caller */
+        res = retVal;
+    } else {
+        /* Unlock errors indicate ctx database corruption or unknown
+         * anomalies. Halt execution
+         */
+        ERROR_MSG("Secure API error during unlock!");
+        tfm_secure_api_error_handler();
+    }
+    return res;
+}
+#endif
+
+void tfm_core_validate_secure_caller_handler(uint32_t *svc_args)
+{
+
+    int32_t res = TFM_ERROR_GENERIC;
+    uint32_t running_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const struct spm_partition_runtime_data_t *curr_part_data =
+            tfm_spm_partition_get_runtime_data(running_partition_idx);
+    uint32_t running_partition_flags =
+            tfm_spm_partition_get_flags(running_partition_idx);
+    uint32_t caller_partition_flags =
+            tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
+
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
+        /* This handler shouldn't be called from outside partition context.
+         * Partitions are only allowed to run while S domain is locked.
+         */
+        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    /* Store return value in r0 */
+    if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
+        res = TFM_SUCCESS;
+    }
+    svc_args[0] = res;
+}
+
+int32_t tfm_core_check_buffer_access(uint32_t  partition_idx,
+                                     void     *start_addr,
+                                     size_t    len,
+                                     uint32_t  alignment)
+{
+    uintptr_t start_addr_value = (uintptr_t)start_addr;
+    uintptr_t end_addr_value = (uintptr_t)start_addr + len;
+    uintptr_t alignment_mask;
+
+    alignment_mask = (((uintptr_t)1) << alignment) - 1;
+
+    /* Check that the pointer is aligned properly */
+    if (start_addr_value & alignment_mask) {
+        /* not aligned, return error */
+        return 0;
+    }
+
+    /* Protect against overflow (and zero len) */
+    if (end_addr_value <= start_addr_value) {
+        return 0;
+    }
+
+#if TFM_LVL == 1
+    /* For privileged partition execution, all secure data memory and stack
+     * is accessible
+     */
+    if (start_addr_value >= S_DATA_START &&
+        end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
+        return 1;
+    }
+#else
+    /* For non-privileged execution the partition's data and stack is
+     * accessible
+     */
+    if (start_addr_value >=
+            tfm_spm_partition_get_stack_bottom(partition_idx) &&
+        end_addr_value <=
+            tfm_spm_partition_get_stack_top(partition_idx)) {
+        return 1;
+    }
+    if (start_addr_value >=
+           tfm_spm_partition_get_rw_start(partition_idx) &&
+        end_addr_value <=
+           tfm_spm_partition_get_rw_limit(partition_idx)) {
+        return 1;
+    }
+    if (start_addr_value >=
+           tfm_spm_partition_get_zi_start(partition_idx) &&
+        end_addr_value <=
+           tfm_spm_partition_get_zi_limit(partition_idx)) {
+        return 1;
+    }
+#endif
+    return 0;
+}
+
+void tfm_core_get_caller_client_id_handler(uint32_t *svc_args)
+{
+    uintptr_t result_ptr_value = svc_args[0];
+    uint32_t running_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const uint32_t running_partition_flags =
+            tfm_spm_partition_get_flags(running_partition_idx);
+    const struct spm_partition_runtime_data_t *curr_part_data =
+            tfm_spm_partition_get_runtime_data(running_partition_idx);
+    int res = 0;
+
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
+        /* This handler shouldn't be called from outside partition context.
+         * Partitions are only allowed to run while S domain is locked.
+         */
+        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    /* Make sure that the output pointer points to a memory area that is owned
+     * by the partition
+     */
+    res = tfm_core_check_buffer_access(running_partition_idx,
+                                       (void *)result_ptr_value,
+                                       sizeof(curr_part_data->caller_client_id),
+                                       2);
+    if (!res) {
+        /* Not in accessible range, return error */
+        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
+
+    /* Store return value in r0 */
+    svc_args[0] = TFM_SUCCESS;
+}
+
+void tfm_core_memory_permission_check_handler(uint32_t *svc_args)
+{
+    uint32_t ptr = svc_args[0];
+    uint32_t size = svc_args[1];
+    int32_t access = svc_args[2];
+
+    uint32_t max_buf_size, ptr_start, range_limit, range_check = false;
+    int32_t res;
+    uint32_t running_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const struct spm_partition_runtime_data_t *curr_part_data =
+            tfm_spm_partition_get_runtime_data(running_partition_idx);
+    uint32_t running_partition_flags =
+            tfm_spm_partition_get_flags(running_partition_idx);
+    int32_t flags = 0;
+    void *rangeptr;
+
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) || (size == 0)) {
+        /* This handler should only be called from a secure partition. */
+        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    if (curr_part_data->share != TFM_BUFFER_SHARE_PRIV) {
+        flags |= CMSE_MPU_UNPRIV;
+    }
+
+    if (access == TFM_MEMORY_ACCESS_RW) {
+        flags |= CMSE_MPU_READWRITE;
+    } else {
+        flags |= CMSE_MPU_READ;
+    }
+
+    /* Check if partition access to address would fail */
+    rangeptr = cmse_check_address_range((void *)ptr, size, flags);
+
+    /* Get regions associated with address */
+    cmse_address_info_t addr_info = cmse_TT((void *)ptr);
+
+    if (rangeptr == NULL) {
+        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    if (addr_info.flags.secure) {
+#if TFM_LVL == 1
+        /* For privileged partition execution, all secure data memory is
+         * accessible
+         */
+        max_buf_size = S_DATA_SIZE;
+        ptr_start = S_DATA_START;
+        range_limit = S_DATA_LIMIT;
+#else
+        /* Only scratch is permitted in secure memory */
+        max_buf_size = (uint32_t)tfm_scratch_area_size;
+        ptr_start = (uint32_t)tfm_scratch_area;
+        range_limit = (uint32_t)tfm_scratch_area + tfm_scratch_area_size - 1;
+#endif
+        range_check = true;
+    } else {
+        if (!addr_info.flags.sau_region_valid) {
+            /* If address is NS, TF-M expects SAU to be configured
+             */
+            svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
+            return;
+        }
+        switch (addr_info.flags.sau_region) {
+        case TFM_NS_REGION_CODE:
+            if (access == TFM_MEMORY_ACCESS_RW) {
+                res = TFM_ERROR_INVALID_PARAMETER;
+            } else {
+                /* Currently TF-M does not support checks for NS Memory
+                 * accesses by partitions
+                 */
+                res = TFM_SUCCESS;
+            }
+            break;
+        case TFM_NS_REGION_DATA:
+            /* Currently TF-M does not support checks for NS Memory
+             * accesses by partitions
+             */
+            res = TFM_SUCCESS;
+            break;
+        default:
+            /* Only NS data and code regions can be accessed as buffers */
+            res = TFM_ERROR_INVALID_PARAMETER;
+            break;
+        }
+    }
+
+    if (range_check == true) {
+        if ((size <= max_buf_size) && (ptr >= ptr_start)
+            && (ptr <= range_limit + 1 - size)) {
+            res = TFM_SUCCESS;
+        } else {
+            res = TFM_ERROR_INVALID_PARAMETER;
+        }
+    }
+
+    /* Store return value in r0 */
+    svc_args[0] = res;
+}
+
+/* This SVC handler is called if veneer is running in thread mode */
+uint32_t tfm_core_partition_request_svc_handler(
+        const struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
+{
+    struct tfm_sfn_req_s *desc_ptr;
+
+    if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
+        /* Service request SVC called with MSP active.
+         * Either invalid configuration for Thread mode or SVC called
+         * from Handler mode, which is not supported.
+         * FixMe: error severity TBD
+         */
+        ERROR_MSG("Service request SVC called with MSP active!");
+        tfm_secure_api_error_handler();
+    }
+
+    desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
+
+    if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
+        tfm_secure_api_error_handler();
+    }
+
+    return EXC_RETURN_SECURE_FUNCTION;
+}
+
+/* This SVC handler is called when sfn returns */
+uint32_t tfm_core_partition_return_handler(uint32_t lr)
+{
+    int32_t res;
+
+    if (!(lr & EXC_RETURN_STACK_PROCESS)) {
+        /* Partition return SVC called with MSP active.
+         * This should not happen!
+         */
+        ERROR_MSG("Partition return SVC called with MSP active!");
+        tfm_secure_api_error_handler();
+    }
+
+    /* Store return value from secure partition */
+    int32_t retVal = *(int32_t *)__get_PSP();
+
+    if (!is_iovec_api_call()) {
+        if ((retVal > TFM_SUCCESS) &&
+            (retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
+            /* Secure function returned a reserved value */
+#ifdef TFM_CORE_DEBUG
+            LOG_MSG("Invalid return value from secure partition!");
+#endif
+            /* FixMe: error can be traced to specific secure partition
+             * and Core is not compromised. Error handling flow can be
+             * refined
+             */
+            tfm_secure_api_error_handler();
+        }
+    }
+
+    res = tfm_return_from_partition(&lr);
+    if (res != TFM_SUCCESS) {
+        /* Unlock errors indicate ctx database corruption or unknown anomalies
+         * Halt execution
+         */
+        ERROR_MSG("Secure API error during unlock!");
+        tfm_secure_api_error_handler();
+    }
+
+    return lr;
+}
+
+void tfm_core_set_buffer_area_handler(uint32_t *args)
+{
+    /* r0 is stored in args[0] in exception stack frame
+     * Store input parameter before writing return value to that address
+     */
+    enum tfm_buffer_share_region_e share;
+    uint32_t running_partition_idx =
+            tfm_spm_partition_get_running_partition_idx();
+    const struct spm_partition_runtime_data_t *curr_part_data =
+            tfm_spm_partition_get_runtime_data(running_partition_idx);
+    uint32_t caller_partition_idx = curr_part_data->caller_partition_idx;
+    uint32_t running_partition_flags =
+            tfm_spm_partition_get_flags(running_partition_idx);
+    uint32_t caller_partition_flags =
+            tfm_spm_partition_get_flags(caller_partition_idx);
+
+     /* tfm_core_set_buffer_area() returns int32_t */
+    int32_t *res_ptr = (int32_t *)&args[0];
+
+    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
+        /* This handler should only be called from a secure partition. */
+        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    switch (args[0]) {
+    case TFM_BUFFER_SHARE_DEFAULT:
+        share = (!(caller_partition_flags & SPM_PART_FLAG_APP_ROT)) ?
+            (TFM_BUFFER_SHARE_NS_CODE) : (TFM_BUFFER_SHARE_SCRATCH);
+        break;
+    case TFM_BUFFER_SHARE_SCRATCH:
+    case TFM_BUFFER_SHARE_NS_CODE:
+        share = args[0];
+        break;
+    default:
+        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
+        return;
+    }
+
+    if (tfm_spm_partition_set_share(running_partition_idx, share) ==
+            SPM_ERR_OK) {
+        *res_ptr = TFM_SUCCESS;
+    } else {
+        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
+    }
+
+    return;
+}
+
diff --git a/secure_fw/core/tfm_handler.c b/secure_fw/core/tfm_handler.c
index d600ddc..10a91a56 100644
--- a/secure_fw/core/tfm_handler.c
+++ b/secure_fw/core/tfm_handler.c
@@ -156,6 +156,30 @@
         return lr;
     }
     switch (svc_number) {
+#ifdef TFM_PSA_API
+    case TFM_SVC_IPC_REQUEST:
+        tfm_psa_ipc_request_handler(svc_args);
+        break;
+    case TFM_SVC_SCHEDULE:
+    case TFM_SVC_EXIT_THRD:
+    case TFM_SVC_PSA_FRAMEWORK_VERSION:
+    case TFM_SVC_PSA_VERSION:
+    case TFM_SVC_PSA_CONNECT:
+    case TFM_SVC_PSA_CALL:
+    case TFM_SVC_PSA_CLOSE:
+    case TFM_SVC_PSA_WAIT:
+    case TFM_SVC_PSA_GET:
+    case TFM_SVC_PSA_SET_RHANDLE:
+    case TFM_SVC_PSA_READ:
+    case TFM_SVC_PSA_SKIP:
+    case TFM_SVC_PSA_WRITE:
+    case TFM_SVC_PSA_REPLY:
+    case TFM_SVC_PSA_NOTIFY:
+    case TFM_SVC_PSA_CLEAR:
+    case TFM_SVC_PSA_EOI:
+        svc_args[0] = SVC_Handler_IPC(svc_number, svc_args, lr);
+        break;
+#else
     case TFM_SVC_SFN_REQUEST:
         lr = tfm_core_partition_request_svc_handler(svc_args, lr);
         break;
@@ -177,10 +201,6 @@
     case TFM_SVC_SET_SHARE_AREA:
         tfm_core_set_buffer_area_handler(svc_args);
         break;
-#ifdef TFM_PSA_API
-    case TFM_SVC_IPC_REQUEST:
-        tfm_psa_ipc_request_handler(svc_args);
-        break;
 #endif
     case TFM_SVC_PRINT:
         printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
@@ -188,27 +208,6 @@
     case TFM_SVC_GET_BOOT_DATA:
         tfm_core_get_boot_data_handler(svc_args);
         break;
-#ifdef TFM_PSA_API
-    case TFM_SVC_SCHEDULE:
-    case TFM_SVC_EXIT_THRD:
-    case TFM_SVC_PSA_FRAMEWORK_VERSION:
-    case TFM_SVC_PSA_VERSION:
-    case TFM_SVC_PSA_CONNECT:
-    case TFM_SVC_PSA_CALL:
-    case TFM_SVC_PSA_CLOSE:
-    case TFM_SVC_PSA_WAIT:
-    case TFM_SVC_PSA_GET:
-    case TFM_SVC_PSA_SET_RHANDLE:
-    case TFM_SVC_PSA_READ:
-    case TFM_SVC_PSA_SKIP:
-    case TFM_SVC_PSA_WRITE:
-    case TFM_SVC_PSA_REPLY:
-    case TFM_SVC_PSA_NOTIFY:
-    case TFM_SVC_PSA_CLEAR:
-    case TFM_SVC_PSA_EOI:
-        svc_args[0] = SVC_Handler_IPC(svc_number, svc_args, lr);
-        break;
-#endif
     default:
         LOG_MSG("Unknown SVC number requested!");
         break;
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index cf65c44..ca0e51c 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -28,89 +28,15 @@
 #define REGION_NAME(a, b, c) REGION(a, b, c)
 #define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
 
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
 REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
-
-#if TFM_LVL == 1
-REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
-REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
-#endif
+#endif /* !defined(TFM_PSA_API) */
 
 /* This is the "Big Lock" on the secure side, to guarantee single entry
  * to SPE
  */
 int32_t tfm_secure_lock;
-static int32_t tfm_secure_api_initializing = 1;
-
-static int32_t is_iovec_api_call(void)
-{
-    uint32_t current_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const struct spm_partition_runtime_data_t *curr_part_data =
-            tfm_spm_partition_get_runtime_data(current_partition_idx);
-    return curr_part_data->iovec_api;
-}
-
-static uint32_t *prepare_partition_ctx(
-            const struct tfm_exc_stack_t *svc_ctx,
-            const struct tfm_sfn_req_s *desc_ptr,
-            uint32_t *dst)
-{
-    /* XPSR  = as was when called, but make sure it's thread mode */
-    *(--dst) = svc_ctx->XPSR & 0xFFFFFE00U;
-    /* ReturnAddress = resume veneer in new context */
-    *(--dst) = svc_ctx->RetAddr;
-    /* LR = sfn address */
-    *(--dst) = (uint32_t)desc_ptr->sfn;
-    /* R12 = don't care */
-    *(--dst) = 0;
-
-    /* R0-R3 = sfn arguments */
-    int32_t i = 4;
-
-    while (i > 0) {
-        i--;
-        *(--dst) = (uint32_t)desc_ptr->args[i];
-    }
-    return dst;
-}
-
-static uint32_t *prepare_partition_iovec_ctx(
-                             const struct tfm_exc_stack_t *svc_ctx,
-                             const struct tfm_sfn_req_s *desc_ptr,
-                             const struct iovec_args_t *iovec_args,
-                             uint32_t *dst)
-{
-    /* XPSR  = as was when called, but make sure it's thread mode */
-    *(--dst) = svc_ctx->XPSR & 0xFFFFFE00U;
-    /* ReturnAddress = resume veneer in new context */
-    *(--dst) = svc_ctx->RetAddr;
-    /* LR = sfn address */
-    *(--dst) = (uint32_t)desc_ptr->sfn;
-    /* R12 = don't care */
-    *(--dst) = 0U;
-
-    /* R0-R3 = sfn arguments */
-    *(--dst) = iovec_args->out_len;
-    *(--dst) = (uint32_t)iovec_args->out_vec;
-    *(--dst) = iovec_args->in_len;
-    *(--dst) = (uint32_t)iovec_args->in_vec;
-
-    return dst;
-}
-
-static void restore_caller_ctx(
-            const struct tfm_exc_stack_t *svc_ctx,
-            struct tfm_exc_stack_t *target_ctx)
-{
-    /* ReturnAddress = resume veneer after second SVC */
-    target_ctx->RetAddr = svc_ctx->RetAddr;
-
-    /* R0 = function return value */
-    target_ctx->R0 = svc_ctx->R0;
-
-    return;
-}
 
 /**
  * \brief Check whether a memory range is inside a memory region.
@@ -167,10 +93,12 @@
 {
     int32_t range_access_allowed_by_mpu;
 
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
     uint32_t scratch_base =
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
     uint32_t scratch_limit =
         (uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
+#endif /* !defined(TFM_PSA_API) */
 
     /* Use the TT instruction to check access to the partition's regions*/
     range_access_allowed_by_mpu =
@@ -180,6 +108,7 @@
         return TFM_SUCCESS;
     }
 
+#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
     /* If the check for the current MPU settings fails, check for the share
      * region, only if the partition is secure
      */
@@ -189,6 +118,7 @@
             return TFM_SUCCESS;
         }
     }
+#endif /* !defined(TFM_PSA_API) */
 
     /* If all else fails, check whether the region is in the non-secure
      * memory
@@ -237,442 +167,6 @@
     return has_access_to_region(p, s, flags);
 }
 
-/** \brief Check whether the iovec parameters are valid, and the memory ranges
- *         are in the posession of the calling partition
- *
- * \param[in] desc_ptr  The secure function request descriptor
- *
- * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
- *         otherwise as in /ref tfm_status_e
- */
-static int32_t tfm_core_check_sfn_parameters(
-                                           const struct tfm_sfn_req_s *desc_ptr)
-{
-    struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
-    size_t in_len;
-    struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
-    size_t out_len;
-
-    uint32_t i;
-
-    if ((desc_ptr->args[1] < 0) || (desc_ptr->args[3] < 0)) {
-        return TFM_ERROR_INVALID_PARAMETER;
-    }
-
-    in_len = (size_t)(desc_ptr->args[1]);
-    out_len = (size_t)(desc_ptr->args[3]);
-
-    /* The number of vectors are within range. Extra checks to avoid overflow */
-    if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
-        (in_len + out_len > PSA_MAX_IOVEC)) {
-        return TFM_ERROR_INVALID_PARAMETER;
-    }
-
-    /* Check whether the caller partition has at write access to the iovec
-     * structures themselves. Use the TT instruction for this.
-     */
-    if (in_len > 0) {
-        if ((in_vec == NULL) ||
-            (tfm_core_has_write_access_to_region(in_vec,
-                            sizeof(psa_invec)*in_len, desc_ptr->ns_caller,
-                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
-            return TFM_ERROR_INVALID_PARAMETER;
-        }
-    } else {
-        if (in_vec != NULL) {
-            return TFM_ERROR_INVALID_PARAMETER;
-        }
-    }
-    if (out_len > 0) {
-        if ((out_vec == NULL) ||
-            (tfm_core_has_write_access_to_region(out_vec,
-                            sizeof(psa_outvec)*out_len, desc_ptr->ns_caller,
-                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
-            return TFM_ERROR_INVALID_PARAMETER;
-        }
-    } else {
-        if (out_vec != NULL) {
-            return TFM_ERROR_INVALID_PARAMETER;
-        }
-    }
-
-    /* Check whether the caller partition has access to the data inside the
-     * iovecs
-     */
-    for (i = 0; i < in_len; ++i) {
-        if (in_vec[i].len > 0) {
-            if ((in_vec[i].base == NULL) ||
-                (tfm_core_has_read_access_to_region(in_vec[i].base,
-                            in_vec[i].len, desc_ptr->ns_caller,
-                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
-                return TFM_ERROR_INVALID_PARAMETER;
-            }
-        }
-    }
-    for (i = 0; i < out_len; ++i) {
-        if (out_vec[i].len > 0) {
-            if ((out_vec[i].base == NULL) ||
-                (tfm_core_has_write_access_to_region(out_vec[i].base,
-                            out_vec[i].len, desc_ptr->ns_caller,
-                            TFM_PARTITION_UNPRIVILEGED_MODE) != TFM_SUCCESS)) {
-                return TFM_ERROR_INVALID_PARAMETER;
-            }
-        }
-    }
-
-    return TFM_SUCCESS;
-}
-
-static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
-                               const struct iovec_args_t *source)
-{
-    size_t i;
-
-    target->in_len = source->in_len;
-    for (i = 0; i < source->in_len; ++i) {
-        target->in_vec[i].base = source->in_vec[i].base;
-        target->in_vec[i].len = source->in_vec[i].len;
-    }
-    target->out_len = source->out_len;
-    for (i = 0; i < source->out_len; ++i) {
-        target->out_vec[i].base = source->out_vec[i].base;
-        target->out_vec[i].len = source->out_vec[i].len;
-    }
-}
-
-static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
-{
-    int i;
-
-    args->in_len = 0;
-    for (i = 0; i < PSA_MAX_IOVEC; ++i) {
-        args->in_vec[i].base = NULL;
-        args->in_vec[i].len = 0;
-    }
-    args->out_len = 0;
-    for (i = 0; i < PSA_MAX_IOVEC; ++i) {
-        args->out_vec[i].base = NULL;
-        args->out_vec[i].len = 0;
-    }
-}
-
-static int32_t tfm_start_partition(const struct tfm_sfn_req_s *desc_ptr,
-                                                             uint32_t excReturn)
-{
-    uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
-    const struct spm_partition_runtime_data_t *curr_part_data;
-    uint32_t caller_flags;
-    register uint32_t partition_idx;
-    uint32_t psp = __get_PSP();
-    uint32_t partition_psp, partition_psplim;
-    uint32_t partition_state;
-    uint32_t partition_flags;
-    struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
-    uint32_t caller_partition_id;
-    int32_t client_id;
-    struct iovec_args_t *iovec_args;
-
-    caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
-
-    /* Check partition state consistency */
-    if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
-        != (!desc_ptr->ns_caller)) {
-        /* Partition state inconsistency detected */
-        return TFM_SECURE_LOCK_FAILED;
-    }
-
-    if((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) {
-        /* Disable NS exception handling while secure service is running.
-         * FixMe:
-         * This restriction is applied to limit the number of possible attack
-         * vectors.
-         * To be removed when pre-emption and context management issues have
-         * been analysed and resolved.
-         */
-        TFM_NS_EXC_DISABLE();
-    }
-
-    partition_idx = get_partition_idx(desc_ptr->sp_id);
-
-    curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
-    partition_state = curr_part_data->partition_state;
-    partition_flags = tfm_spm_partition_get_flags(partition_idx);
-    caller_partition_id = tfm_spm_partition_get_partition_id(
-                                                          caller_partition_idx);
-
-    if (tfm_secure_api_initializing) {
-#if TFM_LVL != 1
-        /* Make thread mode unprivileged while untrusted partition init is
-         * executed
-         */
-        if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
-            tfm_spm_partition_change_privilege(
-                                        TFM_PARTITION_UNPRIVILEGED_MODE);
-        }
-#endif
-    } else if (partition_state == SPM_PARTITION_STATE_RUNNING ||
-        partition_state == SPM_PARTITION_STATE_SUSPENDED ||
-        partition_state == SPM_PARTITION_STATE_BLOCKED) {
-        /* Recursion is not permitted! */
-        return TFM_ERROR_PARTITION_NON_REENTRANT;
-    } else if (partition_state != SPM_PARTITION_STATE_IDLE) {
-        /* The partition to be called is not in a proper state */
-        return TFM_SECURE_LOCK_FAILED;
-    }
-
-#if TFM_LVL == 1
-    /* Prepare switch to shared secure partition stack */
-    /* In case the call is coming from the non-secure world, we save the iovecs
-     * on the stop of the stack. So the memory area, that can actually be used
-     * as stack by the partitions starts at a lower address
-     */
-    partition_psp =
-        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
-        sizeof(struct iovec_args_t);
-    partition_psplim =
-        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
-#else
-    partition_psp = curr_part_data->stack_ptr;
-    partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
-#endif
-    /* Store the context for the partition call */
-    tfm_spm_partition_set_caller_partition_idx(partition_idx,
-                                               caller_partition_idx);
-    tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
-
-    if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
-        tfm_spm_partition_set_caller_client_id(partition_idx,
-                                               caller_partition_id);
-    } else {
-        client_id = tfm_nspm_get_current_client_id();
-        if (client_id >= 0)
-        {
-            return TFM_SECURE_LOCK_FAILED;
-        }
-        tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
-    }
-
-#if (TFM_LVL != 1) && (TFM_LVL != 2)
-    /* Dynamic partitioning is only done is TFM level 3 */
-    tfm_spm_partition_sandbox_deconfig(caller_partition_idx);
-
-    /* Configure partition execution environment */
-    if (tfm_spm_partition_sandbox_config(partition_idx) != SPM_ERR_OK) {
-        ERROR_MSG("Failed to configure sandbox for partition!");
-        tfm_secure_api_error_handler();
-    }
-#endif
-
-    /* Default share to scratch area in case of partition to partition calls
-     * this way partitions always get default access to input buffers
-     */
-    /* FixMe: return value/error handling TBD */
-    tfm_spm_partition_set_share(partition_idx, desc_ptr->ns_caller ?
-        TFM_BUFFER_SHARE_NS_CODE : TFM_BUFFER_SHARE_SCRATCH);
-
-#if TFM_LVL == 1
-    /* In level one, only switch context and return from exception if in
-     * handler mode
-     */
-    if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
-        if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
-            /* Save the iovecs on the common stack. The vectors had been sanity
-             * checked already, and since then the interrupts have been kept
-             * disabled. So we can be sure that the vectors haven't been
-             * tampered with since the check.
-             */
-            iovec_args = (struct iovec_args_t *)
-                    ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
-                     sizeof(struct iovec_args_t));
-            if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
-                SPM_ERR_OK) {
-                return TFM_ERROR_GENERIC;
-            }
-            tfm_copy_iovec_parameters(iovec_args,
-                                      &(curr_part_data->iovec_args));
-
-            /* Prepare the partition context, update stack ptr */
-            psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
-                                                        iovec_args,
-                                                     (uint32_t *)partition_psp);
-        } else {
-            /* Prepare the partition context, update stack ptr */
-            psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
-                                                  (uint32_t *)partition_psp);
-        }
-        __set_PSP(psp);
-        __set_PSPLIM(partition_psplim);
-    }
-#else
-    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
-        /* Save the iovecs on the stack of the partition. The vectors had been
-         * sanity checked already, and since then the interrupts have been kept
-         * disabled. So we can be sure that the vectors haven't been tampered
-         * with since the check.
-         */
-        iovec_args =
-        (struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) -
-        sizeof(struct iovec_args_t));
-        if (tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args) !=
-            SPM_ERR_OK) {
-            return TFM_ERROR_GENERIC;
-        }
-        tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
-
-        /* Prepare the partition context, update stack ptr */
-        psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
-                                                    iovec_args,
-                                                    (uint32_t *)partition_psp);
-    } else {
-        /* Prepare the partition context, update stack ptr */
-        psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
-                                              (uint32_t *)partition_psp);
-    }
-    __set_PSP(psp);
-    __set_PSPLIM(partition_psplim);
-#endif
-
-    tfm_spm_partition_set_state(caller_partition_idx,
-                                SPM_PARTITION_STATE_BLOCKED);
-    tfm_spm_partition_set_state(partition_idx, SPM_PARTITION_STATE_RUNNING);
-    tfm_secure_lock++;
-
-    return TFM_SUCCESS;
-}
-
-static int32_t tfm_return_from_partition(uint32_t *excReturn)
-{
-    uint32_t current_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
-    uint32_t current_partition_flags;
-    uint32_t return_partition_idx;
-    uint32_t return_partition_flags;
-    uint32_t psp = __get_PSP();
-    size_t i;
-    struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
-    struct iovec_args_t *iovec_args;
-
-    if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
-        return TFM_SECURE_UNLOCK_FAILED;
-    }
-
-    curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
-    return_partition_idx = curr_part_data->caller_partition_idx;
-
-    if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
-        return TFM_SECURE_UNLOCK_FAILED;
-    }
-
-    ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
-
-    return_partition_flags = tfm_spm_partition_get_flags(return_partition_idx);
-    current_partition_flags = tfm_spm_partition_get_flags(
-            current_partition_idx);
-
-    tfm_secure_lock--;
-
-    if((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) {
-        /* Re-enable NS exceptions when secure service returns to NS client.
-         * FixMe:
-         * To be removed when pre-emption and context management issues have
-         * been analysed and resolved.
-         */
-        TFM_NS_EXC_ENABLE();
-    }
-
-#if (TFM_LVL != 1) && (TFM_LVL != 2)
-    /* Deconfigure completed partition environment */
-    tfm_spm_partition_sandbox_deconfig(current_partition_idx);
-    if (tfm_secure_api_initializing) {
-        /* Restore privilege for thread mode during TF-M init. This is only
-         * have to be done if the partition is not trusted.
-         */
-        if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 0) {
-            tfm_spm_partition_change_privilege(TFM_PARTITION_PRIVILEGED_MODE);
-        }
-    } else {
-        /* Configure the caller partition environment in case this was a
-         * partition to partition call and returning to untrusted partition
-         */
-        if (tfm_spm_partition_sandbox_config(return_partition_idx)
-            != SPM_ERR_OK) {
-            ERROR_MSG("Failed to configure sandbox for partition!");
-            tfm_secure_api_error_handler();
-        }
-        if (return_partition_flags & SPM_PART_FLAG_APP_ROT) {
-            /* Restore share status */
-            tfm_spm_partition_set_share(
-                return_partition_idx,
-                tfm_spm_partition_get_runtime_data(
-                    return_partition_idx)->share);
-        }
-    }
-#endif
-
-#if TFM_LVL == 1
-    if (!(return_partition_flags & SPM_PART_FLAG_APP_ROT) ||
-        (tfm_secure_api_initializing)) {
-        /* In TFM level 1 context restore is only done when
-         * returning to NS or after initialization
-         */
-        /* Restore caller context */
-        restore_caller_ctx(svc_ctx,
-            (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
-        *excReturn = ret_part_data->lr;
-        __set_PSP(ret_part_data->stack_ptr);
-        extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
-        uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
-       __set_PSPLIM(psp_stack_bottom);
-
-        /* FIXME: The condition should be removed once all the secure service
-         *        calls are done via the iovec veneers */
-        if (curr_part_data->iovec_api) {
-            iovec_args = (struct iovec_args_t *)
-                         ((uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
-                         sizeof(struct iovec_args_t));
-
-            for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
-                curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
-            }
-            tfm_clear_iovec_parameters(iovec_args);
-        }
-    }
-#else
-    /* Restore caller context */
-    restore_caller_ctx(svc_ctx,
-        (struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
-    *excReturn = ret_part_data->lr;
-    __set_PSP(ret_part_data->stack_ptr);
-    __set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
-    /* Clear the context entry before returning */
-    tfm_spm_partition_set_stack(
-                current_partition_idx, psp + sizeof(struct tfm_exc_stack_t));
-
-    /* FIXME: The condition should be removed once all the secure service
-     *        calls are done via the iovec veneers */
-    if (curr_part_data->iovec_api) {
-        iovec_args = (struct iovec_args_t *)
-                     (tfm_spm_partition_get_stack_top(current_partition_idx) -
-                     sizeof(struct iovec_args_t));
-
-        for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
-            curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
-        }
-        tfm_clear_iovec_parameters(iovec_args);
-    }
-#endif
-
-    tfm_spm_partition_cleanup_context(current_partition_idx);
-
-    tfm_spm_partition_set_state(current_partition_idx,
-                                SPM_PARTITION_STATE_IDLE);
-    tfm_spm_partition_set_state(return_partition_idx,
-                                SPM_PARTITION_STATE_RUNNING);
-
-    return TFM_SUCCESS;
-}
-
 void tfm_secure_api_error_handler(void)
 {
     ERROR_MSG("Security violation when calling secure API");
@@ -681,487 +175,3 @@
     }
 }
 
-static int32_t tfm_check_sfn_req_integrity(const struct tfm_sfn_req_s *desc_ptr)
-{
-    if ((desc_ptr == NULL) ||
-        (desc_ptr->sp_id == 0) ||
-        (desc_ptr->sfn == NULL)) {
-        /* invalid parameter */
-        return TFM_ERROR_INVALID_PARAMETER;
-    }
-    return TFM_SUCCESS;
-}
-
-static int32_t tfm_core_check_sfn_req_rules(
-        const struct tfm_sfn_req_s *desc_ptr)
-{
-    /* Check partition idx validity */
-    if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
-        return TFM_ERROR_NO_ACTIVE_PARTITION;
-    }
-
-    if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
-        /* Secure domain is already locked!
-         * This should only happen if caller is secure partition!
-         * FixMe: This scenario is a potential security breach
-         * Take appropriate action!
-         */
-        return TFM_ERROR_SECURE_DOMAIN_LOCKED;
-    }
-
-    if (tfm_secure_api_initializing) {
-        int32_t id =
-            tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
-
-        if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
-            /* Invalid request during system initialization */
-            ERROR_MSG("Invalid service request during initialization!");
-            return TFM_ERROR_NOT_INITIALIZED;
-        }
-    }
-
-    return TFM_SUCCESS;
-}
-
-void tfm_secure_api_init_done(void)
-{
-    tfm_secure_api_initializing = 0;
-#if TFM_LVL != 1
-    if (tfm_spm_partition_sandbox_config(TFM_SP_NON_SECURE_ID) != SPM_ERR_OK) {
-        ERROR_MSG("Failed to configure sandbox for partition!");
-        tfm_secure_api_error_handler();
-    }
-#endif
-}
-
-int32_t tfm_core_sfn_request_handler(
-                             struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
-{
-    int32_t res;
-
-    res = tfm_check_sfn_req_integrity(desc_ptr);
-    if (res != TFM_SUCCESS) {
-        ERROR_MSG("Invalid service request!");
-        tfm_secure_api_error_handler();
-    }
-
-    __disable_irq();
-
-    desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
-
-    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
-        res = tfm_core_check_sfn_parameters(desc_ptr);
-        if (res != TFM_SUCCESS) {
-            /* The sanity check of iovecs failed. */
-            __enable_irq();
-            tfm_secure_api_error_handler();
-        }
-    }
-
-    res = tfm_core_check_sfn_req_rules(desc_ptr);
-    if (res != TFM_SUCCESS) {
-        /* FixMe: error compartmentalization TBD */
-        tfm_spm_partition_set_state(
-            desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
-        __enable_irq();
-        ERROR_MSG("Unauthorized service request!");
-        tfm_secure_api_error_handler();
-    }
-
-    res = tfm_start_partition(desc_ptr, excReturn);
-    if (res != TFM_SUCCESS) {
-        /* FixMe: consider possible fault scenarios */
-        __enable_irq();
-        ERROR_MSG("Failed to process service request!");
-        tfm_secure_api_error_handler();
-    }
-
-    __enable_irq();
-
-    return res;
-}
-
-#if TFM_LVL == 1
-int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
-{
-    int32_t res;
-    int32_t *args;
-    int32_t retVal;
-
-    if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
-        res = tfm_core_check_sfn_parameters(desc_ptr);
-        if (res != TFM_SUCCESS) {
-            /* The sanity check of iovecs failed. */
-            return res;
-        }
-    }
-
-    /* No excReturn value is needed as no exception handling is used */
-    res = tfm_core_sfn_request_handler(desc_ptr, 0);
-
-    if (res != TFM_SUCCESS) {
-        tfm_secure_api_error_handler();
-    }
-
-    /* Secure partition to secure partition call in TFM level 1 */
-    args = desc_ptr->args;
-    retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
-
-    /* return handler should restore original exc_return value... */
-    res = tfm_return_from_partition(NULL);
-    if (res == TFM_SUCCESS) {
-        /* If unlock successful, pass SS return value to caller */
-        res = retVal;
-    } else {
-        /* Unlock errors indicate ctx database corruption or unknown
-         * anomalies. Halt execution
-         */
-        ERROR_MSG("Secure API error during unlock!");
-        tfm_secure_api_error_handler();
-    }
-    return res;
-}
-#endif
-
-void tfm_core_validate_secure_caller_handler(uint32_t *svc_args)
-{
-
-    int32_t res = TFM_ERROR_GENERIC;
-    uint32_t running_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const struct spm_partition_runtime_data_t *curr_part_data =
-            tfm_spm_partition_get_runtime_data(running_partition_idx);
-    uint32_t running_partition_flags =
-            tfm_spm_partition_get_flags(running_partition_idx);
-    uint32_t caller_partition_flags =
-            tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
-
-    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
-        /* This handler shouldn't be called from outside partition context.
-         * Partitions are only allowed to run while S domain is locked.
-         */
-        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    /* Store return value in r0 */
-    if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
-        res = TFM_SUCCESS;
-    }
-    svc_args[0] = res;
-}
-
-int32_t tfm_core_check_buffer_access(uint32_t  partition_idx,
-                                     void     *start_addr,
-                                     size_t    len,
-                                     uint32_t  alignment)
-{
-    uintptr_t start_addr_value = (uintptr_t)start_addr;
-    uintptr_t end_addr_value = (uintptr_t)start_addr + len;
-    uintptr_t alignment_mask;
-
-    alignment_mask = (((uintptr_t)1) << alignment) - 1;
-
-    /* Check that the pointer is aligned properly */
-    if (start_addr_value & alignment_mask) {
-        /* not aligned, return error */
-        return 0;
-    }
-
-    /* Protect against overflow (and zero len) */
-    if (end_addr_value <= start_addr_value)
-    {
-        return 0;
-    }
-
-#if TFM_LVL == 1
-    /* For privileged partition execution, all secure data memory and stack
-     * is accessible
-     */
-    if (start_addr_value >= S_DATA_START &&
-        end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
-        return 1;
-    }
-#else
-    /* For non-privileged execution the partition's data and stack is
-     * accessible
-     */
-    if (start_addr_value >=
-            tfm_spm_partition_get_stack_bottom(partition_idx) &&
-        end_addr_value <=
-            tfm_spm_partition_get_stack_top(partition_idx)) {
-        return 1;
-    }
-    if (start_addr_value >=
-           tfm_spm_partition_get_rw_start(partition_idx) &&
-        end_addr_value <=
-           tfm_spm_partition_get_rw_limit(partition_idx)) {
-        return 1;
-    }
-    if (start_addr_value >=
-           tfm_spm_partition_get_zi_start(partition_idx) &&
-        end_addr_value <=
-           tfm_spm_partition_get_zi_limit(partition_idx)) {
-        return 1;
-    }
-#endif
-    return 0;
-}
-
-void tfm_core_get_caller_client_id_handler(uint32_t *svc_args)
-{
-    uintptr_t result_ptr_value = svc_args[0];
-    uint32_t running_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const uint32_t running_partition_flags =
-            tfm_spm_partition_get_flags(running_partition_idx);
-    const struct spm_partition_runtime_data_t *curr_part_data =
-            tfm_spm_partition_get_runtime_data(running_partition_idx);
-    int res = 0;
-
-    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT))  {
-        /* This handler shouldn't be called from outside partition context.
-         * Partitions are only allowed to run while S domain is locked.
-         */
-        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    /* Make sure that the output pointer points to a memory area that is owned
-     * by the partition
-     */
-    res = tfm_core_check_buffer_access(running_partition_idx,
-                                       (void *)result_ptr_value,
-                                       sizeof(curr_part_data->caller_client_id),
-                                       2);
-    if (!res) {
-        /* Not in accessible range, return error */
-        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    *((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
-
-    /* Store return value in r0 */
-    svc_args[0] = TFM_SUCCESS;
-}
-
-void tfm_core_memory_permission_check_handler(uint32_t *svc_args)
-{
-    uint32_t ptr = svc_args[0];
-    uint32_t size = svc_args[1];
-    int32_t access = svc_args[2];
-
-    uint32_t max_buf_size, ptr_start, range_limit, range_check = false;
-    int32_t res;
-    uint32_t running_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const struct spm_partition_runtime_data_t *curr_part_data =
-            tfm_spm_partition_get_runtime_data(running_partition_idx);
-    uint32_t running_partition_flags =
-            tfm_spm_partition_get_flags(running_partition_idx);
-    int32_t flags = 0;
-    void *rangeptr;
-
-    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) || (size == 0)) {
-        /* This handler should only be called from a secure partition. */
-        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    if (curr_part_data->share != TFM_BUFFER_SHARE_PRIV) {
-        flags |= CMSE_MPU_UNPRIV;
-    }
-
-    if (access == TFM_MEMORY_ACCESS_RW) {
-        flags |= CMSE_MPU_READWRITE;
-    } else {
-        flags |= CMSE_MPU_READ;
-    }
-
-    /* Check if partition access to address would fail */
-    rangeptr = cmse_check_address_range((void *)ptr, size, flags);
-
-    /* Get regions associated with address */
-    cmse_address_info_t addr_info = cmse_TT((void *)ptr);
-
-    if (rangeptr == NULL) {
-        svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    if (addr_info.flags.secure) {
-#if TFM_LVL == 1
-        /* For privileged partition execution, all secure data memory is
-         * accessible
-         */
-        max_buf_size = S_DATA_SIZE;
-        ptr_start = S_DATA_START;
-        range_limit = S_DATA_LIMIT;
-#else
-        /* Only scratch is permitted in secure memory */
-        max_buf_size = (uint32_t)tfm_scratch_area_size;
-        ptr_start = (uint32_t)tfm_scratch_area;
-        range_limit = (uint32_t)tfm_scratch_area + tfm_scratch_area_size - 1;
-#endif
-        range_check = true;
-    } else {
-        if (!addr_info.flags.sau_region_valid) {
-            /* If address is NS, TF-M expects SAU to be configured
-             */
-            svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
-            return;
-        }
-        switch (addr_info.flags.sau_region) {
-        case TFM_NS_REGION_CODE:
-            if (access == TFM_MEMORY_ACCESS_RW) {
-                res = TFM_ERROR_INVALID_PARAMETER;
-            } else {
-                /* Currently TF-M does not support checks for NS Memory
-                 * accesses by partitions
-                 */
-                res = TFM_SUCCESS;
-            }
-            break;
-        case TFM_NS_REGION_DATA:
-            /* Currently TF-M does not support checks for NS Memory
-             * accesses by partitions
-             */
-            res = TFM_SUCCESS;
-            break;
-        default:
-            /* Only NS data and code regions can be accessed as buffers */
-            res = TFM_ERROR_INVALID_PARAMETER;
-            break;
-        }
-    }
-
-    if (range_check == true) {
-        if ((size <= max_buf_size) && (ptr >= ptr_start)
-            && (ptr <= range_limit + 1 - size)) {
-            res = TFM_SUCCESS;
-        } else {
-            res = TFM_ERROR_INVALID_PARAMETER;
-        }
-    }
-
-    /* Store return value in r0 */
-    svc_args[0] = res;
-}
-
-/* This SVC handler is called if veneer is running in thread mode */
-uint32_t tfm_core_partition_request_svc_handler(
-        const struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
-{
-    struct tfm_sfn_req_s *desc_ptr;
-
-    if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
-        /* Service request SVC called with MSP active.
-         * Either invalid configuration for Thread mode or SVC called
-         * from Handler mode, which is not supported.
-         * FixMe: error severity TBD
-         */
-        ERROR_MSG("Service request SVC called with MSP active!");
-        tfm_secure_api_error_handler();
-    }
-
-    desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
-
-    if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
-        tfm_secure_api_error_handler();
-    }
-
-    return EXC_RETURN_SECURE_FUNCTION;
-}
-
-/* This SVC handler is called when sfn returns */
-uint32_t tfm_core_partition_return_handler(uint32_t lr)
-{
-    int32_t res;
-
-    if (!(lr & EXC_RETURN_STACK_PROCESS)) {
-        /* Partition return SVC called with MSP active.
-         * This should not happen!
-         */
-        ERROR_MSG("Partition return SVC called with MSP active!");
-        tfm_secure_api_error_handler();
-    }
-
-    /* Store return value from secure partition */
-    int32_t retVal = *(int32_t *)__get_PSP();
-
-    if (!is_iovec_api_call()) {
-        if ((retVal > TFM_SUCCESS) &&
-            (retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
-            /* Secure function returned a reserved value */
-#ifdef TFM_CORE_DEBUG
-            LOG_MSG("Invalid return value from secure partition!");
-#endif
-            /* FixMe: error can be traced to specific secure partition
-             * and Core is not compromised. Error handling flow can be
-             * refined
-             */
-            tfm_secure_api_error_handler();
-        }
-    }
-
-    res = tfm_return_from_partition(&lr);
-    if (res != TFM_SUCCESS) {
-        /* Unlock errors indicate ctx database corruption or unknown anomalies
-         * Halt execution
-         */
-        ERROR_MSG("Secure API error during unlock!");
-        tfm_secure_api_error_handler();
-    }
-
-    return lr;
-}
-
-void tfm_core_set_buffer_area_handler(uint32_t *args)
-{
-    /* r0 is stored in args[0] in exception stack frame
-     * Store input parameter before writing return value to that address
-     */
-    enum tfm_buffer_share_region_e share;
-    uint32_t running_partition_idx =
-            tfm_spm_partition_get_running_partition_idx();
-    const struct spm_partition_runtime_data_t *curr_part_data =
-            tfm_spm_partition_get_runtime_data(running_partition_idx);
-    uint32_t caller_partition_idx = curr_part_data->caller_partition_idx;
-    uint32_t running_partition_flags =
-            tfm_spm_partition_get_flags(running_partition_idx);
-    uint32_t caller_partition_flags =
-            tfm_spm_partition_get_flags(caller_partition_idx);
-
-     /* tfm_core_set_buffer_area() returns int32_t */
-    int32_t *res_ptr = (int32_t *)&args[0];
-
-    if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
-        /* This handler should only be called from a secure partition. */
-        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    switch (args[0]) {
-    case TFM_BUFFER_SHARE_DEFAULT:
-        share = (!(caller_partition_flags & SPM_PART_FLAG_APP_ROT)) ?
-            (TFM_BUFFER_SHARE_NS_CODE) : (TFM_BUFFER_SHARE_SCRATCH);
-        break;
-    case TFM_BUFFER_SHARE_SCRATCH:
-    case TFM_BUFFER_SHARE_NS_CODE:
-        share = args[0];
-        break;
-    default:
-        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
-        return;
-    }
-
-    if (tfm_spm_partition_set_share(running_partition_idx, share) ==
-            SPM_ERR_OK) {
-        *res_ptr = TFM_SUCCESS;
-    } else {
-        *res_ptr = TFM_ERROR_INVALID_PARAMETER;
-    }
-
-    return;
-}
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 23bcd40..50b56fc 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -130,6 +130,25 @@
                                             uint32_t ns_caller,
                                             uint32_t privileged);
 
+#ifdef TFM_PSA_API
+/* The following macros are only valid if secure services can be called
+ * using veneer functions. This is not the case if IPC messaging is enabled
+ */
+#define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d)               \
+        do {                                                         \
+            ERROR_MSG("Invalid TF-M configuration detected");        \
+            tfm_secure_api_error_handler();                          \
+            /* This point never reached */                           \
+            return (int32_t)TFM_ERROR_GENERIC;                       \
+        } while (0)
+#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d)                     \
+        do {                                                         \
+            ERROR_MSG("Invalid TF-M configuration detected");        \
+            tfm_secure_api_error_handler();                          \
+            /* This point never reached */                           \
+            return (int32_t)TFM_ERROR_GENERIC;                       \
+        } while (0)
+#else
 #define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
         return tfm_core_partition_request(id, fn, TFM_SFN_API_IOVEC, \
                 (int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d)
@@ -190,5 +209,6 @@
 
     }
 }
+#endif
 
 #endif /* __TFM_SECURE_API_H__ */
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index 5f10465..4d56a91 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -98,10 +98,12 @@
      */
 
     /* For the non secure Execution environment */
+#if (TFM_LVL != 1) || defined(TFM_PSA_API)
     extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
     extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[];
     uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
     uint32_t psp_stack_top    = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Limit;
+#endif
     if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
         return SPM_ERR_INVALID_CONFIG;
     }
@@ -117,12 +119,14 @@
     part_ptr->static_data.partition_flags = 0;
 #endif
 
+#if (TFM_LVL != 1) || defined(TFM_PSA_API)
     part_ptr->memory_data.stack_bottom = psp_stack_bottom;
     part_ptr->memory_data.stack_top    = psp_stack_top;
     /* Since RW, ZI and stack are configured as one MPU region, configure
      * RW start address to psp_stack_bottom to get RW access to stack
      */
     part_ptr->memory_data.rw_start     = psp_stack_bottom;
+#endif
 
     part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
     tfm_nspm_configure_clients();
@@ -189,7 +193,10 @@
         }
     }
 
+#ifndef TFM_PSA_API
+    /* Not applicable if IPC messaging is used */
     tfm_secure_api_init_done();
+#endif
 
     if (fail_cnt == 0) {
         return SPM_ERR_OK;
@@ -198,6 +205,7 @@
     }
 }
 
+#if (TFM_LVL != 1) || defined(TFM_PSA_API)
 uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
 {
     return g_spm_partition_db.partitions[partition_idx].
@@ -208,8 +216,9 @@
 {
     return g_spm_partition_db.partitions[partition_idx].memory_data.stack_top;
 }
+#endif
 
-#if TFM_LVL != 1
+#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
 enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx)
 {
     struct spm_partition_desc_t *part;
@@ -319,6 +328,7 @@
             caller_client_id = caller_client_id;
 }
 
+#ifndef TFM_PSA_API
 enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
                                            uint32_t share)
 {
@@ -334,6 +344,7 @@
     }
     return ret;
 }
+#endif
 
 enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
                                            const int32_t *args)
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index c0122d6..106b29f 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -87,6 +87,7 @@
  */
 uint32_t get_partition_idx(uint32_t partition_id);
 
+#if (TFM_LVL != 1) || defined(TFM_PSA_API)
 /**
  * \brief Get bottom of stack region for a partition
  *
@@ -108,8 +109,9 @@
  * \note This function doesn't check if partition_idx is valid.
  */
 uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
+#endif
 
-#if TFM_LVL != 1
+#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
 /**
  * \brief Configure isolated sandbox for a partition
  *
diff --git a/secure_fw/spm/spm_db.h b/secure_fw/spm/spm_db.h
index b8827b4..6e6e25c 100644
--- a/secure_fw/spm/spm_db.h
+++ b/secure_fw/spm/spm_db.h
@@ -57,7 +57,9 @@
     struct spm_partition_static_data_t static_data;
     struct spm_partition_runtime_data_t runtime_data;
     struct tfm_spm_partition_platform_data_t *platform_data;
+#if (TFM_LVL != 1) || defined(TFM_PSA_API)
     struct tfm_spm_partition_memory_data_t memory_data;
+#endif
 #ifdef TFM_PSA_API
     struct tfm_thrd_ctx sp_thrd;
 #endif
@@ -66,8 +68,12 @@
 /* Macros to pick linker symbols and allow to form the partition data base */
 #define REGION(a, b, c) a##b##c
 #define REGION_NAME(a, b, c) REGION(a, b, c)
+#if (TFM_LVL == 1) && !defined(TFM_PSA_API)
+#define REGION_DECLARE(a, b, c)
+#else
 #define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
 #define PART_REGION_ADDR(partition, region) \
     (uint32_t)&REGION_NAME(Image$$, partition, region)
+#endif
 
 #endif /* __SPM_DB_H__ */
diff --git a/secure_fw/spm/spm_db_setup.h b/secure_fw/spm/spm_db_setup.h
index 1e91271..db06154 100644
--- a/secure_fw/spm/spm_db_setup.h
+++ b/secure_fw/spm/spm_db_setup.h
@@ -38,6 +38,9 @@
         data.partition_priority = TFM_PRIORITY(priority);                     \
     } while (0)
 
+#if (TFM_LVL == 1) && !defined(TFM_PSA_API)
+#define PARTITION_INIT_MEMORY_DATA(data, partition)
+#else
 #define PARTITION_INIT_MEMORY_DATA(data, partition)                            \
     do {                                                                       \
         data.code_start      = PART_REGION_ADDR(partition, $$Base);            \
@@ -51,7 +54,7 @@
         data.stack_bottom    = PART_REGION_ADDR(partition, _STACK$$ZI$$Base);  \
         data.stack_top       = PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
     } while (0)
-
+#endif
 
 #if TFM_LVL == 1
 #define PARTITION_INIT_RUNTIME_DATA(data, partition)            \