SPM: Add build-time config for optional PSA APIs

When there is no connection-based service,
the following PSA APIs are optional:
    - psa_connect
    - psa_close
    - psa_set_rhandle
Currently, they are always built, linked and not removed
because the SVC handler references them.
This patch adds a config CONFIG_TFM_CONNECTION_BASED_SERVICE_API
so that they can be excluded and save memory footprints.

Signed-off-by: Xinyu Zhang <xinyu.zhang@arm.com>
Change-Id: I0205ca6a569d375fb1879ab673470a4b2a7a7c01
diff --git a/interface/include/config_impl.h.template b/interface/include/config_impl.h.template
index 2a220ab..0696b91 100644
--- a/interface/include/config_impl.h.template
+++ b/interface/include/config_impl.h.template
@@ -59,4 +59,9 @@
 #error "FP is not supported for SFN model."
 #endif
 
+{% if partition_statistics['connection_based_srv_num'] > 0 %}
+/* Connection-based services exist, include the connection-specific API set. */
+#define {{"%-56s"|format("CONFIG_TFM_CONNECTION_BASED_SERVICE_API")}} 1
+{% endif %}
+
 #endif /* __CONFIG_IMPL_H__ */
diff --git a/interface/include/psa_interface_redirect.h b/interface/include/psa_interface_redirect.h
index 1514f93..3c16cdf 100644
--- a/interface/include/psa_interface_redirect.h
+++ b/interface/include/psa_interface_redirect.h
@@ -13,12 +13,9 @@
 
 #define psa_framework_version    psa_framework_version_svc
 #define psa_version              psa_version_svc
-#define psa_connect              psa_connect_svc
 #define tfm_psa_call_pack        tfm_psa_call_pack_svc
-#define psa_close                psa_close_svc
 #define psa_wait                 psa_wait_svc
 #define psa_get                  psa_get_svc
-#define psa_set_rhandle          psa_set_rhandle_svc
 #define psa_read                 psa_read_svc
 #define psa_skip                 psa_skip_svc
 #define psa_write                psa_write_svc
@@ -31,17 +28,20 @@
 #define psa_irq_disable          psa_irq_disable_svc
 #define psa_reset_signal         psa_reset_signal_svc
 #define psa_rot_lifecycle_state  psa_rot_lifecycle_state_svc
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+#define psa_connect              psa_connect_svc
+#define psa_close                psa_close_svc
+#define psa_set_rhandle          psa_set_rhandle_svc
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
 
 #elif defined(CONFIG_TFM_PSA_API_CROSS_CALL)
 
 #define psa_framework_version    psa_framework_version_cross
 #define psa_version              psa_version_cross
-#define psa_connect              psa_connect_cross
 #define tfm_psa_call_pack        tfm_psa_call_pack_cross
-#define psa_close                psa_close_cross
 #define psa_wait                 psa_wait_cross
 #define psa_get                  psa_get_cross
-#define psa_set_rhandle          psa_set_rhandle_cross
 #define psa_read                 psa_read_cross
 #define psa_skip                 psa_skip_cross
 #define psa_write                psa_write_cross
@@ -54,6 +54,12 @@
 #define psa_irq_disable          psa_irq_disable_cross
 #define psa_reset_signal         psa_reset_signal_cross
 #define psa_rot_lifecycle_state  psa_rot_lifecycle_state_cross
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+#define psa_connect              psa_connect_cross
+#define psa_close                psa_close_cross
+#define psa_set_rhandle          psa_set_rhandle_cross
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
 
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 #define psa_map_invec            psa_map_invec_cross
@@ -66,14 +72,17 @@
 
 #define psa_framework_version    psa_framework_version_sfn
 #define psa_version              psa_version_sfn
-#define psa_connect              psa_connect_sfn
 #define tfm_psa_call_pack        psa_call_pack_sfn
-#define psa_close                psa_close_sfn
 #define psa_wait                 psa_wait_sfn
 #define psa_read                 psa_read_sfn
 #define psa_skip                 psa_skip_sfn
 #define psa_write                psa_write_sfn
 #define psa_panic                psa_panic_sfn
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+#define psa_connect              psa_connect_sfn
+#define psa_close                psa_close_sfn
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
 
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 #define psa_map_invec            psa_map_invec_sfn
diff --git a/secure_fw/partitions/ns_agent_tz/tfm_psa_api_veneers.c b/secure_fw/partitions/ns_agent_tz/tfm_psa_api_veneers.c
index 6b4c824..69273d0 100644
--- a/secure_fw/partitions/ns_agent_tz/tfm_psa_api_veneers.c
+++ b/secure_fw/partitions/ns_agent_tz/tfm_psa_api_veneers.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -42,10 +42,13 @@
 
 #pragma required = tfm_spm_client_psa_framework_version
 #pragma required = tfm_spm_client_psa_version
