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/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)®ION_NAME(Image$$, service, $$Base); \
*db_ptr++ = (uint32_t)®ION_NAME(Image$$, service, $$Limit); \
*db_ptr++ = (uint32_t)®ION_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