Core: use secure partition context for its init

- set appropriate stack pointer for partition init
- move target-independent init code to TF-M core
- set unprivileged execution for init functions if
  privilege handling is enabled
- fix naming convention bug related to spm_api.h
- fix header reference for partition ids

Change-Id: I56fe20a247ecde20047658d3227ae95257c95e0f
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/secure_fw/core/tfm_core.c b/secure_fw/core/tfm_core.c
index f48e9fc..6b64ce1 100644
--- a/secure_fw/core/tfm_core.c
+++ b/secure_fw/core/tfm_core.c
@@ -6,7 +6,9 @@
  */
 
 #include <stdio.h>
+#include "region_defs.h"
 #include "tfm_core.h"
+#include "tfm_internal.h"
 #include "target_cfg.h"
 #include "uart_stdout.h"
 #include "secure_utilities.h"
@@ -86,6 +88,25 @@
 #endif
 }
 
+void configure_ns_code(void)
+{
+    /* SCB_NS.VTOR points to the Non-secure vector table base address */
+    SCB_NS->VTOR = (NS_CODE_START);
+
+    /* Setups Main stack pointer of the non-secure code */
+    uint32_t ns_msp = *((uint32_t *)(NS_CODE_START));
+
+    __TZ_set_MSP_NS(ns_msp);
+
+    /* The entry contains address of the Reset_handler (CMSIS-CORE) function */
+    uint32_t entry_ptr = *((uint32_t *)(NS_CODE_START + 4));
+
+    /* Clears LSB of the function address to indicate the function-call
+     * will perform the switch from secure to non-secure
+     */
+    ns_entry = (nsfptr_t) (entry_ptr & (~0x1));
+}
+
 int32_t tfm_core_init(void)
 {
     /* Enables fault handlers */
@@ -130,20 +151,25 @@
 
     tfm_spm_db_init();
 #if TFM_LVL != 1
-    tfm_spm_mpu_init();
-#endif
-    if (tfm_spm_partition_init() != SPM_ERR_OK) {
-        /* Certain systems might refuse to boot altogether if partitions fail
-         * to initialize. This is a placeholder for such an error handler
-         */
+    if (tfm_spm_mpu_init() != SPM_ERR_OK) {
+        ERROR_MSG("Failed to set up initial MPU configuration! Halting.");
+        while (1) {
+            ;
+        }
     }
-
+#endif
     tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_RUNNING);
 
     extern uint32_t Stack_Mem[];
 
     __set_PSPLIM((uint32_t)Stack_Mem);
 
+    if (tfm_spm_partition_init() != SPM_ERR_OK) {
+        /* Certain systems might refuse to boot altogether if partitions fail
+         * to initialize. This is a placeholder for such an error handler
+         */
+    }
+
 #ifdef TEST_FRAMEWORK_S
     start_integ_test();
 #endif
@@ -153,22 +179,6 @@
     LOG_MSG("Jumping to non-secure code...");
 #endif
 
-#if TFM_LVL != 1
-    /* FixMe: partition MPU regions need to be overloaded for snippet of
-     * code jumping to NS to work in unprivileged thread mode
-     */
-#ifdef UNPRIV_JUMP_TO_NS
-    /* Initialization is done, set thread mode to unprivileged. */
-    CONTROL_Type ctrl;
-
-    ctrl.w = __get_CONTROL();
-    ctrl.b.nPRIV = 1;
-    __set_CONTROL(ctrl.w);
-    __DSB();
-    __ISB();
-#endif
-#endif
-
     /* We close the TFM_SP_CORE_ID partition, because its only purpose is
      * to be able to pass the state checks for the tests started from secure.
      */
diff --git a/secure_fw/core/tfm_internal.h b/secure_fw/core/tfm_internal.h
new file mode 100644
index 0000000..a25bde6
--- /dev/null
+++ b/secure_fw/core/tfm_internal.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_INTERNAL_H__
+#define __TFM_INTERNAL_H__
+
+/*
+ * This function pointer is meant to only hold non secure function pointers.
+ * It will be turned into a non-secure one (LSB cleared) before being called
+ * whatever happens anyway (unless cast to another function pointer type).
+ * Registers will be cleared before branching so that no information leaks
+ * from secure to non-secure world.
+ */
+typedef void __attribute__((cmse_nonsecure_call)) (*nsfptr_t) (void);
+
+extern nsfptr_t ns_entry;
+
+void tfm_secure_api_init_done(void);
+
+/**
+ * \brief Jumps to non-secure code.
+ */
+void jump_to_ns_code(void);
+
+#endif /* __TFM_INTERNAL_H__ */
diff --git a/secure_fw/core/tfm_secure_api.c b/secure_fw/core/tfm_secure_api.c
index f691743..eb0d0b2 100644
--- a/secure_fw/core/tfm_secure_api.c
+++ b/secure_fw/core/tfm_secure_api.c
@@ -39,6 +39,7 @@
  * to SPE
  */
 static int32_t tfm_secure_lock;
+static int32_t tfm_secure_api_init = 1;
 
 static uint32_t *prepare_partition_ctx(
             struct tfm_sfn_req_s *desc_ptr, uint32_t *dst)
@@ -57,7 +58,7 @@
 
     while (i > 0) {
         i--;
-        *(--dst) = desc_ptr->args[i];
+        *(--dst) = (uint32_t)desc_ptr->args[i];
     }
     return dst;
 }