-#pragma required = tfm_spm_client_psa_connect
 #pragma required = tfm_spm_client_psa_call
-#pragma required = tfm_spm_client_psa_close
 #pragma required = spm_interface_cross_dispatcher
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+#pragma required = tfm_spm_client_psa_connect
+#pragma required = tfm_spm_client_psa_close
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
 
 #endif /* CONFIG_TFM_PSA_API_CROSS_CALL */
 
@@ -140,50 +143,6 @@
 }
 
 __tfm_psa_secure_gateway_attributes__
-psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t version)
-{
-    __ASM volatile(
-#if !defined(__ICCARM__)
-        ".syntax unified                                      \n"
-#endif
-
-#if !defined(__ARM_ARCH_8_1M_MAIN__)
-        "   ldr    r2, [sp]                                   \n"
-        "   ldr    r3, ="M2S(STACK_SEAL_PATTERN)"             \n"
-        "   cmp    r2, r3                                     \n"
-        "   bne    reent_panic3                               \n"
-#endif
-        "   mrs    r3, control                                \n"
-        "   push   {r2, r3}                                   \n"
-#ifdef CONFIG_TFM_PSA_API_CROSS_CALL
-        "   push   {r0-r4, lr}                                \n"
-        "   ldr    r0, =tfm_spm_client_psa_connect            \n"
-        "   mov    r1, sp                                     \n"
-        "   movs   r2, #0                                     \n"
-        "   bl     spm_interface_cross_dispatcher             \n"
-        "   pop    {r0-r3}                                    \n"
-        "   pop    {r2, r3}                                   \n"
-        "   mov    lr, r3                                     \n"
-#elif defined(CONFIG_TFM_PSA_API_SFN_CALL)
-        "   push   {r4, lr}                                   \n"
-        "   bl     psa_connect_sfn                            \n"
-        "   pop    {r2, r3}                                   \n"
-        "   mov    lr, r3                                     \n"
-#else
-        "   svc    "M2S(TFM_SVC_PSA_CONNECT)"                 \n"
-#endif
-        "   pop    {r2, r3}                                   \n"
-        "   msr    control, r3                                \n"
-        "   bxns   lr                                         \n"
-#if !defined(__ARM_ARCH_8_1M_MAIN__)
-        "reent_panic3:                                        \n"
-        "   svc    "M2S(TFM_SVC_PSA_PANIC)"                   \n"
-        "   b      .                                          \n"
-#endif
-    );
-}
-
-__tfm_psa_secure_gateway_attributes__
 psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
                                  uint32_t ctrl_param,
                                  const psa_invec *in_vec,
@@ -234,6 +193,54 @@
     );
 }
 
