blob: 2aeb90349556579c55f24e4e796bdd80b028eca8 [file] [log] [blame]
/*
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/* This file contains the APIs exported by the SPM to tfm core */
#include <stdio.h>
#include <string.h>
#include "spm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "secure_utilities.h"
#include "spm_db_setup.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "tfm_nspm.h"
#include "secure_fw/core/tfm_core.h"
#include "platform_retarget.h"
#include "tfm_peripherals_def.h"
#include "spm_partition_defs.h"
struct spm_partition_db_t g_spm_partition_db = {0,};
typedef enum {
TFM_INIT_FAILURE,
} sp_error_type_t;
/*
* This function is called when a secure partition causes an error.
* In case of an error in the error handling, a non-zero value have to be
* returned.
*/
static void tfm_spm_partition_err_handler(
struct spm_partition_desc_t *partition,
sp_error_type_t err_type,
int32_t err_code)
{
#ifdef TFM_CORE_DEBUG
if (err_type == TFM_INIT_FAILURE) {
printf("Partition init failed for partition id 0x%08X\r\n",
partition->static_data.partition_id);
} else {
printf("Unknown partition error %d for partition id 0x%08X\r\n",
err_type, partition->static_data.partition_id);
}
#endif
tfm_spm_partition_set_state(partition->static_data.partition_id,
SPM_PARTITION_STATE_CLOSED);
}
uint32_t get_partition_idx(uint32_t partition_id)
{
int i;
if (partition_id == INVALID_PARTITION_ID) {
return SPM_INVALID_PARTITION_IDX;
}
for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
if (g_spm_partition_db.partitions[i].static_data.partition_id ==
partition_id) {
return i;
}
}
return SPM_INVALID_PARTITION_IDX;
}
enum spm_err_t tfm_spm_db_init(void)
{
struct spm_partition_desc_t *part_ptr;
tfm_memset (&g_spm_partition_db, 0, sizeof(g_spm_partition_db));
/* This function initialises partition db */
g_spm_partition_db.running_partition_idx = SPM_INVALID_PARTITION_IDX;
g_spm_partition_db.partition_count = 0;
/* There are a few partitions that are used by TF-M internally.
* These are explicitly added to the partition db here.
*/
/* For the non secure Execution environment */
#if TFM_LVL != 1
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[];
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
uint32_t psp_stack_top = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Limit;
#endif
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
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->memory_data.stack_bottom = psp_stack_bottom;
part_ptr->memory_data.stack_top = psp_stack_top;
/* Since RW, ZI and stack are configured as one MPU region, configure
* RW start address to psp_stack_bottom to get RW access to stack
*/
part_ptr->memory_data.rw_start = psp_stack_bottom;
#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 */
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
g_spm_partition_db.partition_count]);
part_ptr->static_data.partition_id = TFM_SP_CORE_ID;
part_ptr->static_data.partition_flags =
SPM_PART_FLAG_SECURE | SPM_PART_FLAG_TRUSTED;
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
++g_spm_partition_db.partition_count;
/* Add user-defined secure partitions */
#include "secure_fw/services/tfm_partition_list.inc"
g_spm_partition_db.is_init = 1;
return SPM_ERR_OK;
}
enum spm_err_t tfm_spm_partition_init(void)
{
struct spm_partition_desc_t *part;
struct tfm_sfn_req_s desc;
int32_t args[4] = {0};
int32_t fail_cnt = 0;
uint32_t idx;
/* Call the init function for each partition */
for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
part = &g_spm_partition_db.partitions[idx];
tfm_spm_hal_configure_default_isolation(part->platform_data);
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 res;
desc.args = args;
desc.ns_caller = 0;
desc.sfn = (sfn_t)part->static_data.partition_init;
desc.sp_id = part->static_data.partition_id;
res = tfm_core_sfn_request(&desc);
if (res == TFM_SUCCESS) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
} else {
tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, res);
fail_cnt++;
}
}
}
tfm_secure_api_init_done();
if (fail_cnt == 0) {
return SPM_ERR_OK;
} else {
return SPM_ERR_PARTITION_NOT_AVAILABLE;
}
}
#if TFM_LVL != 1
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx)
{
struct spm_partition_desc_t *part;
if (!g_spm_partition_db.is_init) {
return SPM_ERR_PARTITION_DB_NOT_INIT;
}
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_config(&(part->memory_data),
part->platform_data);
}
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx)
{
/* This function takes a partition id and disables the
* SPM partition for that partition
*/
struct spm_partition_desc_t *part;
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_deconfig(&(part->memory_data),
part->platform_data);
}
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.stack_bottom;
}
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].memory_data.stack_top;
}
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_start;
}
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_limit;
}
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_start;
}
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_limit;
}
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
}
#endif
void tfm_spm_partition_store_context(uint32_t partition_idx,
uint32_t stack_ptr, uint32_t lr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
g_spm_partition_db.partitions[partition_idx].
runtime_data.lr = lr;
}
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_id;
}
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_flags;
}
const struct spm_partition_runtime_data_t *
tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
{
return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
}
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
state;
if (state == SPM_PARTITION_STATE_RUNNING) {
g_spm_partition_db.running_partition_idx = 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;
}
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.
caller_client_id = caller_client_id;
}
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
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_hal_set_share_region(share);
#endif
if (ret == SPM_ERR_OK) {
g_spm_partition_db.partitions[partition_idx].runtime_data.share = share;
}
return ret;
}
uint32_t tfm_spm_partition_get_running_partition_idx(void)
{
return g_spm_partition_db.running_partition_idx;
}
void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
{
struct spm_partition_desc_t *partition =
&(g_spm_partition_db.partitions[partition_idx]);
partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
partition->runtime_data.share = 0;
}