Core: implement TZ context handling if used by NS RTOS

Change-Id: Iaecd473d90d4b51b0174aa5d7695d59fa13fec51
Signed-off-by: Miklos Balint <miklos.balint@arm.com>
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 285c0df..86641ac 100755
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -41,7 +41,6 @@
 set(NS_APP_SRC "${CMSIS_5_DIR}/CMSIS/RTOS2/RTX/Config/RTX_Config.c"
 	"${CMSIS_5_DIR}/CMSIS/RTOS2/RTX/Source/rtx_lib.c"
 	"${APP_DIR}/main_ns.c"
-	"${APP_DIR}/ext/tz_context.c"
 	"${APP_DIR}/tfm_integ_test.c"
 	"${APP_DIR}/os_wrapper_rtx.c"
 	"${INTERFACE_DIR}/src/tfm_sst_api.c"
diff --git a/app/ext/tz_context.c b/app/ext/tz_context.c
deleted file mode 100644
index 26e8081..0000000
--- a/app/ext/tz_context.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2015-2016 ARM Limited. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed under the Apache License, Version 2.0 (the License); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * ----------------------------------------------------------------------------
- *
- * $Date:        15. October 2016
- * $Revision:    1.1.0
- *
- * Project:      TrustZone for ARMv8-M
- * Title:        Context Management for ARMv8-M TrustZone - Stub implementation,
- *               TFM will take charge of the stack memory management in S mode
- *
- *---------------------------------------------------------------------------*/
-
-#include "tz_context.h"
-
-
-/// Initialize secure context memory system
-/// \return execution status (1: success, 0: error)
-uint32_t TZ_InitContextSystem_S (void) {
-  return 1U;    // Success
-}
-
-
-/// Allocate context memory for calling secure software modules in TrustZone
-/// \param[in]  module   identifies software modules called from non-secure mode
-/// \return value != 0 id TrustZone memory slot identifier
-/// \return value 0    no memory available or internal error
-TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module) {
-  uint32_t slot = 0;
-  return (slot + 1U);
-}
-
-
-/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
-/// \param[in]  id  TrustZone memory slot identifier
-/// \return execution status (1: success, 0: error)
-uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id) {
-  return 1U;    // Success
-}
-
-
-/// Load secure context (called on RTOS thread context switch)
-/// \param[in]  id  TrustZone memory slot identifier
-/// \return execution status (1: success, 0: error)
-uint32_t TZ_LoadContext_S (TZ_MemoryId_t id) {
-  return 1U;    // Success
-}
-
-
-/// Store secure context (called on RTOS thread context switch)
-/// \param[in]  id  TrustZone memory slot identifier
-/// \return execution status (1: success, 0: error)
-uint32_t TZ_StoreContext_S (TZ_MemoryId_t id) {
-  return 1U;    // Success
-}
diff --git a/platform/ext/target/mps2/an519/partition/region_defs.h b/platform/ext/target/mps2/an519/partition/region_defs.h
index 6e111f4..0dfd62a 100644
--- a/platform/ext/target/mps2/an519/partition/region_defs.h
+++ b/platform/ext/target/mps2/an519/partition/region_defs.h
@@ -67,7 +67,7 @@
 #define IMAGE_CODE_SIZE \
             (FLASH_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
 
-#define CMSE_VENEER_REGION_SIZE     (0x000000C0)
+#define CMSE_VENEER_REGION_SIZE     (0x000000E0)
 
 /* Use SRAM1 memory to store Code data */
 #define S_ROM_ALIAS_BASE  (0x10000000)
diff --git a/platform/ext/target/mps2/an521/partition/region_defs.h b/platform/ext/target/mps2/an521/partition/region_defs.h
index 768ac92..82d96b6 100644
--- a/platform/ext/target/mps2/an521/partition/region_defs.h
+++ b/platform/ext/target/mps2/an521/partition/region_defs.h
@@ -67,7 +67,7 @@
 #define IMAGE_CODE_SIZE \
             (FLASH_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
 
-#define CMSE_VENEER_REGION_SIZE     (0x000000C0)
+#define CMSE_VENEER_REGION_SIZE     (0x000000E0)
 
 /* Use SRAM1 memory to store Code data */
 #define S_ROM_ALIAS_BASE  (0x10000000)
diff --git a/platform/ext/target/musca_a/partition/region_defs.h b/platform/ext/target/musca_a/partition/region_defs.h
index c44b3ee..203ef74 100755
--- a/platform/ext/target/musca_a/partition/region_defs.h
+++ b/platform/ext/target/musca_a/partition/region_defs.h
@@ -51,7 +51,7 @@
 #define IMAGE_CODE_SIZE \
             (FLASH_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE)
 
-#define CMSE_VENEER_REGION_SIZE     (0x000000C0)
+#define CMSE_VENEER_REGION_SIZE     (0x000000E0)
 
 /*
  * Since we enable/disable flash during s/ns code copy to code sram we cannot
diff --git a/secure_fw/core/CMakeLists.inc b/secure_fw/core/CMakeLists.inc
index 91ba969..f625cd0 100644
--- a/secure_fw/core/CMakeLists.inc
+++ b/secure_fw/core/CMakeLists.inc
@@ -34,6 +34,7 @@
 		"${SS_CORE_DIR}/tfm_handler.c"
 		"${SS_CORE_DIR}/tfm_secure_api.c"
 		"${SS_CORE_DIR}/tfm_unpriv_api.c"
+		"${SS_CORE_DIR}/tfm_nspm.c"
 	)
 
 #Append all our source files to global lists.
diff --git a/secure_fw/core/tfm_nspm.c b/secure_fw/core/tfm_nspm.c
new file mode 100644
index 0000000..76ba608
--- /dev/null
+++ b/secure_fw/core/tfm_nspm.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include "secure_utilities.h"
+
+#ifndef TFM_MAX_NS_THREAD_COUNT
+#define TFM_MAX_NS_THREAD_COUNT 8
+#endif
+#define INVALID_CLIENT_ID 0
+
+typedef uint32_t TZ_ModuleId_t;
+typedef uint32_t TZ_MemoryId_t;
+
+static struct ns_client_list_t {
+    int32_t ns_client_id;
+    int32_t next_free_index;
+} NsClientIdList[TFM_MAX_NS_THREAD_COUNT];
+
+static int32_t next_ns_client_id = -1;
+static int32_t free_index = 0U;
+static int32_t active_ns_client = INVALID_CLIENT_ID;
+
+void tfm_nspm_configure_clients(void)
+{
+    int32_t i;
+
+    /* Default to one NS client */
+    free_index = 1;
+    NsClientIdList[0].ns_client_id = next_ns_client_id--;
+    for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
+        NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
+    }
+}
+
+/* TF-M implementation of the CMSIS TZ RTOS thread context management API */
+
+/// Initialize secure context memory system
+/// \return execution status (1: success, 0: error)
+/* This veneer is TF-M internal, not a secure service */
+__attribute__((cmse_nonsecure_entry))
+uint32_t TZ_InitContextSystem_S(void)
+{
+    int32_t i;
+
+    if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
+        /* This veneer should only be called by NS RTOS in handler mode */
+        return 0U;
+    }
+
+    /* NS RTOS supports TZ context management, override defaults */
+    LOG_MSG("NS RTOS initialized TZ RTOS context management");
+    for (i = 0; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
+        NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
+        NsClientIdList[i].next_free_index = i + 1;
+    }
+
+    /* Terminate list */
+    NsClientIdList[i - 1].next_free_index = -1;
+    free_index = 0;
+    /* Success */
+    return 1U;
+}
+
+
+/// Allocate context memory for calling secure software modules in TrustZone
+/// \param[in]  module   identifies software modules called from non-secure mode
+/// \return value != 0 id TrustZone memory slot identifier
+/// \return value 0    no memory available or internal error
+/* This veneer is TF-M internal, not a secure service */
+__attribute__((cmse_nonsecure_entry))
+TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module)
+{
+    TZ_MemoryId_t tz_id;
+    (void) module; /* Currently unused */
+
+    if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
+        /* This veneer should only be called by NS RTOS in handler mode */
+        return 0U;
+    }
+
+    if (free_index < 0) {
+        /* No more free slots */
+        return 0U;
+    }
+
+    /* TZ_MemoryId_t must be a positive integer */
+    tz_id = free_index + 1;
+    NsClientIdList[free_index].ns_client_id = next_ns_client_id--;
+    printf("TZ_AllocModuleContext_S called, returning id %d\r\n",
+        NsClientIdList[free_index].ns_client_id);
+    free_index = NsClientIdList[free_index].next_free_index;
+
+    return tz_id;
+}
+
+
+/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
+/// \param[in]  id  TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+/* This veneer is TF-M internal, not a secure service */
+__attribute__((cmse_nonsecure_entry))
+uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id)
+{
+    uint32_t index;
+
+    if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
+        /* This veneer should only be called by NS RTOS in handler mode */
+        return 0U;
+    }
+
+    if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
+        /* Invalid TZ_MemoryId_t */
+        return 0U;
+    }
+
+    index = id - 1;
+
+    if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
+        /* Non-existent client */
+        return 0U;
+    }
+
+    printf("TZ_FreeModuleContext_S called for id %d\r\n",
+        NsClientIdList[index].ns_client_id);
+    if (active_ns_client == NsClientIdList[index].ns_client_id) {
+        printf("Freeing active NS client, NS inactive\r\n");
+        active_ns_client = INVALID_CLIENT_ID;
+    }
+    NsClientIdList[index].ns_client_id = INVALID_CLIENT_ID;
+    NsClientIdList[index].next_free_index = free_index;
+
+    free_index = index;
+
+    return 1U;    // Success
+}
+
+
+/// Load secure context (called on RTOS thread context switch)
+/// \param[in]  id  TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+/* This veneer is TF-M internal, not a secure service */
+__attribute__((cmse_nonsecure_entry))
+uint32_t TZ_LoadContext_S (TZ_MemoryId_t id)
+{
+    uint32_t index;
+
+    if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
+        /* This veneer should only be called by NS RTOS in handler mode */
+        return 0U;
+    }
+
+    LOG_MSG("TZ_LoadContext_S called");
+    if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
+        /* Invalid TZ_MemoryId_t */
+        return 0U;
+    }
+
+    index = id - 1;
+
+    if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
+        /* Non-existent client */
+        return 0U;
+    }
+
+    active_ns_client = NsClientIdList[index].ns_client_id;
+    printf("TZ_LoadContext_S called for id %d\r\n",
+        NsClientIdList[index].ns_client_id);
+
+    return 1U;    // Success
+}
+
+
+/// Store secure context (called on RTOS thread context switch)
+/// \param[in]  id  TrustZone memory slot identifier
+/// \return execution status (1: success, 0: error)
+/* This veneer is TF-M internal, not a secure service */
+__attribute__((cmse_nonsecure_entry))
+uint32_t TZ_StoreContext_S (TZ_MemoryId_t id)
+{
+    uint32_t index;
+
+    if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
+        /* This veneer should only be called by NS RTOS in handler mode */
+        return 0U;
+    }
+
+    LOG_MSG("TZ_StoreContext_S called");
+    /* id corresponds to context being swapped out on NS side */
+    if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
+        /* Invalid TZ_MemoryId_t */
+        return 0U;
+    }
+
+    index = id - 1;
+
+    if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
+        /* Non-existent client */
+        return 0U;
+    }
+
+    if (active_ns_client != NsClientIdList[index].ns_client_id) {
+        printf("TZ_StoreContext_S called for id %d, active id: %d\r\n",
+            NsClientIdList[index].ns_client_id, active_ns_client);
+        return 0U;
+    }
+
+    printf("TZ_StoreContext_S called for id %d\r\n",
+        NsClientIdList[index].ns_client_id);
+    active_ns_client = INVALID_CLIENT_ID;
+
+    return 1U;    // Success
+}
diff --git a/secure_fw/spm/spm_api.c b/secure_fw/spm/spm_api.c
index ee08e8c..7b96b11 100644
--- a/secure_fw/spm/spm_api.c
+++ b/secure_fw/spm/spm_api.c
@@ -66,6 +66,9 @@
     return SPM_INVALID_PARTITION_IDX;
 }
 
+/* FixMe: this should be in a header */
+extern void tfm_nspm_configure_clients(void);
+
 enum spm_err_t tfm_spm_db_init(void)
 {
     struct spm_partition_desc_t *part_ptr;
@@ -103,6 +106,7 @@
 #endif
 
     part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
+    tfm_nspm_configure_clients();
     ++g_spm_partition_db.partition_count;
 
     /* For the TF-M core environment itself */