+/* Following veneers are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+__tfm_psa_secure_gateway_attributes__
+psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t version)
+{
+    __ASM volatile(
+#if !defined(__ICCARM__)
+        ".syntax unified                                      \n"
+#endif
+
+#if !defined(__ARM_ARCH_8_1M_MAIN__)
+        "   ldr    r2, [sp]                                   \n"
+        "   ldr    r3, ="M2S(STACK_SEAL_PATTERN)"             \n"
+        "   cmp    r2, r3                                     \n"
+        "   bne    reent_panic3                               \n"
+#endif
+        "   mrs    r3, control                                \n"
+        "   push   {r2, r3}                                   \n"
+        "   mov    r3, r12                                    \n"
+#ifdef CONFIG_TFM_PSA_API_CROSS_CALL
+        "   push   {r0-r4, lr}                                \n"
+        "   ldr    r0, =tfm_spm_client_psa_connect            \n"
+        "   mov    r1, sp                                     \n"
+        "   movs   r2, #0                                     \n"
+        "   bl     spm_interface_cross_dispatcher             \n"
+        "   pop    {r0-r3}                                    \n"
+        "   pop    {r2, r3}                                   \n"
+        "   mov    lr, r3                                     \n"
+#elif defined(CONFIG_TFM_PSA_API_SFN_CALL)
+        "   push   {r4, lr}                                   \n"
+        "   bl     psa_connect_sfn                            \n"
+        "   pop    {r2, r3}                                   \n"
+        "   mov    lr, r3                                     \n"
+#else
+        "   svc    "M2S(TFM_SVC_PSA_CONNECT)"                 \n"
+#endif
+        "   pop    {r2, r3}                                   \n"
+        "   msr    control, r3                                \n"
+        "   bxns   lr                                         \n"
+#if !defined(__ARM_ARCH_8_1M_MAIN__)
+        "reent_panic3:                                        \n"
+        "   svc    "M2S(TFM_SVC_PSA_PANIC)"                   \n"
+        "   b      .                                          \n"
+#endif
+    );
+}
+
 __tfm_psa_secure_gateway_attributes__
 void tfm_psa_close_veneer(psa_handle_t handle)
 {
@@ -277,3 +284,5 @@
 #endif
     );
 }
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
diff --git a/secure_fw/spm/cmsis_psa/psa_interface_cross.c b/secure_fw/spm/cmsis_psa/psa_interface_cross.c
index 1d3a7c2..1f9de89 100644
--- a/secure_fw/spm/cmsis_psa/psa_interface_cross.c
+++ b/secure_fw/spm/cmsis_psa/psa_interface_cross.c
@@ -69,21 +69,6 @@
 
 __naked
 __section(".psa_interface_cross_call")
-psa_handle_t psa_connect_cross(uint32_t sid, uint32_t version)
-{
-    __asm volatile(
-#if !defined(__ICCARM__)
-        ".syntax unified                                    \n"
-#endif
-        "push   {r0-r4, lr}                                 \n"
-        "ldr    r0, =tfm_spm_client_psa_connect             \n"
-        "mov    r1, sp                                      \n"
-        "b      psa_interface_cross_unified_entry           \n"
-    );
-}
-
-__naked
-__section(".psa_interface_cross_call")
 psa_status_t tfm_psa_call_pack_cross(psa_handle_t handle,
                                      uint32_t ctrl_param,
                                      const psa_invec *in_vec,
@@ -102,21 +87,6 @@
 
 __naked
 __section(".psa_interface_cross_call")
-void psa_close_cross(psa_handle_t handle)
-{
-    __asm volatile(
-#if !defined(__ICCARM__)
-        ".syntax unified                                    \n"
-#endif
-        "push   {r0-r4, lr}                                 \n"
-        "ldr    r0, =tfm_spm_client_psa_close               \n"
-        "mov    r1, sp                                      \n"
-        "b      psa_interface_cross_unified_entry           \n"
-    );
-}
-
-__naked
-__section(".psa_interface_cross_call")
 psa_signal_t psa_wait_cross(psa_signal_t signal_mask, uint32_t timeout)
 {
     __asm volatile(
@@ -147,21 +117,6 @@
 
 __naked
 __section(".psa_interface_cross_call")
-void psa_set_rhandle_cross(psa_handle_t msg_handle, void *rhandle)
-{
-    __asm volatile(
-#if !defined(__ICCARM__)
-        ".syntax unified                                    \n"
-#endif
-        "push   {r0-r4, lr}                                 \n"
-        "ldr    r0, =tfm_spm_partition_psa_set_rhandle      \n"
-        "mov    r1, sp                                      \n"
-        "b      psa_interface_cross_unified_entry           \n"
-    );
-}
-
-__naked
-__section(".psa_interface_cross_call")
 size_t psa_read_cross(psa_handle_t msg_handle, uint32_t invec_idx,
                       void *buffer, size_t num_bytes)
 {
@@ -343,6 +298,56 @@
     );
 }
 
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+__naked
+__section(".psa_interface_cross_call")
+psa_handle_t psa_connect_cross(uint32_t sid, uint32_t version)
+{
+    __asm volatile(
+#if !defined(__ICCARM__)
+        ".syntax unified                                    \n"
+#endif
+        "push   {r0-r4, lr}                                 \n"
+        "ldr    r0, =tfm_spm_client_psa_connect             \n"
+        "mov    r1, sp                                      \n"
+        "b      psa_interface_cross_unified_entry           \n"
+    );
+}
+
+__naked
+__section(".psa_interface_cross_call")
+void psa_close_cross(psa_handle_t handle)
+{
+    __asm volatile(
+#if !defined(__ICCARM__)
+        ".syntax unified                                    \n"
+#endif
+        "push   {r0-r4, lr}                                 \n"
+        "ldr    r0, =tfm_spm_client_psa_close               \n"
+        "mov    r1, sp                                      \n"
+        "b      psa_interface_cross_unified_entry           \n"
+    );
+}
+
+__naked
+__section(".psa_interface_cross_call")
+void psa_set_rhandle_cross(psa_handle_t msg_handle, void *rhandle)
+{
+    __asm volatile(
+#if !defined(__ICCARM__)
+        ".syntax unified                                    \n"
+#endif
+        "push   {r0-r4, lr}                                 \n"
+        "ldr    r0, =tfm_spm_partition_psa_set_rhandle      \n"
+        "mov    r1, sp                                      \n"
+        "b      psa_interface_cross_unified_entry           \n"
+    );
+}
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 
 __naked
diff --git a/secure_fw/spm/cmsis_psa/psa_interface_sfn.c b/secure_fw/spm/cmsis_psa/psa_interface_sfn.c
index e4eb05a..07d5d80 100644
--- a/secure_fw/spm/cmsis_psa/psa_interface_sfn.c
+++ b/secure_fw/spm/cmsis_psa/psa_interface_sfn.c
@@ -22,24 +22,6 @@
     return tfm_spm_client_psa_version(sid);
 }
 
-psa_handle_t psa_connect_sfn(uint32_t sid, uint32_t version)
-{
-    struct partition_t *p_client, *p_target;
-    psa_status_t stat;
-
-    p_client = GET_CURRENT_COMPONENT();
-
-    stat = tfm_spm_client_psa_connect(sid, version);
-
-    p_target = GET_CURRENT_COMPONENT();
-    if (p_client != p_target) {
-        stat = tfm_spm_partition_psa_reply(p_target->p_msg->msg.handle, stat);
-    }
-
-    spm_handle_programmer_errors(stat);
-    return (psa_handle_t)stat;
-}
-
 psa_status_t psa_call_pack_sfn(psa_handle_t handle, uint32_t ctrl_param,
                                const psa_invec *in_vec, psa_outvec *out_vec)
 {
@@ -59,24 +41,6 @@
     return (psa_status_t)stat;
 }
 
-void psa_close_sfn(psa_handle_t handle)
-{
-    struct partition_t *p_client, *p_target;
-    psa_status_t stat;
-
-    p_client = GET_CURRENT_COMPONENT();
-
-    stat = tfm_spm_client_psa_close(handle);
-
-    p_target = GET_CURRENT_COMPONENT();
-    if (p_client != p_target) {
-        stat = tfm_spm_partition_psa_reply(p_target->p_msg->msg.handle,
-                                           PSA_SUCCESS);
-    }
-
-    spm_handle_programmer_errors(stat);
-}
-
 psa_signal_t psa_wait_sfn(psa_signal_t signal_mask, uint32_t timeout)
 {
     /*
@@ -106,6 +70,47 @@
     tfm_spm_partition_psa_write(msg_handle, outvec_idx, buffer, num_bytes);
 }
 
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+psa_handle_t psa_connect_sfn(uint32_t sid, uint32_t version)
+{
+    struct partition_t *p_client, *p_target;
+    psa_status_t stat;
+
+    p_client = GET_CURRENT_COMPONENT();
+
+    stat = tfm_spm_client_psa_connect(sid, version);
+
+    p_target = GET_CURRENT_COMPONENT();
+    if (p_client != p_target) {
+        stat = tfm_spm_partition_psa_reply(p_target->p_msg->msg.handle, stat);
+    }
+
+    spm_handle_programmer_errors(stat);
+    return (psa_handle_t)stat;
+}
+
+void psa_close_sfn(psa_handle_t handle)
+{
+    struct partition_t *p_client, *p_target;
+    psa_status_t stat;
+
+    p_client = GET_CURRENT_COMPONENT();
+
+    stat = tfm_spm_client_psa_close(handle);
+
+    p_target = GET_CURRENT_COMPONENT();
+    if (p_client != p_target) {
+        stat = tfm_spm_partition_psa_reply(p_target->p_msg->msg.handle,
+                                           PSA_SUCCESS);
+    }
+
+    spm_handle_programmer_errors(stat);
+}
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 
 const void *psa_map_invec_sfn(psa_handle_t msg_handle, uint32_t invec_idx)
diff --git a/secure_fw/spm/cmsis_psa/psa_interface_svc.c b/secure_fw/spm/cmsis_psa/psa_interface_svc.c
index 129db54..ef34b84 100644
--- a/secure_fw/spm/cmsis_psa/psa_interface_svc.c
+++ b/secure_fw/spm/cmsis_psa/psa_interface_svc.c
@@ -26,12 +26,6 @@
                    "bx      lr                                 \n");
 }
 
-__naked psa_handle_t psa_connect_svc(uint32_t sid, uint32_t version)
-{
-    __asm volatile("svc     "M2S(TFM_SVC_PSA_CONNECT)"         \n"
-                   "bx      lr                                 \n");
-}
-
 __naked psa_status_t tfm_psa_call_pack_svc(psa_handle_t handle,
                                            uint32_t ctrl_param,
                                            const psa_invec *in_vec,
@@ -41,12 +35,6 @@
                    "bx      lr                                 \n");
 }
 
-__naked void psa_close_svc(psa_handle_t handle)
-{
-    __asm volatile("svc     "M2S(TFM_SVC_PSA_CLOSE)"           \n"
-                   "bx      lr                                 \n");
-}
-
 __naked psa_signal_t psa_wait_svc(psa_signal_t signal_mask, uint32_t timeout)
 {
     __asm volatile("svc     "M2S(TFM_SVC_PSA_WAIT)"            \n"
@@ -59,12 +47,6 @@
                    "bx      lr                                 \n");
 }
 
-__naked void psa_set_rhandle_svc(psa_handle_t msg_handle, void *rhandle)
-{
-    __asm volatile("svc     "M2S(TFM_SVC_PSA_SET_RHANDLE)"     \n"
-                   "bx      lr                                 \n");
-}
-
 __naked size_t psa_read_svc(psa_handle_t msg_handle, uint32_t invec_idx,
                             void *buffer, size_t num_bytes)
 {
@@ -139,3 +121,26 @@
     __asm volatile("svc     "M2S(TFM_SVC_PSA_LIFECYCLE)"       \n"
                    "bx      lr                                 \n");
 }
+
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+__naked psa_handle_t psa_connect_svc(uint32_t sid, uint32_t version)
+{
+    __asm volatile("svc     "M2S(TFM_SVC_PSA_CONNECT)"         \n"
+                   "bx      lr                                 \n");
+}
+
+__naked void psa_close_svc(psa_handle_t handle)
+{
+    __asm volatile("svc     "M2S(TFM_SVC_PSA_CLOSE)"           \n"
+                   "bx      lr                                 \n");
+}
+
+__naked void psa_set_rhandle_svc(psa_handle_t msg_handle, void *rhandle)
+{
+    __asm volatile("svc     "M2S(TFM_SVC_PSA_SET_RHANDLE)"     \n"
+                   "bx      lr                                 \n");
+}
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
diff --git a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
index e0d92f3..1c41851 100644
--- a/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_core_svcalls_ipc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -42,25 +42,16 @@
         return tfm_spm_client_psa_framework_version();
     case TFM_SVC_PSA_VERSION:
         return tfm_spm_client_psa_version(ctx[0]);
-    case TFM_SVC_PSA_CONNECT:
-        status = tfm_spm_client_psa_connect(ctx[0], ctx[1]);
-        break;
     case TFM_SVC_PSA_CALL:
         status = tfm_spm_client_psa_call((psa_handle_t)ctx[0], ctx[1],
                                          (const psa_invec *)ctx[2],
                                          (psa_outvec *)ctx[3]);
         break;
-    case TFM_SVC_PSA_CLOSE:
-        status = tfm_spm_client_psa_close((psa_handle_t)ctx[0]);
-        break;
     case TFM_SVC_PSA_WAIT:
         return tfm_spm_partition_psa_wait((psa_signal_t)ctx[0], ctx[1]);
     case TFM_SVC_PSA_GET:
         return tfm_spm_partition_psa_get((psa_signal_t)ctx[0],
                                          (psa_msg_t *)ctx[1]);
-    case TFM_SVC_PSA_SET_RHANDLE:
-        tfm_spm_partition_psa_set_rhandle((psa_handle_t)ctx[0], (void *)ctx[1]);
-        break;
     case TFM_SVC_PSA_READ:
         return tfm_spm_partition_psa_read((psa_handle_t)ctx[0], ctx[1],
                                           (void *)ctx[2], (size_t)ctx[3]);
@@ -88,6 +79,18 @@
         break;
     case TFM_SVC_PSA_LIFECYCLE:
         return tfm_spm_get_lifecycle_state();
+/* Following svc handlers are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+    case TFM_SVC_PSA_CONNECT:
+        status = tfm_spm_client_psa_connect(ctx[0], ctx[1]);
+        break;
+    case TFM_SVC_PSA_CLOSE:
+        status = tfm_spm_client_psa_close((psa_handle_t)ctx[0]);
+        break;
+    case TFM_SVC_PSA_SET_RHANDLE:
+        tfm_spm_partition_psa_set_rhandle((psa_handle_t)ctx[0], (void *)ctx[1]);
+        break;
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
 #if TFM_SP_LOG_RAW_ENABLED
     case TFM_SVC_OUTPUT_UNPRIV_STRING:
         return tfm_hal_output_spm_log((const char *)ctx[0], ctx[1]);
diff --git a/secure_fw/spm/cmsis_psa/tfm_rpc.c b/secure_fw/spm/cmsis_psa/tfm_rpc.c
index 5fcd85f..88e7bdd 100644
--- a/secure_fw/spm/cmsis_psa/tfm_rpc.c
+++ b/secure_fw/spm/cmsis_psa/tfm_rpc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -47,13 +47,6 @@
     return tfm_spm_client_psa_version(params->sid);
 }
 
-psa_status_t tfm_rpc_psa_connect(const struct client_call_params_t *params)
-{
-    TFM_CORE_ASSERT(params != NULL);
-
-    return tfm_spm_client_psa_connect(params->sid, params->version);
-}
-
 psa_status_t tfm_rpc_psa_call(const struct client_call_params_t *params)
 {
     TFM_CORE_ASSERT(params != NULL);
@@ -65,6 +58,16 @@
                                    params->in_vec, params->out_vec);
 }
 
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+psa_status_t tfm_rpc_psa_connect(const struct client_call_params_t *params)
+{
+    TFM_CORE_ASSERT(params != NULL);
+
+    return tfm_spm_client_psa_connect(params->sid, params->version);
+}
+
 void tfm_rpc_psa_close(const struct client_call_params_t *params)
 {
     TFM_CORE_ASSERT(params != NULL);
@@ -72,6 +75,8 @@
     tfm_spm_client_psa_close(params->handle);
 }
 
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 int32_t tfm_rpc_register_ops(const struct tfm_rpc_ops_t *ops_ptr)
 {
     if (!ops_ptr) {
diff --git a/secure_fw/spm/cmsis_psa/tfm_spe_mailbox.c b/secure_fw/spm/cmsis_psa/tfm_spe_mailbox.c
index 7c01dc5..ef19c80 100644
--- a/secure_fw/spm/cmsis_psa/tfm_spe_mailbox.c
+++ b/secure_fw/spm/cmsis_psa/tfm_spe_mailbox.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
  * Copyright (c) 2021, Cypress Semiconductor Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -39,11 +39,6 @@
         spm_params.sid = params->psa_version_params.sid;
         *psa_ret = tfm_rpc_psa_version(&spm_params);
         return MAILBOX_SUCCESS;
-    case MAILBOX_PSA_CONNECT:
-        spm_params.sid = params->psa_connect_params.sid;
-        spm_params.version = params->psa_connect_params.version;
-        *psa_ret = tfm_rpc_psa_connect(&spm_params);
-        return MAILBOX_SUCCESS;
     case MAILBOX_PSA_CALL:
         spm_params.handle = params->psa_call_params.handle;
         spm_params.type = params->psa_call_params.type;
@@ -53,10 +48,18 @@
         spm_params.out_len = params->psa_call_params.out_len;
         *psa_ret = tfm_rpc_psa_call(&spm_params);
         return MAILBOX_SUCCESS;
+/* Following cases are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+    case MAILBOX_PSA_CONNECT:
+        spm_params.sid = params->psa_connect_params.sid;
+        spm_params.version = params->psa_connect_params.version;
+        *psa_ret = tfm_rpc_psa_connect(&spm_params);
+        return MAILBOX_SUCCESS;
     case MAILBOX_PSA_CLOSE:
         spm_params.handle = params->psa_close_params.handle;
         tfm_rpc_psa_close(&spm_params);
         return MAILBOX_SUCCESS;
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
     default:
         return MAILBOX_INVAL_PARAMS;
     }
diff --git a/secure_fw/spm/ffm/psa_api.c b/secure_fw/spm/ffm/psa_api.c
index 5d5d2d8..7b8342b 100644
--- a/secure_fw/spm/ffm/psa_api.c
+++ b/secure_fw/spm/ffm/psa_api.c
@@ -139,69 +139,6 @@
     return service->p_ldinf->version;
 }
 
-psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
-{
-    struct service_t *service;
-    struct tfm_msg_body_t *msg;
-    struct tfm_conn_handle_t *connect_handle;
-    int32_t client_id;
-    psa_handle_t handle;
-    bool ns_caller = tfm_spm_is_ns_caller();
-    struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
-
-    /*
-     * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
-     * platform.
-     */
-    service = tfm_spm_get_service_by_sid(sid);
-    if (!service) {
-        return PSA_ERROR_CONNECTION_REFUSED;
-    }
-
-    /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
-    if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
-        return PSA_ERROR_PROGRAMMER_ERROR;
-    }
-
-    /*
-     * It is a PROGRAMMER ERROR if the caller is not authorized to access the
-     * RoT Service.
-     */
-    if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
-        return PSA_ERROR_CONNECTION_REFUSED;
-    }
-
-    /*
-     * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
-     * not supported on the platform.
-     */
-    if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
-        return PSA_ERROR_CONNECTION_REFUSED;
-    }
-
-    client_id = tfm_spm_get_client_id(ns_caller);
-
-    /*
-     * Create connection handle here since it is possible to return the error
-     * code to client when creation fails.
-     */
-    CRITICAL_SECTION_ENTER(cs_assert);
-    connect_handle = tfm_spm_create_conn_handle(service, client_id);
-    CRITICAL_SECTION_LEAVE(cs_assert);
-    if (!connect_handle) {
-        return PSA_ERROR_CONNECTION_BUSY;
-    }
-
-    msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
-
-    handle = tfm_spm_to_user_handle(connect_handle);
-    /* No input or output needed for connect message */
-    tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
-                     client_id, NULL, 0, NULL, 0, NULL);
-
-    return backend_instance.messaging(service, msg);
-}
-
 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
                                      uint32_t ctrl_param,
                                      const psa_invec *inptr,
