Core: Move context information to the service db

This commit removes the ctx array, and moves all the service context
related data.

Two new dummy services are added, one for the non-secure PE, and one
for the core. The latter, TFM_SEC_FUNC_CORE_ID, is used as running
service when calling secure tests. This way the checks done at context
switch pass.

Change-Id: I4fc3cad59a57e8dea630c642b8c363cbacfd58f3
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index e634998..eeeb5ad 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -144,6 +144,8 @@
          */
     }
 
+    tfm_spm_service_set_state(TFM_SEC_FUNC_CORE_ID, SPM_PART_STATE_RUNNING);
+
     extern uint32_t Stack_Mem[];
 
     __set_PSPLIM((uint32_t)Stack_Mem);
@@ -173,5 +175,12 @@
 #endif
 #endif
 
+    /* We close the TFM_SEC_FUNC_CORE_ID service, because its only purpose is
+     * to be able to pass the state checks for the tests started from secure.
+     */
+    tfm_spm_service_set_state(TFM_SEC_FUNC_CORE_ID, SPM_PART_STATE_CLOSED);
+    tfm_spm_service_set_state(TFM_SEC_FUNC_NON_SECURE_ID,
+                              SPM_PART_STATE_RUNNING);
+
     jump_to_ns_code();
 }
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index d2d885a..d3e9cce 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -16,20 +16,9 @@
 #include "region_defs.h"
 #include "tfm_api.h"
 
-#define SECURE_LOCK_STACK_LIMIT 5
-
 /* NOTE: this does not account for possible FP stacking */
 #define SVC_STACK_FRAME_SIZE 0x20
 
-static struct tfm_secure_lock_ctx_t {
-    uint32_t service_id;
-    uint32_t orig_psp;
-    uint32_t orig_psplim;
-    uint32_t orig_lr;
-    int32_t  ns_caller;
-    enum tfm_buffer_share_region_e share;
-} ctx[SECURE_LOCK_STACK_LIMIT];
-
 #ifndef TFM_LVL
 #error TFM_LVL is not defined!
 #endif
@@ -46,7 +35,10 @@
 
 extern void tfm_core_service_return_svc(void);
 
-static int32_t lock_cnt;
+/* This is the "Big Lock" on the secure side, to guarantee single entry
+ * to SPE
+ */
+static int32_t tfm_secure_lock;
 
 static uint32_t *prepare_service_ctx(
             struct tfm_sfn_req_s *desc_ptr, uint32_t *dst)