@@ -72,7 +73,9 @@
     uint32_t psp;
     uint32_t partition_psp, partition_psplim;
     uint32_t partition_state;
+    uint32_t partition_flags;
 
+    /* Check partition idx validity */
     if (caller_partition_idx == SPM_INVALID_PARTITION_IDX) {
         return TFM_SECURE_LOCK_FAILED;
     }
@@ -80,94 +83,112 @@
     caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
 
     /* Check partition state consistency */
-    if (((caller_flags&SPM_PART_FLAG_SECURE) != 0) == (!desc_ptr->ns_caller)) {
-        partition_idx = get_partition_idx(desc_ptr->ss_id);
-        psp = __get_PSP();
-        curr_part_data = tfm_spm_partition_get_runtime_data(partition_idx);
-        partition_state = curr_part_data->partition_state;
-
-        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 */
-        partition_psp =
-            (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
-        partition_psplim =
-            (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
-#else
-        if (caller_flags&SPM_PART_FLAG_SECURE) {
-            /* Store the caller PSP in case we are doing a partition to
-             * partition call
-             */
-            tfm_spm_partition_set_stack(caller_partition_idx, psp);
-        }
-        partition_psp = curr_part_data->stack_ptr;
-        partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
-#endif
-        /* Stack the context for the partition call */
-        tfm_spm_partition_set_orig_psp(partition_idx, psp);
-        tfm_spm_partition_set_orig_psplim(partition_idx, __get_PSPLIM());
-        tfm_spm_partition_set_orig_lr(partition_idx, lr);
-        tfm_spm_partition_set_caller_partition_id(partition_idx,
-                                                  caller_partition_idx);
-
-#if (TFM_LVL != 1) && (TFM_LVL != 2)
-        /* Dynamic partition partitioning is only done is TFM level 3 */
-        if (caller_flags&SPM_PART_FLAG_SECURE) {
-            /* In a partition to partition call, deconfigure the
-             * caller partition
-             */
-            tfm_spm_partition_sandbox_deconfig(caller_partition_idx);
-        }
-
-        /* Configure partition execution environment */
-        tfm_spm_partition_sandbox_config(partition_idx);
-#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->exc_num != EXC_NUM_THREAD_MODE) {
-            /* Prepare the partition context, update stack ptr */
-            psp = (uint32_t)prepare_partition_ctx(
-                        desc_ptr, (uint32_t *)partition_psp);
-            __set_PSP(psp);
-            __set_PSPLIM(partition_psplim);
-        }
-#else
-        /* Prepare the partition context, update stack ptr */
-        psp = (uint32_t)prepare_partition_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;
-    } else {
-        /* Secure partition stacking limit exceeded */
+    if (((caller_flags&SPM_PART_FLAG_SECURE) != 0) != (!desc_ptr->ns_caller)) {
+        /* Partition state inconsistency detected */
         return TFM_SECURE_LOCK_FAILED;
     }
+
+    partition_idx = get_partition_idx(desc_ptr->sp_id);
+    psp = __get_PSP();
+
+    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);
+
+    if ((tfm_secure_api_init) &&
+        (tfm_spm_partition_get_partition_id(caller_partition_idx)
+            == TFM_SP_CORE_ID) &&
+        (partition_state == SPM_PARTITION_STATE_UNINIT)) {
+#if TFM_LVL != 1
+        /* Make thread mode unprivileged while untrusted partition init is
+         * executed
+         */
+        if ((partition_flags & SPM_PART_FLAG_TRUSTED) == 0) {
+            CONTROL_Type ctrl;
+
+            ctrl.w = __get_CONTROL();
+            ctrl.b.nPRIV = 1;
+            __set_CONTROL(ctrl.w);
+            __DSB();
+            __ISB();
+        }
+#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 */
+    partition_psp =
+        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
+    partition_psplim =
+        (uint32_t)&REGION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
+#else
+    if (caller_flags&SPM_PART_FLAG_SECURE) {
+        /* Store the caller PSP in case we are doing a partition to
+         * partition call
+         */
+        tfm_spm_partition_set_stack(caller_partition_idx, psp);
+    }
+    partition_psp = curr_part_data->stack_ptr;
+    partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
+#endif
+    /* Stack the context for the partition call */
+    tfm_spm_partition_set_orig_psp(partition_idx, psp);
+    tfm_spm_partition_set_orig_psplim(partition_idx, __get_PSPLIM());
+    tfm_spm_partition_set_orig_lr(partition_idx, lr);
+    tfm_spm_partition_set_caller_partition_idx(partition_idx,
+                                               caller_partition_idx);
+
+#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->exc_num != EXC_NUM_THREAD_MODE) || (tfm_secure_api_init)) {
+        /* Prepare the partition context, update stack ptr */
+        psp = (uint32_t)prepare_partition_ctx(
+                    desc_ptr, (uint32_t *)partition_psp);
+        __set_PSP(psp);
+        __set_PSPLIM(partition_psplim);
+    }
+#else
+    /* Prepare the partition context, update stack ptr */
+    psp = (uint32_t)prepare_partition_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_pop_lock(uint32_t *lr_ptr)
@@ -175,6 +196,7 @@
     uint32_t current_partition_idx =
             tfm_spm_partition_get_running_partition_idx();
     const struct spm_partition_runtime_data_t *curr_part_data;
+    uint32_t current_partition_flags;
     uint32_t return_partition_idx;
     uint32_t return_partition_flags;
 #if TFM_LVL != 1
@@ -193,26 +215,50 @@
     }
 
     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 (TFM_LVL != 1) && (TFM_LVL != 2)
     /* Deconfigure completed partition environment */
     tfm_spm_partition_sandbox_deconfig(current_partition_idx);