@@ -388,6 +325,72 @@
     return backend_instance.messaging(service, msg);
 }
 
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
+{
+    struct service_t *service;
+    struct tfm_msg_body_t *msg;
+    struct tfm_conn_handle_t *connect_handle;
+    int32_t client_id;
+    psa_handle_t handle;
+    bool ns_caller = tfm_spm_is_ns_caller();
+    struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
+
+    /*
+     * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
+     * platform.
+     */
+    service = tfm_spm_get_service_by_sid(sid);
+    if (!service) {
+        return PSA_ERROR_CONNECTION_REFUSED;
+    }
+
+    /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
+    if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
+        return PSA_ERROR_PROGRAMMER_ERROR;
+    }
+
+    /*
+     * It is a PROGRAMMER ERROR if the caller is not authorized to access the
+     * RoT Service.
+     */
+    if (tfm_spm_check_authorization(sid, service, ns_caller) != SPM_SUCCESS) {
+        return PSA_ERROR_CONNECTION_REFUSED;
+    }
+
+    /*
+     * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
+     * not supported on the platform.
+     */
+    if (tfm_spm_check_client_version(service, version) != SPM_SUCCESS) {
+        return PSA_ERROR_CONNECTION_REFUSED;
+    }
+
+    client_id = tfm_spm_get_client_id(ns_caller);
+
+    /*
+     * Create connection handle here since it is possible to return the error
+     * code to client when creation fails.
+     */
+    CRITICAL_SECTION_ENTER(cs_assert);
+    connect_handle = tfm_spm_create_conn_handle(service, client_id);
+    CRITICAL_SECTION_LEAVE(cs_assert);
+    if (!connect_handle) {
+        return PSA_ERROR_CONNECTION_BUSY;
+    }
+
+    msg = tfm_spm_get_msg_buffer_from_conn_handle(connect_handle);
+
+    handle = tfm_spm_to_user_handle(connect_handle);
+    /* No input or output needed for connect message */
+    tfm_spm_fill_msg(msg, service, handle, PSA_IPC_CONNECT,
+                     client_id, NULL, 0, NULL, 0, NULL);
+
+    return backend_instance.messaging(service, msg);
+}
+
 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
 {
     struct service_t *service;
@@ -440,6 +443,8 @@
     return backend_instance.messaging(service, msg);
 }
 
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 /* PSA Partition API function body */
 
 psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