@@ -72,60 +64,67 @@
 
 static int32_t tfm_push_lock(struct tfm_sfn_req_s *desc_ptr, uint32_t lr)
 {
-    if ((lock_cnt >= 0) && (lock_cnt < SECURE_LOCK_STACK_LIMIT)) {
+    uint32_t caller_service_id = tfm_spm_service_get_running_service_id();
+
+    if (caller_service_id >= TFM_SEC_FUNC_BASE &&
+        /* Also check service state consistency */
+        (caller_service_id == TFM_SEC_FUNC_NON_SECURE_ID) ==
+                (desc_ptr->ns_caller != 0)) {
         register uint32_t service_id = desc_ptr->ss_id;
         uint32_t psp = __get_PSP();
         uint32_t service_psp, service_psplim;
+        uint32_t service_state = tfm_spm_service_get_state(service_id);
+
+        if (service_state == SPM_PART_STATE_RUNNING ||
+            service_state == SPM_PART_STATE_SUSPENDED ||
+            service_state == SPM_PART_STATE_BLOCKED) {
+            /* Recursion is not permitted! */
+            return TFM_ERROR_SERVICE_NON_REENTRANT;
+        } else if (service_state != SPM_PART_STATE_IDLE) {
+            /* The service to be called is not in a proper state */
+            return TFM_SECURE_LOCK_FAILED;
+        }
+
 #if TFM_LVL == 1
         /* Prepare switch to shared secure service stack */
         service_psp =
             (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
         service_psplim =
             (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
-        if ((lock_cnt > 0) && (ctx[lock_cnt-1].service_id == desc_ptr->ss_id)) {
-            /* Direct recursion is not permitted! */
-            return TFM_ERROR_SERVICE_NON_REENTRANT;
-        }
 #else
-        if (lock_cnt > 0) {
+        if (caller_service_id != TFM_SEC_FUNC_NON_SECURE_ID) {
             /* Store the caller PSP in case we are doing a service to
              * service call
              */
-            tfm_spm_service_set_stack(ctx[lock_cnt-1].service_id, psp);
+            tfm_spm_service_set_stack(caller_service_id, psp);
         }
-
         service_psp = tfm_spm_service_get_stack(service_id);
-        if (service_psp != tfm_spm_service_get_stack_top(service_id)) {
-            /* We can't stack a service if it's already running, i.e. it has a
-             * context stacked
-             */
-            return TFM_ERROR_SERVICE_NON_REENTRANT;
-        }
         service_psplim = tfm_spm_service_get_stack_bottom(service_id);
 #endif
         /* Stack the context for the service call */
-        ctx[lock_cnt].service_id = service_id;
-        ctx[lock_cnt].orig_psp = psp;
-        ctx[lock_cnt].orig_psplim = __get_PSPLIM();
-        ctx[lock_cnt].orig_lr = lr;
-        ctx[lock_cnt].ns_caller = desc_ptr->ns_caller;
-        /* Default share to scratch area in case of service-to-service calls
-         * this way services always get default access to input buffers
-         */
-        ctx[lock_cnt].share = desc_ptr->ns_caller ?
-            TFM_BUFFER_SHARE_NS_CODE : TFM_BUFFER_SHARE_SCRATCH;
+        tfm_spm_service_set_orig_psp(service_id, psp);
+        tfm_spm_service_set_orig_psplim(service_id, __get_PSPLIM());
+        tfm_spm_service_set_orig_lr(service_id, lr);
+        tfm_spm_service_set_caller_service_id(service_id, caller_service_id);
 
 #if (TFM_LVL != 1) && (TFM_LVL != 2)
         /* Dynamic service partitioning is only done is TFM level 3 */
-        if (lock_cnt > 0) {
+        if (caller_service_id != TFM_SEC_FUNC_NON_SECURE_ID) {
             /* In a service to service call, deconfigure the caller service */
-            tfm_spm_service_sandbox_deconfig(ctx[lock_cnt-1].service_id);
+            tfm_spm_service_sandbox_deconfig(caller_service_id);
         }
 
         /* Configure service execution environment */
         tfm_spm_service_sandbox_config(service_id);
 #endif
 
+        /* Default share to scratch area in case of service-to-service calls
+         * this way services always get default access to input buffers
+         */
+        /* FixMe: return value/error handling TBD */
+        tfm_spm_service_set_share(service_id, 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
@@ -138,16 +137,15 @@
             __set_PSPLIM(service_psplim);
         }
 #else
-        /* FixMe: return value/error handling TBD */
-        tfm_spm_set_share_region(ctx[lock_cnt].share);
-
         /* Prepare the service context, update stack ptr */
         psp = (uint32_t)prepare_service_ctx(desc_ptr, (uint32_t *)service_psp);
         __set_PSP(psp);
         __set_PSPLIM(service_psplim);
 #endif
 
-        lock_cnt++;
+        tfm_spm_service_set_state(caller_service_id, SPM_PART_STATE_BLOCKED);
+        tfm_spm_service_set_state(service_id, SPM_PART_STATE_RUNNING);
+        tfm_secure_lock++;
 
         return TFM_SUCCESS;
     } else {
@@ -158,46 +156,59 @@
 
 static int32_t tfm_pop_lock(uint32_t *lr_ptr)
 {
-    if ((lock_cnt > 0) && (lock_cnt <= SECURE_LOCK_STACK_LIMIT)) {
-        lock_cnt--;
+    uint32_t current_service_id = tfm_spm_service_get_running_service_id();
+    uint32_t return_service_id =
+            tfm_spm_service_get_caller_service_id(current_service_id);
+
+    if (current_service_id < TFM_SEC_FUNC_BASE) {
+        return TFM_SECURE_UNLOCK_FAILED;
+    }
+
+    if (return_service_id >= TFM_SEC_FUNC_BASE) {
+        tfm_secure_lock--;
 #if (TFM_LVL != 1) && (TFM_LVL != 2)
         /* Deconfigure completed service environment */
-        tfm_spm_service_sandbox_deconfig(ctx[lock_cnt].service_id);
-        if (lock_cnt > 0) {
+        tfm_spm_service_sandbox_deconfig(current_service_id);
+        if (return_service_id != TFM_SEC_FUNC_NON_SECURE_ID) {
             /* Configure the caller service environment in case this was a
              * service to service call
              */
-            tfm_spm_service_sandbox_config(ctx[lock_cnt-1].service_id);
+            tfm_spm_service_sandbox_config(return_service_id);
             /* Restore share status */
-            tfm_spm_set_share_region(ctx[lock_cnt-1].share);
+            tfm_spm_service_set_share(return_service_id,
+                    tfm_spm_service_get_share(return_service_id));
         }
 #endif
 
 #if TFM_LVL == 1
-        if (ctx[lock_cnt].ns_caller) {
+        if (tfm_spm_service_get_caller_service_id(current_service_id) ==
+                TFM_SEC_FUNC_NON_SECURE_ID) {
             /* In TFM level 1 context restore is only done when
              * returning to NS
              */
             /* Restore caller PSP and LR ptr */
-            __set_PSP(ctx[lock_cnt].orig_psp);
-            __set_PSPLIM(ctx[lock_cnt].orig_psplim);
-            *lr_ptr = ctx[lock_cnt].orig_lr;
+            __set_PSP(tfm_spm_service_get_orig_psp(current_service_id));
+            __set_PSPLIM(tfm_spm_service_get_orig_psplim(current_service_id));
+            *lr_ptr = tfm_spm_service_get_orig_lr(current_service_id);
         }
 #else
         uint32_t psp = __get_PSP();
 
         /* Discount SVC call stack frame when storing sfn ctx */
         tfm_spm_service_set_stack(
-                    ctx[lock_cnt].service_id, psp + SVC_STACK_FRAME_SIZE);
+                    current_service_id, psp + SVC_STACK_FRAME_SIZE);
 
         /* Restore caller PSP and LR ptr */
-        __set_PSP(ctx[lock_cnt].orig_psp);
-        __set_PSPLIM(ctx[lock_cnt].orig_psplim);
-        *lr_ptr = ctx[lock_cnt].orig_lr;
+        __set_PSP(tfm_spm_service_get_orig_psp(current_service_id));
+        __set_PSPLIM(tfm_spm_service_get_orig_psplim(current_service_id));
+        *lr_ptr = tfm_spm_service_get_orig_lr(current_service_id);
 #endif
 
         /* Clear the context entry in the context stack before returning */
-        memset(&ctx[lock_cnt], 0, sizeof(ctx[0]));
+        tfm_spm_service_cleanup_context(current_service_id);
+
+        tfm_spm_service_set_state(current_service_id, SPM_PART_STATE_IDLE);
+        tfm_spm_service_set_state(return_service_id, SPM_PART_STATE_RUNNING);
 
         return TFM_SUCCESS;
     } else {
@@ -239,7 +250,7 @@
              */
             return TFM_ERROR_NS_THREAD_MODE_CALL;
         }
-        if (lock_cnt != 0) {
+        if (tfm_secure_lock != 0) {
             /*
              * Secure domain is already locked!
              * This should only happen if caller is secure function!
@@ -438,8 +449,9 @@
 {
 
     int32_t res = TFM_ERROR_GENERIC;
+    uint32_t running_service_id = tfm_spm_service_get_running_service_id();
 
-    if (lock_cnt == 0)  {
+    if (running_service_id == TFM_SEC_FUNC_NON_SECURE_ID)  {
         /* This handler shouldn't be called from outside service context.
          * Services are only allowed to run while S domain is locked.
          */
@@ -448,7 +460,8 @@
     }
 
     /* Store return value in r0 */
-    if (!ctx[lock_cnt-1].ns_caller) {
+    if (tfm_spm_service_get_caller_service_id(running_service_id) !=
+            TFM_SEC_FUNC_NON_SECURE_ID) {
         res = TFM_SUCCESS;
     }
     svc_args[0] = res;
@@ -462,8 +475,9 @@
 
     uint32_t max_buf_size, ptr_start, range_limit, range_check = false;
     int32_t res;
+    uint32_t running_service_id = tfm_spm_service_get_running_service_id();
 
-    if ((lock_cnt == 0) || (size == 0)) {
+    if ((running_service_id == TFM_SEC_FUNC_NON_SECURE_ID) || (size == 0)) {
         /* This handler shouldn't be called from outside service context.
          * Services are only allowed to run while S domain is locked.
          */
@@ -473,7 +487,8 @@
 
     int32_t flags = 0;
 
-    if (ctx[lock_cnt-1].share != TFM_BUFFER_SHARE_PRIV) {
+    if (tfm_spm_service_get_share(running_service_id) !=
+            TFM_BUFFER_SHARE_PRIV) {
         flags |= CMSE_MPU_UNPRIV;
     }
 
@@ -657,12 +672,12 @@
      * Store input parameter before writing return value to that address
      */
     enum tfm_buffer_share_region_e share;
+    uint32_t running_service_id = tfm_spm_service_get_running_service_id();
      /* tfm_core_set_buffer_area() returns int32_t */
     int32_t *res_ptr = (int32_t *)&args[0];
 
-    if (lock_cnt == 0) {
+    if (running_service_id == TFM_SEC_FUNC_NON_SECURE_ID) {
         /* This handler shouldn't be called from outside service context.
-         * Services are only allowed to run while S domain is locked
          */
         *res_ptr = TFM_ERROR_INVALID_PARAMETER;
         return;
@@ -670,7 +685,8 @@
 
     switch (args[0]) {
     case TFM_BUFFER_SHARE_DEFAULT:
-        share = (ctx[lock_cnt-1].ns_caller) ?
+        share = (tfm_spm_service_get_caller_service_id(running_service_id) ==
+                TFM_SEC_FUNC_NON_SECURE_ID) ?
             (TFM_BUFFER_SHARE_NS_CODE) : (TFM_BUFFER_SHARE_SCRATCH);
         break;
     case TFM_BUFFER_SHARE_SCRATCH:
@@ -682,18 +698,11 @@
         return;
     }
 
-#if TFM_LVL == 1
-    /* No configuration needed in level 1 */
-    ctx[lock_cnt-1].share = share;
-    *res_ptr = TFM_SUCCESS;
-#else
-    if (tfm_spm_set_share_region(share) == SPM_ERR_OK) {
-        ctx[lock_cnt-1].share = share;
+    if (tfm_spm_service_set_share(running_service_id, share) == SPM_ERR_OK) {
         *res_ptr = TFM_SUCCESS;
     } else {
         *res_ptr = TFM_ERROR_INVALID_PARAMETER;
     }
-#endif
 
     return;
 }
diff --git a/secure_fw/spm/service_defs.h b/secure_fw/spm/service_defs.h
index 7c8e292..5aba225 100644
--- a/secure_fw/spm/service_defs.h
+++ b/secure_fw/spm/service_defs.h
@@ -13,21 +13,33 @@
  */
 #define TFM_SEC_FUNC_BASE 256
 
+/* A reserved partition ID that is used for uninitialised data */
+#define INVALID_PARITION_ID (~0U)
+
 /* FixMe: current implementation requires consecutive IDs, no gaps */
-#define TFM_SEC_FUNC_STORAGE_ID (TFM_SEC_FUNC_BASE + 0)
+/* From the SPM point of view the non secure processing environment is handled
+ * as a special secure partition. This simplifies the context switch
+ * operations.
+ */
+#define TFM_SEC_FUNC_NON_SECURE_ID (TFM_SEC_FUNC_BASE + 0)
+/* A dummy partition for TFM_SEC_FUNC_CORE is created to handle secure service
+ * calls done directly from the core, before NS execution started.
+ */
+#define TFM_SEC_FUNC_CORE_ID (TFM_SEC_FUNC_BASE + 1)
+#define TFM_SEC_FUNC_STORAGE_ID (TFM_SEC_FUNC_BASE + 2)
 
 #ifdef CORE_TEST_SERVICES
-#define TFM_SEC_FUNC_CORE_TEST_ID (TFM_SEC_FUNC_BASE + 1)
-#define TFM_SEC_FUNC_CORE_TEST_2_ID (TFM_SEC_FUNC_BASE + 2)
+#define TFM_SEC_FUNC_CORE_TEST_ID (TFM_SEC_FUNC_BASE + 3)
+#define TFM_SEC_FUNC_CORE_TEST_2_ID (TFM_SEC_FUNC_BASE + 4)
 
 /* Give SST test service next ID after core test services */
 #ifdef SST_TEST_SERVICES
-#define TFM_SEC_FUNC_SST_TEST_SERVICE_ID (TFM_SEC_FUNC_BASE + 3)
+#define TFM_SEC_FUNC_SST_TEST_SERVICE_ID (TFM_SEC_FUNC_BASE + 5)
 #endif
 
 #elif defined(SST_TEST_SERVICES) /* CORE_TEST_SERVICES */
 /* Avoid creating a gap if core test services are not enabled */
-#define TFM_SEC_FUNC_SST_TEST_SERVICE_ID (TFM_SEC_FUNC_BASE + 1)
+#define TFM_SEC_FUNC_SST_TEST_SERVICE_ID (TFM_SEC_FUNC_BASE + 3)
 #endif /* CORE_TEST_SERVICES */
 
 #endif /* __SERVICE_DEFS_H__ */
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index 79ba4cd..af4f4bd 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -8,8 +8,9 @@
 /* This file contains the apis exported by the SPM to tfm core */
 
 #include <stdio.h>
-#include "spm_db.h"
 #include "spm_api.h"
+#include "spm_db.h"
+#include "tfm_api.h"
 #include "mpu_armv8m_drv.h"
 #include "region_defs.h"
 #include "secure_fw/core/tfm_core.h"
@@ -34,29 +35,31 @@
 
 /*
  * This function is called when a secure service causes an error.
+ * In case of an error in the error handling, a non-zero value have to be
+ * returned.
  */
 static void tfm_spm_service_err_handler(
-    uint32_t ss_id, ss_error_type_t err_type, int32_t err_code)
+    struct spm_service_region_t *service,
+    ss_error_type_t err_type,
+    int32_t err_code)
 {
-    /*
-     * FixMe: error handling to be added. E.g. service info to be updated with
-     * init failed so that calls to the service are rejected
-     */
 #ifdef TFM_CORE_DEBUG
     if (err_type == TFM_INIT_FAILURE) {
-        printf("Service init failed for service id 0x%08X\r\n", ss_id);
+        printf("Service init failed for service id 0x%08X\r\n",
+                service->service_id);
     } else {
         printf("Unknown service error %d for service id 0x%08X\r\n",
-            err_type,
-            ss_id);
+            err_type, service->service_id);
     }
 #endif
+    tfm_spm_service_set_state(service->service_id, SPM_PART_STATE_CLOSED);
 }
 
 enum spm_err_t tfm_spm_db_init(void)
 {
     /* This function initialises service db */
     g_spm_service_db.is_init = 1;
+    g_spm_service_db.running_service_id = INVALID_PARITION_ID;
 
     g_spm_service_db.services_count =
         create_user_service_db(&g_spm_service_db, SPM_MAX_SERVICES);
@@ -123,7 +126,11 @@
     return SPM_ERR_OK;
 }
 
-enum spm_err_t tfm_spm_set_share_region(enum tfm_buffer_share_region_e share)
+/**
+ * Set share region to which the service needs access
+ */
+static enum spm_err_t tfm_spm_set_share_region(
+            enum tfm_buffer_share_region_e share)
 {
     enum spm_err_t res = SPM_ERR_INVALID_CONFIG;
     uint32_t scratch_base =
@@ -189,12 +196,16 @@
             ppc_configure_to_secure(serv->periph_ppc_bank,
                                     serv->periph_ppc_loc);
         }
-        if (serv->service_init != 0) {
+        if (serv->service_init == NULL) {
+            tfm_spm_service_set_state(serv->service_id, SPM_PART_STATE_IDLE);
+        } else {
             int32_t ret = serv->service_init();
 
-            if (ret != 0) {
-                tfm_spm_service_err_handler(serv->service_id,
-                    TFM_INIT_FAILURE, ret);
+            if (ret == TFM_SUCCESS) {
+                tfm_spm_service_set_state(
+                        serv->service_id, SPM_PART_STATE_IDLE);
+            } else {
+                tfm_spm_service_err_handler(serv, TFM_INIT_FAILURE, ret);
                 fail_cnt++;
             }
         }
@@ -339,3 +350,98 @@
     g_spm_service_db.services[SERVICE_ID_GET(service_id)].stack_ptr = stack_ptr;
 }
 #endif
+
+uint32_t tfm_spm_service_get_state(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].
+            service_state;
+}
+
+uint32_t tfm_spm_service_get_caller_service_id(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].
+            caller_service_id;
+}
+
+uint32_t tfm_spm_service_get_orig_psp(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psp;
+}
+
+uint32_t tfm_spm_service_get_orig_psplim(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psplim;
+}
+
+uint32_t tfm_spm_service_get_orig_lr(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_lr;
+}
+
+uint32_t tfm_spm_service_get_share(uint32_t service_id)
+{
+    return g_spm_service_db.services[SERVICE_ID_GET(service_id)].share;
+}
+
+void tfm_spm_service_set_state(uint32_t service_id, uint32_t state)
+{
+    g_spm_service_db.services[SERVICE_ID_GET(service_id)].service_state = state;
+    if (state == SPM_PART_STATE_RUNNING) {
+        g_spm_service_db.running_service_id = service_id;
+    }
+}
+
+void tfm_spm_service_set_caller_service_id(uint32_t service_id,
+                                           uint32_t caller_service_id)
+{
+    g_spm_service_db.services[SERVICE_ID_GET(service_id)].caller_service_id =
+            caller_service_id;
+}
+
+void tfm_spm_service_set_orig_psp(uint32_t service_id, uint32_t orig_psp)
+{
+    g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psp = orig_psp;
+}
+
+void tfm_spm_service_set_orig_psplim(uint32_t service_id, uint32_t orig_psplim)
+{
+    g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_psplim =
+            orig_psplim;
+}
+
+void tfm_spm_service_set_orig_lr(uint32_t service_id, uint32_t orig_lr)
+{
+    g_spm_service_db.services[SERVICE_ID_GET(service_id)].orig_lr = orig_lr;
+}
+
+enum spm_err_t tfm_spm_service_set_share(uint32_t service_id, uint32_t share)
+{
+    enum spm_err_t ret = SPM_ERR_OK;
+
+#if TFM_LVL != 1
+    /* Only need to set configuration on levels higher than 1 */
+    ret = tfm_spm_set_share_region(share);
+#endif
+
+    if (ret == SPM_ERR_OK) {
+        g_spm_service_db.services[SERVICE_ID_GET(service_id)].share = share;
+    }
+    return ret;
+}
+
+uint32_t tfm_spm_service_get_running_service_id(void)
+{
+    return g_spm_service_db.running_service_id;
+}
+
+void tfm_spm_service_cleanup_context(uint32_t service_id)
+{
+    struct spm_service_region_t *service =
+            &g_spm_service_db.services[SERVICE_ID_GET(service_id)];
+    service->service_state = 0;
+    service->caller_service_id = 0;
+    service->orig_psp = 0;
+    service->orig_psplim = 0;
+    service->orig_lr = 0;
+    service->share = 0;
+}
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index f6059cf..92263f7 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -20,6 +20,15 @@
     SPM_ERR_INVALID_CONFIG,
 };
 
+enum spm_part_state_t {
+    SPM_PART_STATE_UNINIT = 0,
+    SPM_PART_STATE_IDLE,
+    SPM_PART_STATE_RUNNING,
+    SPM_PART_STATE_SUSPENDED,
+    SPM_PART_STATE_BLOCKED,
+    SPM_PART_STATE_CLOSED,
+};
+
 /**
  * \brief Configure isolated sandbox for a service
  *
@@ -76,6 +85,82 @@
 uint32_t tfm_spm_service_get_stack_top(uint32_t service_id);
 
 /**
+ * \brief Get the current state of a service
+ *
+ * \param[in] service_id     Service id
+ *
+ * \return The state of the specified service
+ *
+ * \note This function doesn't check if service_id is valid.
+ * \note The returned value has the value set of \ref spm_part_state_t.
+ */
+uint32_t tfm_spm_service_get_state(uint32_t service_id);
+
+/**
+ * \brief Get the Id of the caller of the service given
+ *
+ * \param[in] service_id     Service id to get the caller of
+ *
+ * \return The Id of the caller service
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+uint32_t tfm_spm_service_get_caller_service_id(uint32_t service_id);
+
+/**
+ * \brief Get the original PSP of the service
+ *
+ * \param[in] service_id     Service id
+ *
+ * \return The original PSP of the service
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+uint32_t tfm_spm_service_get_orig_psp(uint32_t service_id);
+
+/**
+ * \brief Get the original PSP limit of the service
+ *
+ * \param[in] service_id     Service id
+ *
+ * \return The original PSP limit of the service
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+uint32_t tfm_spm_service_get_orig_psplim(uint32_t service_id);
+
+/**
+ * \brief Get the original link register value of the service
+ *
+ * \param[in] service_id     Service id
+ *
+ * \return The original link register value of the service
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+uint32_t tfm_spm_service_get_orig_lr(uint32_t service_id);
+
+/**
+ * \brief Get the buffer share region of the service
+ *
+ * \param[in] service_id     Service id
+ *
+ * \return The buffer share region of the service
+ *
+ * \note This function doesn't check if service_id is valid.
+ * \note The returned value has the value set of \ref tfm_buffer_share_region_e
+ */
+uint32_t tfm_spm_service_get_share(uint32_t service_id);
+
+/**
+ * \brief Returns the id of the service that has running state
+ *
+ * \return The Id of the service with the running state, if there is any set.
+ *         0 otherwise.
+ */
+uint32_t tfm_spm_service_get_running_service_id(void);
+
+/**
  * \brief Save stack pointer for service in database
  *
  * \param[in] service_id     Service id
@@ -86,6 +171,71 @@
 void tfm_spm_service_set_stack(uint32_t service_id, uint32_t stack_ptr);
 
 /**
+ * \brief Set the current state of a service
+ *
+ * \param[in] service_id     Service id
+ * \param[in] state          The state to be set
+ *
+ * \note This function doesn't check if service_id is valid.
+ * \note The \ref state has to have the value set of \ref spm_part_state_t.
+ */
+void tfm_spm_service_set_state(uint32_t service_id, uint32_t state);
+
+/**
+ * \brief Set the caller service Id for a given service
+ *
+ * \param[in] service_id         Service id
+ * \param[in] caller_service_id  The Id of the caller service
+ *
+ * \note This function doesn't check if any of the service_ids is valid.
+ */
+void tfm_spm_service_set_caller_service_id(uint32_t service_id,
+                                           uint32_t caller_service_id);
+
+/**
+ * \brief Set the original PSP value of a service
+ *
+ * \param[in] service_id     Service id
+ * \param[in] orig_psp       The PSP value to set
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+void tfm_spm_service_set_orig_psp(uint32_t service_id, uint32_t orig_psp);
+
+/**
+ * \brief Set the original PSP limit value of a service
+ *
+ * \param[in] service_id     Service id
+ * \param[in] orig_psplim    The PSP limit value to set
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+void tfm_spm_service_set_orig_psplim(uint32_t service_id, uint32_t orig_psplim);
+
+/**
+ * \brief Set the original link register value of a service
+ *
+ * \param[in] service_id     Service id
+ * \param[in] orig_lr        The link register value to set
+ *
+ * \note This function doesn't check if service_id is valid.
+ */
+void tfm_spm_service_set_orig_lr(uint32_t service_id, uint32_t orig_lr);
+
+/**
+ * \brief Set the buffer share region of the service
+ *
+ * \param[in] service_id     Service id
+ * \param[in] share          The buffer share region to be set
+ *
+ * \return Error code \ref spm_err_t
+ *
+ * \note This function doesn't check if service_id is valid.
+ * \note share has to have the value set of \ref tfm_buffer_share_region_e
+ */
+enum spm_err_t tfm_spm_service_set_share(uint32_t service_id, uint32_t share);
+
+/**
  * \brief Initialize service database
  *
  * \return Error code \ref spm_err_t
@@ -107,14 +257,12 @@
 enum spm_err_t tfm_spm_service_init(void);
 
 /**
- * \brief Set share region to which the service needs access
+ * \brief Clears the context info from the database for a service.
  *
- * \param[in] share     Share region id \ref tfm_buffer_share_region_e
- *
- * \return Error code \ref spm_err_t
+ * \param[in] service_id     Service id
  *
  * \note This function doesn't check if service_id is valid.
  */
-enum spm_err_t tfm_spm_set_share_region(enum tfm_buffer_share_region_e share);
+void tfm_spm_service_cleanup_context(uint32_t service_id);
 
 #endif /*__SPM_API_H__ */
diff --git a/secure_fw/spm/spm_db.h b/secure_fw/spm/spm_db.h
index ed31dbd..cb3dd3a 100644
--- a/secure_fw/spm/spm_db.h
+++ b/secure_fw/spm/spm_db.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -23,6 +23,12 @@
 #if TFM_LVL == 1
 struct spm_service_region_t {
     uint32_t service_id;
+    uint32_t service_state;
+    uint32_t caller_service_id;
+    uint32_t orig_psp;
+    uint32_t orig_psplim;
+    uint32_t orig_lr;
+    uint32_t share;
     uint32_t stack_ptr;
     uint32_t periph_start;
     uint32_t periph_limit;
@@ -33,6 +39,12 @@
 #else
 struct spm_service_region_t {
     uint32_t service_id;
+    uint32_t service_state;
+    uint32_t caller_service_id;
+    uint32_t orig_psp;
+    uint32_t orig_psplim;
+    uint32_t orig_lr;
+    uint32_t share;
     uint32_t code_start;
     uint32_t code_limit;
     uint32_t ro_start;
@@ -55,6 +67,7 @@
 struct spm_service_db_t {
     uint32_t is_init;
     uint32_t services_count;
+    uint32_t running_service_id;
     struct spm_service_region_t services[SPM_MAX_SERVICES];
 };
 
@@ -87,6 +100,12 @@
      }                                                        \
      db_ptr = (uint32_t *)&(db->services[index]);             \
     *db_ptr++ = service##_ID;                                 \
+    *db_ptr++ = SPM_PART_STATE_UNINIT; /* service_state  */   \
+    *db_ptr++ = 0U;     /* caller service id */               \
+    *db_ptr++ = 0U;     /* original psp */                    \
+    *db_ptr++ = 0U;     /* original psplim */                 \
+    *db_ptr++ = 0U;     /* original lr */                     \
+    *db_ptr++ = 0U;     /* share */                           \
     *db_ptr++ = 0U;     /* stack pointer on service enter */  \
     *db_ptr++ = 0U;     /* peripheral start */                \
     *db_ptr++ = 0U;     /* peripheral limit */                \
@@ -101,6 +120,12 @@
      }                                                                       \
      db_ptr = (uint32_t *)&(db->services[index]);                            \
     *db_ptr++ = service##_ID;                                                \
+    *db_ptr++ = SPM_PART_STATE_UNINIT; /* service_state  */                  \
+    *db_ptr++ = 0U;     /* caller service id */                              \
+    *db_ptr++ = 0U;     /* original psp */                                   \
+    *db_ptr++ = 0U;     /* original psplim */                                \
+    *db_ptr++ = 0U;     /* original lr */                                    \
+    *db_ptr++ = 0U;     /* share */                                          \
     *db_ptr++ = (uint32_t)&REGION_NAME(Image$$, service, $$Base);            \
     *db_ptr++ = (uint32_t)&REGION_NAME(Image$$, service, $$Limit);           \
     *db_ptr++ = (uint32_t)&REGION_NAME(Image$$, service, $$RO$$Base);        \
@@ -120,6 +145,58 @@
 }
 #endif
 
+#if TFM_LVL == 1
+#define DUMMY_SERVICE_ADD(service) {                          \
+     if (index >= max_services) {                             \
+         return max_services;                                 \
+     }                                                        \
+     db_ptr = (uint32_t *)&(db->services[index]);             \
+    *db_ptr++ = service##_ID;                                 \
+    *db_ptr++ = SPM_PART_STATE_UNINIT; /* service_state  */   \
+    *db_ptr++ = 0U;     /* caller service id */               \
+    *db_ptr++ = 0U;     /* original psp */                    \
+    *db_ptr++ = 0U;     /* original psplim */                 \
+    *db_ptr++ = 0U;     /* original lr */                     \
+    *db_ptr++ = 0U;     /* share */                           \
+    *db_ptr++ = 0U;     /* stack pointer on service enter */  \
+    *db_ptr++ = 0U;     /* peripheral start */                \
+    *db_ptr++ = 0U;     /* peripheral limit */                \
+    *db_ptr++ = 0U;     /* uint16_t[2] peripheral bank/loc */ \
+    *db_ptr++ = 0U;     /* service init function*/            \
+    index++;                                                  \
+    }
+#else
+#define DUMMY_SERVICE_ADD(service) {                          \
+     if (index >= max_services) {                             \
+         return max_services;                                 \
+     }                                                        \
+     db_ptr = (uint32_t *)&(db->services[index]);             \
+    *db_ptr++ = service##_ID;                                 \
+    *db_ptr++ = SPM_PART_STATE_UNINIT; /* service_state  */   \
+    *db_ptr++ = 0U;     /* caller service id */               \
+    *db_ptr++ = 0U;     /* original_psp */                    \
+    *db_ptr++ = 0U;     /* original_psplim */                 \
+    *db_ptr++ = 0U;     /* original_lr */                     \
+    *db_ptr++ = 0U;     /* share */                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;                                           \
+    *db_ptr++ = 0U;     /* peripheral start */                \
+    *db_ptr++ = 0U;     /* peripheral limit */                \
+    *db_ptr++ = 0U;     /* uint16_t[2] peripheral bank/loc */ \
+    *db_ptr++ = 0U;     /* service init function*/            \
+    index++;                                                  \
+}
+#endif
+
 #define SERVICE_ADD_PERIPHERAL(service, start, limit, bank, loc) {          \
         db_ptr = (uint32_t *)&(db->services[SERVICE_ID_GET(service##_ID)]); \
         ((struct spm_service_region_t *)db_ptr)->periph_start = start;      \
diff --git a/secure_fw/spm/user_service_defines.inc b/secure_fw/spm/user_service_defines.inc
index e3fbbf5..59ab7bc 100644
--- a/secure_fw/spm/user_service_defines.inc
+++ b/secure_fw/spm/user_service_defines.inc
@@ -13,6 +13,13 @@
 #include "target_cfg.h"
 #include "service_defs.h"
 
+/* TFM_SEC_FUNC_NON_SECURE and TFM_SEC_FUNC_CORE are not real services, we
+ * only created them to have an entry for them in the database. They don't have
+ * their dedicated sections in the scatter file, so no symbols are needed to
+ * be declared.
+ */
+/* SERVICE_DECLARE(TFM_SEC_FUNC_NON_SECURE) */
+/* SERVICE_DECLARE(TFM_SEC_FUNC_CORE) */
 SERVICE_DECLARE(TFM_SEC_FUNC_STORAGE)
 
 #ifdef CORE_TEST_SERVICES
@@ -28,6 +35,8 @@
 #define __SPM_ADD_USER_SERVICES__
 
 /* Order must be same as id!!! */
+DUMMY_SERVICE_ADD(TFM_SEC_FUNC_NON_SECURE)
+DUMMY_SERVICE_ADD(TFM_SEC_FUNC_CORE)
 SERVICE_ADD(TFM_SEC_FUNC_STORAGE)
 
 #ifdef CORE_TEST_SERVICES
diff --git a/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c
index 08f1389..cca4541 100644
--- a/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c
+++ b/test/test_services/tfm_core_test_2/tfm_ss_core_test_2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2018, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -11,9 +11,13 @@
 #include "tfm_secure_api.h"
 #include "test/test_services/tfm_core_test/core_test_defs.h"
 
+/* FIXME: Add a testcase to test that a failed init makes the secure partition
+ * closed, and none of its functions can be called.
+ * A new test service for this purpose is to be added.
+ */
 int32_t core_test_2_init(void)
 {
-    return TFM_ERROR_GENERIC;
+    return TFM_SUCCESS;
 }
 
 int32_t spm_core_test_2_slave_service(void)