-    if (return_partition_flags&SPM_PART_FLAG_SECURE) {
-        /* Configure the caller partition environment in case this was a
-         * partition to partition call
+    if (tfm_secure_api_init) {
+        /* Restore privilege for thread mode during TF-M init. This is only
+         * have to be done if the partition is not trusted.
          */
-        tfm_spm_partition_sandbox_config(return_partition_idx);
-        /* Restore share status */
-        tfm_spm_partition_set_share(return_partition_idx,
-           tfm_spm_partition_get_runtime_data(return_partition_idx)->share);
+        if ((current_partition_flags & SPM_PART_FLAG_TRUSTED) == 0) {
+            CONTROL_Type ctrl;
+
+            ctrl.w = __get_CONTROL();
+            ctrl.b.nPRIV = 0;
+            __set_CONTROL(ctrl.w);
+            __DSB();
+            __ISB();
+        }
+    } 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_SECURE) {
+            /* 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_SECURE)) {
+    if (!(return_partition_flags&SPM_PART_FLAG_SECURE) ||
+        (tfm_secure_api_init)) {
         /* In TFM level 1 context restore is only done when
-         * returning to NS
+         * returning to NS or after initialization
          */
         /* Restore caller PSP and LR ptr */
         __set_PSP(curr_part_data->orig_psp);
@@ -237,6 +283,8 @@
 
     tfm_spm_partition_set_state(current_partition_idx,
                                 SPM_PARTITION_STATE_IDLE);
+    tfm_spm_partition_set_caller_partition_idx(current_partition_idx,
+                                SPM_INVALID_PARTITION_IDX);
     tfm_spm_partition_set_state(return_partition_idx,
                                 SPM_PARTITION_STATE_RUNNING);
 
@@ -254,7 +302,7 @@
 static int32_t tfm_check_sfn_req_integrity(struct tfm_sfn_req_s *desc_ptr)
 {
     if ((desc_ptr == NULL) ||
-        (desc_ptr->ss_id == 0) ||
+        (desc_ptr->sp_id == 0) ||
         (desc_ptr->sfn == NULL)) {
         /* invalid parameter */
         return TFM_ERROR_INVALID_PARAMETER;
@@ -403,13 +451,24 @@
 
 extern void return_from_sfn(void);
 
+void tfm_secure_api_init_done(void)
+{
+    tfm_secure_api_init = 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
+}
+
 static int32_t tfm_core_call_sfn(struct tfm_sfn_req_s *desc_ptr)
 {
 #if TFM_LVL == 1
-    if (desc_ptr->exc_num == EXC_NUM_THREAD_MODE) {
+    if ((desc_ptr->exc_num == EXC_NUM_THREAD_MODE) && (!tfm_secure_api_init)) {
         /* Secure partition to secure partition call in TFM level 1 */
         int32_t res;
-        uint32_t *args = desc_ptr->args;
+        int32_t *args = desc_ptr->args;
         int32_t retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
         /* return handler should restore original exc_return value... */
         res = tfm_pop_lock(NULL);
diff --git a/secure_fw/core/tfm_secure_api.h b/secure_fw/core/tfm_secure_api.h
index 5504e0b..02fda8d 100644
--- a/secure_fw/core/tfm_secure_api.h
+++ b/secure_fw/core/tfm_secure_api.h
@@ -43,10 +43,12 @@
 
 extern void tfm_secure_api_error_handler(void);
 
+typedef int32_t(*sfn_t)(int32_t, int32_t, int32_t, int32_t);
+
 struct tfm_sfn_req_s {
-    uint32_t ss_id;
-    int32_t (*sfn)(int32_t, int32_t, int32_t, int32_t);
-    uint32_t *args;
+    uint32_t sp_id;
+    sfn_t sfn;
+    int32_t *args;
     uint32_t exc_num;
     int32_t ns_caller : 1;
 };
@@ -91,10 +93,10 @@
 int32_t tfm_core_partition_request(uint32_t id, void *fn,
             int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
 {
-    uint32_t args[4] = {arg1, arg2, arg3, arg4};
+    int32_t args[4] = {arg1, arg2, arg3, arg4};
     struct tfm_sfn_req_s desc, *desc_ptr = &desc;
 
-    desc.ss_id = id;
+    desc.sp_id = id;
     desc.sfn = fn;
     desc.args = args;
     desc.ns_caller = cmse_nonsecure_caller();
diff --git a/secure_fw/core/tfm_unpriv_api.c b/secure_fw/core/tfm_unpriv_api.c
index 8c531ff..a3761de 100644
--- a/secure_fw/core/tfm_unpriv_api.c
+++ b/secure_fw/core/tfm_unpriv_api.c
@@ -5,11 +5,33 @@
  *
  */
 
+#include <arm_cmse.h>
+
 #include "tfm_svc.h"
 #include "tfm_secure_api.h"
+#include "tfm_internal.h"
 
 uint8_t *tfm_scratch_area;
 int32_t tfm_scratch_area_size;
+nsfptr_t ns_entry;
+
+void jump_to_ns_code(void)
+{
+#if TFM_LVL != 1
+    /* Initialization is done, set thread mode to unprivileged. */
+    CONTROL_Type ctrl;
+
+    ctrl.w = __get_CONTROL();
+    ctrl.b.nPRIV = 1;
+    __set_CONTROL(ctrl.w);
+#endif
+    /* All changes made to memory will be effective after this point */
+    __DSB();
+    __ISB();
+
+    /* Calls the non-secure Reset_Handler to jump to the non-secure binary */
+    ns_entry();
+}
 
 __attribute__((naked)) void tfm_core_partition_return_svc(void)
 {
diff --git a/secure_fw/ns_callable/tfm_sst_veneers.c b/secure_fw/ns_callable/tfm_sst_veneers.c
index d95bc0b..76fa9a7 100644
--- a/secure_fw/ns_callable/tfm_sst_veneers.c
+++ b/secure_fw/ns_callable/tfm_sst_veneers.c
@@ -9,7 +9,7 @@
 #include "secure_fw/services/secure_storage/sst_asset_management.h"
 #include "tfm_secure_api.h"
 #include "tfm_api.h"
-#include "secure_fw/spm/spm_api.h"
+#include "secure_fw/spm/spm_partition_defs.h"
 
 __tfm_secure_gateway_attributes__
 enum tfm_sst_err_t tfm_sst_veneer_get_handle(uint32_t app_id,
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index 40d054d..e83c62e 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -11,6 +11,7 @@
 #include <string.h>
 #include "spm_api.h"
 #include "spm_db.h"
+#include "tfm_internal.h"
 #include "tfm_api.h"
 #include "mpu_armv8m_drv.h"
 #include "region_defs.h"
@@ -89,6 +90,10 @@
      */
 
     /* For the non secure Execution environment */
+#if TFM_LVL != 1
+    extern uint32_t Stack_Mem[];
+    extern uint32_t Stack_top[];
+#endif
     if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
         return SPM_ERR_INVALID_CONFIG;
     }
@@ -96,6 +101,16 @@
             g_spm_partition_db.partition_count]);
     part_ptr->static_data.partition_id = TFM_SP_NON_SECURE_ID;
     part_ptr->static_data.partition_flags = 0;
+
+#if TFM_LVL != 1
+    part_ptr->static_data.stack_bottom = (uint32_t)Stack_Mem;
+    part_ptr->static_data.stack_top = (uint32_t)Stack_top;
+    /* Since RW, ZI and stack are configured as one MPU region, configure
+     * RW start address to Stack_Mem to get RW access to stack
+     */
+    part_ptr->static_data.rw_start = (uint32_t)Stack_Mem;
+#endif
+
     part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
     ++g_spm_partition_db.partition_count;
 
@@ -140,7 +155,9 @@
     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
 
     /* TFM Core unprivileged code region */
     region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_CODE;
@@ -151,7 +168,9 @@
     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
 
     /* TFM Core unprivileged data region */
     region_cfg.region_nr = MPU_REGION_TFM_UNPRIV_DATA;
@@ -162,7 +181,9 @@
     region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
 
     /* TFM Core unprivileged non-secure data region */
     region_cfg.region_nr = MPU_REGION_NS_DATA;
@@ -171,7 +192,9 @@
     region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
 
     mpu_armv8m_enable(&dev_mpu_s, 1, 1);
 
@@ -234,14 +257,12 @@
 enum spm_err_t tfm_spm_partition_init(void)
 {
     struct spm_partition_desc_t *part;
+    struct tfm_sfn_req_s desc, *desc_ptr = &desc;
+    int32_t args[4] = {0};
     int32_t fail_cnt = 0;
     uint32_t idx;
 
     /* Call the init function for each partition */
-    /* FixMe: This implementation only fits level 1 isolation.
-     * On higher levels MPU (and PPC) configuration need to be in place to have
-     * proper isolation during init.
-     */
     for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
         part = &g_spm_partition_db.partitions[idx];
         if (part->static_data.periph_start) {
@@ -250,8 +271,22 @@
         }
         if (part->static_data.partition_init == NULL) {
             tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
+            tfm_spm_partition_set_caller_partition_idx(idx,
+                                                     SPM_INVALID_PARTITION_IDX);
         } else {
-            int32_t ret = part->static_data.partition_init();
+            int32_t ret;
+
+            desc.args = args;
+            desc.exc_num = EXC_NUM_THREAD_MODE;
+            desc.ns_caller = 0;
+            desc.sfn = (sfn_t)part->static_data.partition_init;
+            desc.sp_id = part->static_data.partition_id;
+            __ASM("MOV r0, %1\n"
+                  "SVC %2\n"
+                  "MOV %0, r0\n"
+                  : "=r" (ret)
+                  : "r" (desc_ptr), "I" (TFM_SVC_SFN_REQUEST)
+                  : "r0");
 
             if (ret == TFM_SUCCESS) {
                 tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
@@ -262,6 +297,8 @@
         }
     }
 
+    tfm_secure_api_init_done();
+
     if (fail_cnt == 0) {
         return SPM_ERR_OK;
     } else {
@@ -290,15 +327,20 @@
 
     /* Configure Regions */
 
-    /* RO region*/
-    region_cfg.region_nr = PARTITION_REGION_RO;
-    region_cfg.region_base = part->static_data.ro_start;
-    region_cfg.region_limit = part->static_data.ro_limit;
-    region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
-    region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
-    region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
+    if (part->static_data.ro_start) {
+        /* RO region*/
+        region_cfg.region_nr = PARTITION_REGION_RO;
+        region_cfg.region_base = part->static_data.ro_start;
+        region_cfg.region_limit = part->static_data.ro_limit;
+        region_cfg.attr_access = MPU_ARMV8M_AP_RO_PRIV_UNPRIV;
+        region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
+        region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_OK;
 
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg)
+            != MPU_ARMV8M_OK) {
+            return SPM_ERR_INVALID_CONFIG;
+        }
+    }
 
     /* RW, ZI and stack as one region*/
     region_cfg.region_nr = PARTITION_REGION_RW_STACK;
@@ -308,7 +350,9 @@
     region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
     region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
 
-    mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+    if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg) != MPU_ARMV8M_OK) {
+        return SPM_ERR_INVALID_CONFIG;
+    }
 
     if (part->static_data.periph_start) {
         /* Peripheral */
@@ -318,7 +362,10 @@
         region_cfg.attr_access = MPU_ARMV8M_AP_RW_PRIV_UNPRIV;
         region_cfg.attr_sh = MPU_ARMV8M_SH_NONE;
         region_cfg.attr_exec = MPU_ARMV8M_XN_EXEC_NEVER;
-        mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg);
+        if (mpu_armv8m_region_enable(&dev_mpu_s, &region_cfg)
+            != MPU_ARMV8M_OK) {
+            return SPM_ERR_INVALID_CONFIG;
+        }
 
         ppc_en_secure_unpriv(part->static_data.periph_ppc_bank,
                              part->static_data.periph_ppc_loc);
@@ -326,21 +373,6 @@
 
     mpu_armv8m_enable(&dev_mpu_s, 1, 1);
 
-#ifndef UNPRIV_JUMP_TO_NS
-    /* FixMe: if jump_to_ns_code() from unprivileged is solved,
-     * this code can be removed
-     */
-    /* Initialization is done, set thread mode to unprivileged.
-     */
-    CONTROL_Type ctrl;
-
-    ctrl.w = __get_CONTROL();
-    ctrl.b.nPRIV = 1;
-    __set_CONTROL(ctrl.w);
-    __DSB();
-    __ISB();
-#endif
-
     return SPM_ERR_OK;
 }
 
@@ -350,19 +382,6 @@
      * SPM partition for that partition
      */
 
-#ifndef UNPRIV_JUMP_TO_NS
-    /* FixMe: if jump_to_ns_code() from unprivileged is solved,
-     * this code can be removed
-     */
-    CONTROL_Type ctrl;
-
-    ctrl.w = __get_CONTROL();
-    ctrl.b.nPRIV = 0;
-    __set_CONTROL(ctrl.w);
-    __DSB();
-    __ISB();
-#endif
-
     struct spm_partition_desc_t *part;
 
     part = &g_spm_partition_db.partitions[partition_idx];
@@ -428,8 +447,8 @@
     }
 }
 
-void tfm_spm_partition_set_caller_partition_id(uint32_t partition_idx,
-                                               uint32_t caller_partition_idx)
+void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
+                                                uint32_t caller_partition_idx)
 {
     g_spm_partition_db.partitions[partition_idx].runtime_data.
             caller_partition_idx = caller_partition_idx;
diff --git a/secure_fw/spm/spm_api.h b/secure_fw/spm/spm_api.h
index c36288f..5e15044 100644
--- a/secure_fw/spm/spm_api.h
+++ b/secure_fw/spm/spm_api.h
@@ -170,15 +170,15 @@
 void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
 
 /**
- * \brief Set the caller partition Id for a given partition
+ * \brief Set the caller partition index for a given partition
  *
  * \param[in] partition_idx        Partition index
- * \param[in] caller_partition_id  The Id of the caller partition
+ * \param[in] caller_partition_idx The index of the caller partition
  *
- * \note This function doesn't check if any of the partition_ids is valid.
+ * \note This function doesn't check if any of the partition_idxs are valid.
  */
-void tfm_spm_partition_set_caller_partition_id(uint32_t partition_idx,
-                                           uint32_t caller_partition_id);
+void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
+                                                uint32_t caller_partition_idx);
 
 /**
  * \brief Set the original PSP value of a partition