@@ -545,29 +550,6 @@
     return PSA_SUCCESS;
 }
 
-void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
-{
-    struct tfm_msg_body_t *msg = NULL;
-    struct tfm_conn_handle_t *conn_handle;
-
-    /* It is a fatal error if message handle is invalid */
-    msg = tfm_spm_get_msg_from_handle(msg_handle);
-    if (!msg) {
-        tfm_core_panic();
-    }
-
-    /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
-    if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
-        tfm_core_panic();
-    }
-
-    msg->msg.rhandle = rhandle;
-    conn_handle = tfm_spm_to_handle_instance(msg_handle);
-
-    /* Store reverse handle for following client calls. */
-    tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
-}
-
 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
                                   void *buffer, size_t num_bytes)
 {
@@ -1040,6 +1022,34 @@
     CRITICAL_SECTION_LEAVE(cs_assert);
 }
 
+/* psa_set_rhandle is only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
+{
+    struct tfm_msg_body_t *msg = NULL;
+    struct tfm_conn_handle_t *conn_handle;
+
+    /* It is a fatal error if message handle is invalid */
+    msg = tfm_spm_get_msg_from_handle(msg_handle);
+    if (!msg) {
+        tfm_core_panic();
+    }
+
+    /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
+    if (SERVICE_IS_STATELESS(msg->service->p_ldinf->flags)) {
+        tfm_core_panic();
+    }
+
+    msg->msg.rhandle = rhandle;
+    conn_handle = tfm_spm_to_handle_instance(msg_handle);
+
+    /* Store reverse handle for following client calls. */
+    tfm_spm_set_rhandle(msg->service, conn_handle, rhandle);
+}
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 
 const void *tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle,
diff --git a/secure_fw/spm/include/ffm/psa_api.h b/secure_fw/spm/include/ffm/psa_api.h
index 1258c76..97ab352 100644
--- a/secure_fw/spm/include/ffm/psa_api.h
+++ b/secure_fw/spm/include/ffm/psa_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -59,23 +59,6 @@
 uint32_t tfm_spm_client_psa_version(uint32_t sid);
 
 /**
- * \brief handler for \ref psa_connect.
- *
- * \param[in] sid               RoT Service identity.
- * \param[in] version           The version of the RoT Service.
- *
- * \retval PSA_SUCCESS          Success.
- * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
- *                              connection.
- * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
- *                              connection at the moment.
- * \retval "Does not return"    The RoT Service ID and version are not
- *                              supported, or the caller is not permitted to
- *                              access the service.
- */
-psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version);
-
-/**
  * \brief handler for \ref psa_call.
  *
  * \param[in] handle            Service handle to the established connection,
@@ -102,6 +85,26 @@
                                      const psa_invec *inptr,
                                      psa_outvec *outptr);
 
+/* Following PSA APIs are only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+/**
+ * \brief handler for \ref psa_connect.
+ *
+ * \param[in] sid               RoT Service identity.
+ * \param[in] version           The version of the RoT Service.
+ *
+ * \retval PSA_SUCCESS          Success.
+ * \retval PSA_ERROR_CONNECTION_REFUSED The SPM or RoT Service has refused the
+ *                              connection.
+ * \retval PSA_ERROR_CONNECTION_BUSY The SPM or RoT Service cannot make the
+ *                              connection at the moment.
+ * \retval "Does not return"    The RoT Service ID and version are not
+ *                              supported, or the caller is not permitted to
+ *                              access the service.
+ */
+psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version);
+
 /**
  * \brief handler for \ref psa_close.
  *
@@ -118,6 +121,8 @@
  */
 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle);
 
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 /* PSA Partition API function body, for privileged use only. */
 
 /**
@@ -157,19 +162,6 @@
 psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg);
 
 /**
- * \brief Function body of \ref psa_set_rhandle.
- *
- * \param[in] msg_handle        Handle for the client's message.
- * \param[in] rhandle           Reverse handle allocated by the RoT Service.
- *
- * \retval void                 Success, rhandle will be provided with all
- *                              subsequent messages delivered on this
- *                              connection.
- * \retval "PROGRAMMER ERROR"   msg_handle is invalid.
- */
-void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
-
-/**
  * \brief Function body of \ref psa_read.
  *
  * \param[in] msg_handle        Handle for the client's message.
@@ -355,6 +347,24 @@
  */
 void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal);
 
+/* psa_set_rhandle is only needed by connection-based services */
+#if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
+
+/**
+ * \brief Function body of \ref psa_set_rhandle.
+ *
+ * \param[in] msg_handle        Handle for the client's message.
+ * \param[in] rhandle           Reverse handle allocated by the RoT Service.
+ *
+ * \retval void                 Success, rhandle will be provided with all
+ *                              subsequent messages delivered on this
+ *                              connection.
+ * \retval "PROGRAMMER ERROR"   msg_handle is invalid.
+ */
+void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
+
+#endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
+
 #if PSA_FRAMEWORK_HAS_MM_IOVEC
 
 /**
diff --git a/tools/tfm_parse_manifest_list.py b/tools/tfm_parse_manifest_list.py
index 3a6bd71..b359f15 100644
--- a/tools/tfm_parse_manifest_list.py
+++ b/tools/tfm_parse_manifest_list.py
@@ -142,6 +142,7 @@
     pid_list = []
     no_pid_manifest_idx = []
     partition_statistics = {
+        'connection_based_srv_num': 0,
         'ipc_partition_num': 0,
         'sfn_partition_num': 0
     }
@@ -218,6 +219,12 @@
             else:
                 partition_statistics['ipc_partition_num'] += 1
 
+        for service in manifest.get('services', []):
+            if 'connection_based' not in service.keys():
+                partition_statistics['connection_based_srv_num'] += 1
+            elif service['connection_based']:
+                partition_statistics['connection_based_srv_num'] += 1
+
         manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
 
         if 'output_path' in manifest_item:
@@ -250,7 +257,6 @@
 
     context['partitions'] = partition_list
     context['partition_statistics'] = partition_statistics
-
     context['stateless_services'] = process_stateless_services(partition_list)
 
     return context