mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #9653 from kfnta/tfm_src_integ
TF-M sources integration to Mbed-OSpull/9774/head
commit
4c04771c5d
|
|
@ -22,4 +22,5 @@ TESTS/mbed_hal/trng/pithy
|
|||
targets
|
||||
components/802.15.4_RF
|
||||
components/wifi
|
||||
components/TARGET_PSA/TARGET_TFM
|
||||
tools
|
||||
|
|
|
|||
|
|
@ -323,6 +323,8 @@ matrix:
|
|||
- env:
|
||||
- NAME=psa-autogen
|
||||
script:
|
||||
# Run SPM code generator and check that changes are not needed
|
||||
- python tools/spm/generate_partition_code.py
|
||||
# Run SPM code generators and check that changes are not needed
|
||||
- python tools/psa/generate_mbed_spm_partition_code.py
|
||||
- git diff --exit-code
|
||||
- python tools/psa/generate_tfm_partition_code.py
|
||||
- git diff --exit-code
|
||||
|
|
|
|||
1
LICENSE
1
LICENSE
|
|
@ -5,6 +5,7 @@ Folders containing files under different permissive license than Apache 2.0 are
|
|||
|
||||
- [cmsis](./cmsis) - MIT, BSD-3-Clause
|
||||
- [components/802.15.4_RF/mcr20a-rf-driver](./components/802.15.4_RF/mcr20a-rf-driver) - BSD-3-Clause
|
||||
- [components/TARGET_PSA/TARGET_TFM](./components/TARGET_PSA/TARGET_TFM) - BSD-3-Clause
|
||||
- [features/cryptocell/FEATURE_CRYPTOCELL310](./features/cryptocell/FEATURE_CRYPTOCELL310) - ARM Object Code and Header Files License
|
||||
- [features/FEATURE_BOOTLOADER](./features/FEATURE_BOOTLOADER) - PBL
|
||||
- [features/FEATURE_BLE/targets](./features/FEATURE_BLE/targets) - BSD-style, PBL, MIT-style
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
|
||||
#endif // COMPONENT_PSA_SRV_IPC
|
||||
|
||||
#ifndef TARGET_MBED_SPM
|
||||
#error [NOT_SUPPORTED] SPM tests currently only run on MBED_SPM targets
|
||||
#endif // TARGET_MBED_SPM
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
|
||||
#endif // COMPONENT_PSA_SRV_IPC
|
||||
|
||||
#ifndef TARGET_MBED_SPM
|
||||
#error [NOT_SUPPORTED] SPM tests currently only run on MBED_SPM targets
|
||||
#endif // TARGET_MBED_SPM
|
||||
|
||||
#include "mbed.h"
|
||||
#include "greentea-client/test_env.h"
|
||||
#include "unity.h"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@
|
|||
#ifndef COMPONENT_PSA_SRV_IPC
|
||||
#error [NOT_SUPPORTED] SPM tests can run only on SPM-enabled targets
|
||||
#endif // COMPONENT_PSA_SRV_IPC
|
||||
|
||||
#ifndef TARGET_MBED_SPM
|
||||
#error [NOT_SUPPORTED] SPM tests currently only run on MBED_SPM targets
|
||||
#endif // TARGET_MBED_SPM
|
||||
|
||||
/* -------------------------------------- Includes ----------------------------------- */
|
||||
|
||||
#include "greentea-client/test_env.h"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "rtx_os.h"
|
||||
#include "cmsis_os2.h"
|
||||
|
||||
#include "tfm_api.h"
|
||||
#include "tfm_ns_lock.h"
|
||||
|
||||
/**
|
||||
* \brief struct ns_lock_state type
|
||||
*/
|
||||
struct ns_lock_state
|
||||
{
|
||||
bool init;
|
||||
osMutexId_t id;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ns_lock status
|
||||
*/
|
||||
static struct ns_lock_state ns_lock = {.init=false, .id=NULL};
|
||||
|
||||
/**
|
||||
* \brief Mutex properties, NS lock
|
||||
*/
|
||||
|
||||
static osRtxMutex_t ns_lock_cb = { 0 };
|
||||
|
||||
static const osMutexAttr_t ns_lock_attrib = {
|
||||
.name = "ns_lock",
|
||||
.attr_bits = osMutexPrioInherit,
|
||||
.cb_mem = &ns_lock_cb,
|
||||
.cb_size = sizeof(ns_lock_cb)
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief NS world, NS lock based dispatcher
|
||||
*/
|
||||
uint32_t tfm_ns_lock_dispatch(veneer_fn fn,
|
||||
uint32_t arg0, uint32_t arg1,
|
||||
uint32_t arg2, uint32_t arg3)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
/* Check the NS lock has been initialized */
|
||||
if (ns_lock.init == false) {
|
||||
return TFM_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
/* TFM request protected by NS lock */
|
||||
osMutexAcquire(ns_lock.id,osWaitForever);
|
||||
|
||||
result = fn(arg0, arg1, arg2, arg3);
|
||||
|
||||
osMutexRelease(ns_lock.id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief NS world, Init NS lock
|
||||
*/
|
||||
uint32_t tfm_ns_lock_init()
|
||||
{
|
||||
if (ns_lock.init == false) {
|
||||
ns_lock.id = osMutexNew(&ns_lock_attrib);
|
||||
ns_lock.init = true;
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
else {
|
||||
return TFM_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
bool tfm_ns_lock_get_init_state()
|
||||
{
|
||||
return ns_lock.init;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include "interface/include/psa_client.h"
|
||||
#include "tfm_ns_lock.h"
|
||||
#include "tfm_api.h"
|
||||
|
||||
/**** API functions ****/
|
||||
|
||||
uint32_t psa_framework_version(void)
|
||||
{
|
||||
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_framework_version_veneer,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
uint32_t psa_version(uint32_t sid)
|
||||
{
|
||||
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer,
|
||||
sid,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
|
||||
{
|
||||
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer,
|
||||
sid,
|
||||
minor_version,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
psa_status_t psa_call(psa_handle_t handle,
|
||||
const psa_invec *in_vec,
|
||||
size_t in_len,
|
||||
psa_outvec *out_vec,
|
||||
size_t out_len)
|
||||
{
|
||||
/* FixMe: sanity check can be added to offload some NS thread checks from
|
||||
* TFM secure API
|
||||
*/
|
||||
|
||||
/* Due to v8M restrictions, TF-M NS API needs to add another layer of
|
||||
* serialization in order for NS to pass arguments to S
|
||||
*/
|
||||
psa_invec in_vecs, out_vecs;
|
||||
|
||||
in_vecs.base = in_vec;
|
||||
in_vecs.len = in_len;
|
||||
out_vecs.base = out_vec;
|
||||
out_vecs.len = out_len;
|
||||
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer,
|
||||
(uint32_t)handle,
|
||||
(uint32_t)&in_vecs,
|
||||
(uint32_t)&out_vecs,
|
||||
0);
|
||||
}
|
||||
|
||||
void psa_close(psa_handle_t handle)
|
||||
{
|
||||
tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer,
|
||||
(uint32_t)handle,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2017-2019 ARM Limited
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
|
||||
|
||||
#ifndef __TFM_PARTITION_DEFS_INC__
|
||||
#define __TFM_PARTITION_DEFS_INC__
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
#define ITS_ID (TFM_SP_BASE + 0)
|
||||
#endif
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
#define PLATFORM_ID (TFM_SP_BASE + 1)
|
||||
#endif
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
#define CRYPTO_SRV_ID (TFM_SP_BASE + 2)
|
||||
#endif
|
||||
|
||||
#define TFM_MAX_USER_PARTITIONS (3)
|
||||
|
||||
#endif /* __TFM_PARTITION_DEFS_INC__ */
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
|
||||
|
||||
#ifndef __TFM_PARTITION_LIST_INC__
|
||||
#define __TFM_PARTITION_LIST_INC__
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** ITS ********/
|
||||
PARTITION_DECLARE(ITS, 0
|
||||
| SPM_PART_FLAG_IPC
|
||||
, "APPLICATION-ROT", 10, NORMAL, 2048);
|
||||
PARTITION_ADD_INIT_FUNC(ITS, its_entry);
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** PLATFORM ********/
|
||||
PARTITION_DECLARE(PLATFORM, 0
|
||||
| SPM_PART_FLAG_IPC
|
||||
, "APPLICATION-ROT", 8, NORMAL, 1024);
|
||||
PARTITION_ADD_INIT_FUNC(PLATFORM, platform_partition_entry);
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** CRYPTO_SRV ********/
|
||||
PARTITION_DECLARE(CRYPTO_SRV, 0
|
||||
| SPM_PART_FLAG_IPC
|
||||
, "APPLICATION-ROT", 35, NORMAL, 16384);
|
||||
PARTITION_ADD_INIT_FUNC(CRYPTO_SRV, crypto_main);
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#endif /* __TFM_PARTITION_LIST_INC__ */
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
/*********** WARNING: This is an auto-generated file. Do not edit! ***********/
|
||||
|
||||
#ifndef __TFM_SERVICE_LIST_INC__
|
||||
#define __TFM_SERVICE_LIST_INC__
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** ITS ********/
|
||||
{"PSA_ITS_GET", ITS_ID, PSA_ITS_GET_MSK, 0x00011A00, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_ITS_SET", ITS_ID, PSA_ITS_SET_MSK, 0x00011A01, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_ITS_INFO", ITS_ID, PSA_ITS_INFO_MSK, 0x00011A02, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_ITS_REMOVE", ITS_ID, PSA_ITS_REMOVE_MSK, 0x00011A03, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_ITS_RESET", ITS_ID, PSA_ITS_RESET_MSK, 0x00011A04, false, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** PLATFORM ********/
|
||||
{"PSA_PLATFORM_LC_GET", PLATFORM_ID, PSA_PLATFORM_LC_GET_MSK, 0x00011000, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_PLATFORM_LC_SET", PLATFORM_ID, PSA_PLATFORM_LC_SET_MSK, 0x00011001, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
{"PSA_PLATFORM_SYSTEM_RESET", PLATFORM_ID, PSA_PLATFORM_SYSTEM_RESET_MSK, 0x00011002, true, 1, TFM_VERSION_POLICY_RELAXED},
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
/******** CRYPTO_SRV ********/
|
||||
{"PSA_CRYPTO_INIT_ID", CRYPTO_SRV_ID, PSA_CRYPTO_INIT, 0x00000F00, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_MAC_ID", CRYPTO_SRV_ID, PSA_MAC, 0x00000F01, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_HASH_ID", CRYPTO_SRV_ID, PSA_HASH, 0x00000F02, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_ASYMMETRIC_ID", CRYPTO_SRV_ID, PSA_ASYMMETRIC, 0x00000F03, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_SYMMETRIC_ID", CRYPTO_SRV_ID, PSA_SYMMETRIC, 0x00000F04, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_AEAD_ID", CRYPTO_SRV_ID, PSA_AEAD, 0x00000F05, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_KEY_MNG_ID", CRYPTO_SRV_ID, PSA_KEY_MNG, 0x00000F06, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_RNG_ID", CRYPTO_SRV_ID, PSA_RNG, 0x00000F07, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_CRYPTO_FREE_ID", CRYPTO_SRV_ID, PSA_CRYPTO_FREE, 0x00000F08, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_GENERATOR_ID", CRYPTO_SRV_ID, PSA_GENERATOR, 0x00000F09, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
{"PSA_ENTROPY_ID", CRYPTO_SRV_ID, PSA_ENTROPY_INJECT, 0x00000F0A, true, 1, TFM_VERSION_POLICY_STRICT},
|
||||
#endif /* TFM_PSA_API */
|
||||
|
||||
#endif /* __TFM_SERVICE_LIST_INC__ */
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_SPM_SIGNAL_DEFS_H__
|
||||
#define __TFM_SPM_SIGNAL_DEFS_H__
|
||||
|
||||
#define PSA_ITS_GET_MSK_POS (4UL)
|
||||
#define PSA_ITS_GET_MSK (1UL << PSA_ITS_GET_MSK_POS)
|
||||
#define PSA_ITS_SET_MSK_POS (5UL)
|
||||
#define PSA_ITS_SET_MSK (1UL << PSA_ITS_SET_MSK_POS)
|
||||
#define PSA_ITS_INFO_MSK_POS (6UL)
|
||||
#define PSA_ITS_INFO_MSK (1UL << PSA_ITS_INFO_MSK_POS)
|
||||
#define PSA_ITS_REMOVE_MSK_POS (7UL)
|
||||
#define PSA_ITS_REMOVE_MSK (1UL << PSA_ITS_REMOVE_MSK_POS)
|
||||
#define PSA_ITS_RESET_MSK_POS (8UL)
|
||||
#define PSA_ITS_RESET_MSK (1UL << PSA_ITS_RESET_MSK_POS)
|
||||
|
||||
#define PSA_PLATFORM_LC_GET_MSK_POS (4UL)
|
||||
#define PSA_PLATFORM_LC_GET_MSK (1UL << PSA_PLATFORM_LC_GET_MSK_POS)
|
||||
#define PSA_PLATFORM_LC_SET_MSK_POS (5UL)
|
||||
#define PSA_PLATFORM_LC_SET_MSK (1UL << PSA_PLATFORM_LC_SET_MSK_POS)
|
||||
#define PSA_PLATFORM_SYSTEM_RESET_MSK_POS (6UL)
|
||||
#define PSA_PLATFORM_SYSTEM_RESET_MSK (1UL << PSA_PLATFORM_SYSTEM_RESET_MSK_POS)
|
||||
|
||||
#define PSA_CRYPTO_INIT_POS (4UL)
|
||||
#define PSA_CRYPTO_INIT (1UL << PSA_CRYPTO_INIT_POS)
|
||||
#define PSA_MAC_POS (5UL)
|
||||
#define PSA_MAC (1UL << PSA_MAC_POS)
|
||||
#define PSA_HASH_POS (6UL)
|
||||
#define PSA_HASH (1UL << PSA_HASH_POS)
|
||||
#define PSA_ASYMMETRIC_POS (7UL)
|
||||
#define PSA_ASYMMETRIC (1UL << PSA_ASYMMETRIC_POS)
|
||||
#define PSA_SYMMETRIC_POS (8UL)
|
||||
#define PSA_SYMMETRIC (1UL << PSA_SYMMETRIC_POS)
|
||||
#define PSA_AEAD_POS (9UL)
|
||||
#define PSA_AEAD (1UL << PSA_AEAD_POS)
|
||||
#define PSA_KEY_MNG_POS (10UL)
|
||||
#define PSA_KEY_MNG (1UL << PSA_KEY_MNG_POS)
|
||||
#define PSA_RNG_POS (11UL)
|
||||
#define PSA_RNG (1UL << PSA_RNG_POS)
|
||||
#define PSA_CRYPTO_FREE_POS (12UL)
|
||||
#define PSA_CRYPTO_FREE (1UL << PSA_CRYPTO_FREE_POS)
|
||||
#define PSA_GENERATOR_POS (13UL)
|
||||
#define PSA_GENERATOR (1UL << PSA_GENERATOR_POS)
|
||||
#define PSA_ENTROPY_INJECT_POS (14UL)
|
||||
#define PSA_ENTROPY_INJECT (1UL << PSA_ENTROPY_INJECT_POS)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BOOT_RECORD_H__
|
||||
#define __BOOT_RECORD_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \enum shared_data_err_t
|
||||
*
|
||||
* \brief Return values for adding data entry to shared memory area
|
||||
*/
|
||||
enum shared_memory_err_t {
|
||||
SHARED_MEMORY_OK = 0,
|
||||
SHARED_MEMORY_OVERFLOW = 1,
|
||||
SHARED_MEMORY_OVERWRITE = 2,
|
||||
|
||||
/* This is used to force the maximum size */
|
||||
TLV_TYPE_MAX = INT_MAX
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Add a data item to the shared data area between bootloader and
|
||||
* runtime SW
|
||||
*
|
||||
* \param[in] major_type TLV major type, identify consumer
|
||||
* \param[in] minor_type TLV minor type, identify TLV type
|
||||
* \param[in] size length of added data
|
||||
* \param[in] data pointer to data
|
||||
*
|
||||
* \return Returns error code as specified in \ref shared_memory_err_t
|
||||
*/
|
||||
enum shared_memory_err_t
|
||||
boot_add_data_to_shared_area(uint8_t major_type,
|
||||
uint8_t minor_type,
|
||||
size_t size,
|
||||
const uint8_t *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOOT_RECORD_H__ */
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_BOOT_STATUS_H__
|
||||
#define __TFM_BOOT_STATUS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Major numbers to identify the consumer of shared data in runtime SW */
|
||||
#define TLV_MAJOR_CORE 0x0
|
||||
#define TLV_MAJOR_IAS 0x1
|
||||
|
||||
/* PSA Root of Trust */
|
||||
#define TLV_MINOR_IAS_PRoT_SHA256 0x00
|
||||
#define TLV_MINOR_IAS_PRoT_SW_VERSION 0x01
|
||||
#define TLV_MINOR_IAS_PRoT_EPOCH 0x02
|
||||
|
||||
/* Application Root of Trust */
|
||||
#define TLV_MINOR_IAS_ARoT_SHA256 0x03
|
||||
#define TLV_MINOR_IAS_ARoT_SW_VERSION 0x04
|
||||
#define TLV_MINOR_IAS_ARoT_EPOCH 0x05
|
||||
|
||||
/* Non-secure processing environment: single non-secure image */
|
||||
#define TLV_MINOR_IAS_NSPE_SHA256 0x06
|
||||
#define TLV_MINOR_IAS_NSPE_SW_VERSION 0x07
|
||||
#define TLV_MINOR_IAS_NSPE_EPOCH 0x08
|
||||
|
||||
/* ARoT + PRoT: single secure image */
|
||||
#define TLV_MINOR_IAS_S_SHA256 0x09
|
||||
#define TLV_MINOR_IAS_S_SW_VERSION 0x0a
|
||||
#define TLV_MINOR_IAS_S_EPOCH 0x0b
|
||||
|
||||
/* S + NS: combined secure and non-secure image */
|
||||
#define TLV_MINOR_IAS_S_NS_SHA256 0x0c
|
||||
#define TLV_MINOR_IAS_S_NS_SW_VERSION 0x0d
|
||||
#define TLV_MINOR_IAS_S_NS_EPOCH 0x0e
|
||||
|
||||
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
|
||||
|
||||
/**
|
||||
* Shared data TLV header. All fields in little endian.
|
||||
*
|
||||
* ---------------------------
|
||||
* | tlv_magic | tlv_tot_len |
|
||||
* ---------------------------
|
||||
*/
|
||||
struct shared_data_tlv_header {
|
||||
uint16_t tlv_magic;
|
||||
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
|
||||
};
|
||||
|
||||
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
|
||||
|
||||
/**
|
||||
* Shared data TLV entry header format. All fields in little endian.
|
||||
*
|
||||
* ---------------------------------------------
|
||||
* | tlv_major_type | tlv_minor_type | tlv_len |
|
||||
* ---------------------------------------------
|
||||
* | Raw data |
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
struct shared_data_tlv_entry {
|
||||
uint8_t tlv_major_type;
|
||||
uint8_t tlv_minor_type;
|
||||
uint16_t tlv_len; /* size of single TLV entry (including this header). */
|
||||
};
|
||||
|
||||
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
|
||||
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_BOOT_STATUS_H__ */
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "tfm",
|
||||
"config": {
|
||||
"handle_pool_size": {
|
||||
"help": "maximum number of handles that can be opened at the same time",
|
||||
"macro_name": "TFM_CONN_HANDLE_MAX_NUM",
|
||||
"value": 10
|
||||
},
|
||||
"rot_pool_size": {
|
||||
"help": "maximum number of RoT services allowed",
|
||||
"macro_name": "TFM_SPM_MAX_ROT_SERV_NUM",
|
||||
"value": 20
|
||||
},
|
||||
"message_pool_size": {
|
||||
"help": "maximum number of RoT services allowed",
|
||||
"macro_name": "TFM_MSG_QUEUE_MAX_MSG_NUM",
|
||||
"value": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2013-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
|
||||
*
|
||||
* http://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: 2. Jan 2014
|
||||
* $Revision: V2.00
|
||||
*
|
||||
* Project: Common Driver definitions
|
||||
*/
|
||||
|
||||
/* History:
|
||||
* Version 2.00
|
||||
* Changed prefix ARM_DRV -> ARM_DRIVER
|
||||
* Added General return codes definitions
|
||||
* Version 1.10
|
||||
* Namespace prefix ARM_ added
|
||||
* Version 1.00
|
||||
* Initial release
|
||||
*/
|
||||
|
||||
#ifndef __DRIVER_COMMON_H
|
||||
#define __DRIVER_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARM_DRIVER_VERSION_MAJOR_MINOR(major,minor) (((major) << 8) | (minor))
|
||||
|
||||
/**
|
||||
\brief Driver Version
|
||||
*/
|
||||
typedef struct _ARM_DRIVER_VERSION {
|
||||
uint16_t api; ///< API version
|
||||
uint16_t drv; ///< Driver version
|
||||
} ARM_DRIVER_VERSION;
|
||||
|
||||
/* General return codes */
|
||||
#define ARM_DRIVER_OK 0 ///< Operation succeeded
|
||||
#define ARM_DRIVER_ERROR -1 ///< Unspecified error
|
||||
#define ARM_DRIVER_ERROR_BUSY -2 ///< Driver is busy
|
||||
#define ARM_DRIVER_ERROR_TIMEOUT -3 ///< Timeout occurred
|
||||
#define ARM_DRIVER_ERROR_UNSUPPORTED -4 ///< Operation not supported
|
||||
#define ARM_DRIVER_ERROR_PARAMETER -5 ///< Parameter error
|
||||
#define ARM_DRIVER_ERROR_SPECIFIC -6 ///< Start of driver specific errors
|
||||
|
||||
/**
|
||||
\brief General power states
|
||||
*/
|
||||
typedef enum _ARM_POWER_STATE {
|
||||
ARM_POWER_OFF, ///< Power off: no operation possible
|
||||
ARM_POWER_LOW, ///< Low Power mode: retain state, detect and signal wake-up events
|
||||
ARM_POWER_FULL ///< Power on: full operation at maximum performance
|
||||
} ARM_POWER_STATE;
|
||||
|
||||
#endif /* __DRIVER_COMMON_H */
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2018 ARM Limited
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
#ifndef __DRIVER_MPC_H
|
||||
#define __DRIVER_MPC_H
|
||||
|
||||
#include "Driver_Common.h"
|
||||
|
||||
/* API version */
|
||||
#define ARM_MPC_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0)
|
||||
|
||||
/* Error code returned by the driver functions */
|
||||
#define ARM_MPC_ERR_NOT_INIT (ARM_DRIVER_ERROR_SPECIFIC - 1) ///< MPC not initialized */
|
||||
#define ARM_MPC_ERR_NOT_IN_RANGE (ARM_DRIVER_ERROR_SPECIFIC - 2) ///< Address does not belong to a range controlled by the MPC */
|
||||
#define ARM_MPC_ERR_NOT_ALIGNED (ARM_DRIVER_ERROR_SPECIFIC - 3) ///< Address is not aligned on the block size of this MPC */
|
||||
#define ARM_MPC_ERR_INVALID_RANGE (ARM_DRIVER_ERROR_SPECIFIC - 4) ///< The given address range to configure is invalid
|
||||
#define ARM_MPC_ERR_RANGE_SEC_ATTR_NON_COMPATIBLE (ARM_DRIVER_ERROR_SPECIFIC - 4) ///< The given range cannot be accessed with the wanted security attributes */
|
||||
#define ARM_MPC_ERR_UNSPECIFIED (ARM_DRIVER_ERROR_SPECIFIC - 5) ///< Unspecified error */
|
||||
|
||||
/* Security attribute used in various place of the API */
|
||||
typedef enum _ARM_MPC_SEC_ATTR {
|
||||
ARM_MPC_ATTR_SECURE, ///< Secure attribute
|
||||
ARM_MPC_ATTR_NONSECURE, ///< Non-secure attribute
|
||||
/* Used when getting the configuration of a memory range and some blocks are
|
||||
* secure whereas some other are non secure */
|
||||
ARM_MPC_ATTR_MIXED, ///< Mixed attribute
|
||||
} ARM_MPC_SEC_ATTR;
|
||||
|
||||
/* Function documentation */
|
||||
/**
|
||||
\fn ARM_DRIVER_VERSION ARM_MPC_GetVersion (void)
|
||||
\brief Get driver version.
|
||||
\return \ref ARM_DRIVER_VERSION
|
||||
|
||||
\fn int32_t ARM_MPC_Initialize (void)
|
||||
\brief Initialize MPC Interface.
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_Uninitialize (void)
|
||||
\brief De-initialize MPC Interface. The controlled memory region
|
||||
should not be accessed after a call to this function, as
|
||||
it is allowed to configure everything to be secure (to
|
||||
prevent information leak for example).
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_GetBlockSize (uint32_t* blk_size)
|
||||
\brief Get the block size of the MPC. All regions must be aligned
|
||||
on this block size (base address and limit+1 address).
|
||||
\param[out] blk_size: The block size in bytes.
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_GetCtrlConfig (uint32_t* ctrl_val)
|
||||
\brief Get some information on how the MPC IP is configured.
|
||||
\param[out] ctrl_val: MPC control configuration
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_SetCtrlConfig (uint32_t ctrl)
|
||||
\brief Set new control configuration for the MPC IP.
|
||||
\param[in] ctrl: New control configuration.
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_ConfigRegion (uintptr_t base,
|
||||
uintptr_t limit,
|
||||
ARM_MPC_SEC_ATTR attr)
|
||||
\brief Configure a memory region (base and limit included).
|
||||
Both base and limit addresses must belong to the same
|
||||
memory range, and this range must be managed by this MPC.
|
||||
Also, some ranges are only allowed to be configured as
|
||||
secure/non-secure, because of hardware requirements
|
||||
(security aliases), and only a relevant security attribute
|
||||
is therefore allowed for such ranges.
|
||||
\param[in] base: Base address of the region to configure. This
|
||||
bound is included in the configured region.
|
||||
This must be aligned on the block size of this MPC.
|
||||
\param[in] limit: Limit address of the region to configure. This
|
||||
bound is included in the configured region.
|
||||
Limit+1 must be aligned on the block size of this MPC.
|
||||
\param[in] attr: Wanted security attribute of the region.
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_GetRegionConfig (uintptr_t base,
|
||||
uintptr_t limit,
|
||||
ARM_MPC_SEC_ATTR *attr)
|
||||
\brief Gets a memory region (base and limit included).
|
||||
\param[in] base: Base address of the region to poll. This
|
||||
bound is included. It does not need to be aligned
|
||||
in any way.
|
||||
\param[in] limit: Limit address of the region to poll. This
|
||||
bound is included. (limit+1) does not need to be aligned
|
||||
in any way.
|
||||
\param[out] attr: Security attribute of the region.
|
||||
If the region has mixed secure/non-secure,
|
||||
a special value is returned (\ref ARM_MPC_SEC_ATTR).
|
||||
|
||||
In case base and limit+1 addresses are not aligned on
|
||||
the block size, the enclosing region with base and
|
||||
limit+1 aligned on block size will be queried.
|
||||
In case of early termination of the function (error), the
|
||||
security attribute will be set to ARM_MPC_ATTR_MIXED.
|
||||
\return Returns error code.
|
||||
|
||||
\fn int32_t ARM_MPC_EnableInterrupt (void)
|
||||
\brief Enable MPC interrupt.
|
||||
\return Returns error code.
|
||||
|
||||
\fn void ARM_MPC_DisableInterrupt (void)
|
||||
\brief Disable MPC interrupt.
|
||||
|
||||
\fn void ARM_MPC_ClearInterrupt (void)
|
||||
\brief Clear MPC interrupt.
|
||||
|
||||
\fn uint32_t ARM_MPC_InterruptState (void)
|
||||
\brief MPC interrupt state.
|
||||
\return Returns 1 if the interrupt is active, 0 otherwise.
|
||||
|
||||
\fn int32_t ARM_MPC_LockDown (void)
|
||||
\brief Lock down the MPC configuration.
|
||||
\return Returns error code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Access structure of the MPC Driver.
|
||||
*/
|
||||
typedef struct _ARM_DRIVER_MPC {
|
||||
ARM_DRIVER_VERSION (*GetVersion) (void); ///< Pointer to \ref ARM_MPC_GetVersion : Get driver version.
|
||||
int32_t (*Initialize) (void); ///< Pointer to \ref ARM_MPC_Initialize : Initialize the MPC Interface.
|
||||
int32_t (*Uninitialize) (void); ///< Pointer to \ref ARM_MPC_Uninitialize : De-initialize the MPC Interface.
|
||||
int32_t (*GetBlockSize) (uint32_t* blk_size); ///< Pointer to \ref ARM_MPC_GetBlockSize : Get MPC block size
|
||||
int32_t (*GetCtrlConfig) (uint32_t* ctrl_val); ///< Pointer to \ref ARM_MPC_GetCtrlConfig : Get the MPC control configuration flags.
|
||||
int32_t (*SetCtrlConfig) (uint32_t ctrl); ///< Pointer to \ref ARM_MPC_SetCtrlConfig : Set the MPC control configuration flags.
|
||||
int32_t (*ConfigRegion) (uintptr_t base, uintptr_t limit, ARM_MPC_SEC_ATTR attr); ///< Pointer to \ref ARM_MPC_ConfigRegion : Configure a region using the driver for the specific MPC.
|
||||
int32_t (*GetRegionConfig) (uintptr_t base, uintptr_t limit, ARM_MPC_SEC_ATTR *attr); ///< Pointer to \ref ARM_MPC_GetRegionConfig : Get the configuration of a specific region on this MPC.
|
||||
int32_t (*EnableInterrupt) (void); ///< Pointer to \ref ARM_MPC_EnableInterrupt : Enable MPC interrupt.
|
||||
void (*DisableInterrupt) (void); ///< Pointer to \ref ARM_MPC_DisableInterrupt : Disable MPC interrupt.
|
||||
void (*ClearInterrupt) (void); ///< Pointer to \ref ARM_MPC_ClearInterrupt : Clear MPC interrupt.
|
||||
uint32_t (*InterruptState) (void); ///< Pointer to \ref ARM_MPC_InterruptState : MPC interrupt State.
|
||||
int32_t (*LockDown) (void); ///< Pointer to \ref ARM_MPC_LockDown : Lock down the MPC configuration.
|
||||
} const ARM_DRIVER_MPC;
|
||||
|
||||
#endif /* __DRIVER_MPC_H */
|
||||
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
#ifndef __CMSIS_PPC_DRV_H__
|
||||
#define __CMSIS_PPC_DRV_H__
|
||||
|
||||
#include "Driver_Common.h"
|
||||
|
||||
/* API version */
|
||||
#define ARM_PPC_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0)
|
||||
|
||||
/* Security attribute used to configure the peripheral */
|
||||
typedef enum _ARM_PPC_SecAttr {
|
||||
ARM_PPC_SECURE_ONLY, ///< Secure access
|
||||
ARM_PPC_NONSECURE_ONLY, ///< Non-secure access
|
||||
} ARM_PPC_SecAttr;
|
||||
|
||||
/* Privilege attribute used to configure the peripheral */
|
||||
typedef enum _ARM_PPC_PrivAttr {
|
||||
ARM_PPC_PRIV_AND_NONPRIV, ///< Privilege and non-privilege access
|
||||
ARM_PPC_PRIV_ONLY, ///< Privilege only access
|
||||
} ARM_PPC_PrivAttr;
|
||||
|
||||
/* Function documentation */
|
||||
/**
|
||||
\fn ARM_DRIVER_VERSION ARM_PPC_GetVersion (void)
|
||||
\brief Get driver version.
|
||||
\return \ref ARM_DRIVER_VERSION
|
||||
|
||||
\fn int32_t ARM_PPC_Initialize (void)
|
||||
\brief Initialize PPC Interface.
|
||||
\return Returns ARM error code.
|
||||
|
||||
\fn int32_t ARM_PPC_Uninitialize (void)
|
||||
\brief De-initialize MPC Interface.
|
||||
\return Returns ARM error code.
|
||||
|
||||
\fn int32_t ARM_PPC_ConfigPeriph (uint8_t periph,
|
||||
ARM_PPC_SecAttr sec_attr,
|
||||
ARM_PPC_PrivAttr priv_attr)
|
||||
\brief Configures a peripheral controlled by the given PPC.
|
||||
\param[in] periph: Peripheral position in SPCTRL and NSPCTRL registers.
|
||||
\param[in] sec_attr: Secure attribute value.
|
||||
\param[in] priv_attr: Privilege attrivute value.
|
||||
|
||||
Secure Privilege Control Block ( SPCTRL )
|
||||
Non-Secure Privilege Control Block ( NSPCTRL )
|
||||
|
||||
\return Returns ARM error code.
|
||||
|
||||
\fn int32_t ARM_PPC_IsPeriphSecure (uint8_t periph)
|
||||
\brief Check if the peripheral is configured to be secure.
|
||||
\param[in] periph: Peripheral position in SPCTRL and NSPCTRL registers.
|
||||
|
||||
Secure Privilege Control Block ( SPCTRL )
|
||||
Non-Secure Privilege Control Block ( NSPCTRL )
|
||||
|
||||
\return Returns 1 if the peripheral is configured as secure,
|
||||
0 for non-secure.
|
||||
|
||||
\fn uint32_t ARM_PPC_IsPeriphPrivOnly (uint8_t periph)
|
||||
\brief Check if the peripheral is configured to be privilege only.
|
||||
\param[in] periph: Peripheral position in SPCTRL and NSPCTRL registers.
|
||||
|
||||
Secure Privilege Control Block ( SPCTRL )
|
||||
Non-Secure Privilege Control Block ( NSPCTRL )
|
||||
|
||||
\return Returns 1 if the peripheral is configured as privilege access
|
||||
only, 0 for privilege and unprivilege access mode.
|
||||
|
||||
\fn int32_t ARM_PPC_EnableInterrupt (void)
|
||||
\brief Enable PPC interrupt.
|
||||
\return Returns ARM error code.
|
||||
|
||||
\fn void ARM_PPC_DisableInterrupt (void)
|
||||
\brief Disable PPC interrupt.
|
||||
|
||||
\fn void ARM_PPC_ClearInterrupt (void)
|
||||
\brief Clear PPC interrupt.
|
||||
|
||||
\fn int32_t ARM_PPC_InterruptState (void)
|
||||
\brief PPC interrupt state.
|
||||
\return Returns 1 if the interrupt is active, 0 otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Access structure of the MPC Driver.
|
||||
*/
|
||||
typedef struct _ARM_DRIVER_PPC {
|
||||
ARM_DRIVER_VERSION (*GetVersion) (void); ///< Pointer to \ref ARM_PPC_GetVersion : Get driver version.
|
||||
int32_t (*Initialize) (void); ///< Pointer to \ref ARM_PPC_Initialize : Initialize the PPC Interface.
|
||||
int32_t (*Uninitialize) (void); ///< Pointer to \ref ARM_PPC_Uninitialize : De-initialize the PPC Interface.
|
||||
int32_t (*ConfigPeriph) (uint8_t periph, ARM_PPC_SecAttr sec_attr, ARM_PPC_PrivAttr priv_attr); ///< Pointer to \ref ARM_PPC_ConfigPeriph : Configure a peripheral controlled by the PPC.
|
||||
uint32_t (*IsPeriphSecure) (uint8_t periph); ///< Pointer to \ref IsPeriphSecure : Check if the peripheral is configured to be secure.
|
||||
uint32_t (*IsPeriphPrivOnly) (uint8_t periph); ///< Pointer to \ref IsPeriphPrivOnly : Check if the peripheral is configured to be privilege only.
|
||||
int32_t (*EnableInterrupt) (void); ///< Pointer to \ref ARM_PPC_EnableInterrupt : Enable PPC interrupt.
|
||||
void (*DisableInterrupt) (void); ///< Pointer to \ref ARM_PPC_DisableInterrupt : Disable PPC interrupt.
|
||||
void (*ClearInterrupt) (void); ///< Pointer to \ref ARM_PPC_ClearInterrupt : Clear PPC interrupt.
|
||||
uint32_t (*InterruptState) (void); ///< Pointer to \ref ARM_PPC_InterruptState : PPC interrupt State.
|
||||
} const ARM_DRIVER_PPC;
|
||||
|
||||
#endif /* __CMSIS_PPC_DRV_H__ */
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_PLAT_BOOT_SEED_H__
|
||||
#define __TFM_PLAT_BOOT_SEED_H__
|
||||
/**
|
||||
* \file tfm_plat_boot_seed.h
|
||||
*
|
||||
* Boot seed is used by a validating entity to ensure multiple reports were
|
||||
* generated in the same boot session. Boot seed is a random number, generated
|
||||
* only once during a boot cycle and its value is constant in the same cycle.
|
||||
* Size recommendation is 256-bit to meet the statistically improbable property.
|
||||
* Boot seed can be generated by secure boot loader an included to the measured
|
||||
* boot state or can be generated by PRoT SW.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \note The interfaces defined in this file must be implemented for each
|
||||
* SoC.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tfm_plat_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \def BOOT_SEED_SIZE
|
||||
*
|
||||
* \brief Size of boot seed in bytes.
|
||||
*/
|
||||
#define BOOT_SEED_SIZE (32u)
|
||||
|
||||
/**
|
||||
* \brief Gets the boot seed, which is a constant random number during a boot
|
||||
* cycle.
|
||||
*
|
||||
* \param[in] size The required size of boot seed in bytes
|
||||
* \param[out] buf Pointer to the buffer to store boot seed
|
||||
*
|
||||
* \return TFM_PLAT_ERR_SUCCESS if the value is generated correctly. Otherwise,
|
||||
* it returns TFM_PLAT_ERR_SYSTEM_ERR.
|
||||
*/
|
||||
enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_PLAT_BOOT_SEED_H__ */
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_PLAT_DEFS_H__
|
||||
#define __TFM_PLAT_DEFS_H__
|
||||
/**
|
||||
* \note The interfaces defined in this file must be implemented for each
|
||||
* target.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
enum tfm_plat_err_t {
|
||||
TFM_PLAT_ERR_SUCCESS = 0,
|
||||
TFM_PLAT_ERR_SYSTEM_ERR,
|
||||
TFM_PLAT_ERR_MAX_VALUE,
|
||||
/* Following entry is only to ensure the error code of int size */
|
||||
TFM_PLAT_ERR_FORCE_INT_SIZE = INT_MAX
|
||||
};
|
||||
|
||||
/*!
|
||||
* \def TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME)
|
||||
*
|
||||
* \brief This macro provides a mechanism to place a function code in a specific
|
||||
* secure partition at linker time in TF-M Level 3.
|
||||
*
|
||||
* \param[in] TFM_PARTITION_NAME TF-M partition name assigned in the manifest
|
||||
* file "name" field.
|
||||
*/
|
||||
#define TFM_LINK_SET_OBJECT_IN_PARTITION_SECTION(TFM_PARTITION_NAME) \
|
||||
__attribute__((section(TFM_PARTITION_NAME"_ATTR_FN")))
|
||||
|
||||
#endif /* __TFM_PLAT_DEFS_H__ */
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_PLAT_DEVICE_ID_H__
|
||||
#define __TFM_PLAT_DEVICE_ID_H__
|
||||
/**
|
||||
* \file tfm_plat_device_id.h
|
||||
* Provide the Universal Entity ID (UEID) of the device.
|
||||
* It identifies the entire device or a submodule or subsystem. Must be
|
||||
* universally and globally unique and immutable. Variable length with a
|
||||
* maximum size of 33 bytes: 1 type byte and 256 bits.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \note The interfaces defined in this file must be implemented for each
|
||||
* SoC.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tfm_plat_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \def DEVICE_ID_MAX_SIZE
|
||||
*
|
||||
* \brief Maximum size of device ID in bytes
|
||||
*/
|
||||
#define DEVICE_ID_MAX_SIZE (33u)
|
||||
|
||||
/**
|
||||
* \brief Get the UEID of the device.
|
||||
*
|
||||
* \param[in] size The size of the buffer in bytes to store the UEID
|
||||
* \param[out] buf Pointer to the buffer to store the UEID
|
||||
*
|
||||
* \return The size of device ID in bytes, if buffer big enough to store the
|
||||
* ID, otherwise -1.
|
||||
*/
|
||||
int32_t tfm_plat_get_device_id(uint32_t size, uint8_t *buf);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_PLAT_DEVICE_ID_H__ */
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_SPM_HAL_H__
|
||||
#define __TFM_SPM_HAL_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "tfm_secure_api.h"
|
||||
#include "spm_api.h"
|
||||
|
||||
/**
|
||||
* \brief Holds peripheral specific data fields required to manage the
|
||||
* peripherals isolation
|
||||
*
|
||||
* This structure has to be defined in the platform directory, and may have
|
||||
* different definition for each platform. The structure should contain fields
|
||||
* that describe the peripheral for the functions that are prototyped in this
|
||||
* file and are responsible for configuring the isolation of the peripherals.
|
||||
*
|
||||
* Pointers to structures of this type are managed by the SPM, and passed to the
|
||||
* necessary function on isolation request. The pointers are also defined by the
|
||||
* platform in the header file tfm_peripherals_def.h. For details on this, see
|
||||
* the documentation of that file.
|
||||
*/
|
||||
struct tfm_spm_partition_platform_data_t;
|
||||
|
||||
#if TFM_LVL != 1
|
||||
/**
|
||||
* \brief Holds SPM db fields that define the memory regions used by a
|
||||
* partition.
|
||||
*/
|
||||
struct tfm_spm_partition_memory_data_t
|
||||
{
|
||||
uint32_t code_start; /*!< Start of the code memory of this partition. */
|
||||
uint32_t code_limit; /*!< Address of the byte beyond the end of the code
|
||||
* memory of this partition.
|
||||
*/
|
||||
uint32_t ro_start; /*!< Start of the read only memory of this
|
||||
* partition.
|
||||
*/
|
||||
uint32_t ro_limit; /*!< Address of the byte beyond the end of the read
|
||||
* only memory of this partition.
|
||||
*/
|
||||
uint32_t rw_start; /*!< Start of the data region of this partition. */
|
||||
uint32_t rw_limit; /*!< Address of the byte beyond the end of the data
|
||||
* region of this partition.
|
||||
*/
|
||||
uint32_t zi_start; /*!< Start of the zero initialised data region of
|
||||
* this partition.
|
||||
*/
|
||||
uint32_t zi_limit; /*!< Address of the byte beyond the end of the zero
|
||||
* initialised region of this partition.
|
||||
*/
|
||||
uint32_t stack_bottom; /*!< The bottom of the stack for the partition. */
|
||||
uint32_t stack_top; /*!< The top of the stack for the partition. */
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief This function initialises the HW used for isolation, and sets the
|
||||
* default configuration for them.
|
||||
*
|
||||
* This function is called during TF-M core early startup, before DB init
|
||||
*/
|
||||
void tfm_spm_hal_init_isolation_hw(void);
|
||||
|
||||
/**
|
||||
* \brief This function initialises the HW used for isolation, and sets the
|
||||
* default configuration for them.
|
||||
* This function is called during TF-M core early startup, after DB init
|
||||
*/
|
||||
void tfm_spm_hal_setup_isolation_hw(void);
|
||||
|
||||
/**
|
||||
* \brief Configure peripherals for a partition based on the platfotm data from
|
||||
* the DB
|
||||
*
|
||||
* This function is called during partition initialisation (before calling the
|
||||
* init function for the partition)
|
||||
*
|
||||
* \param[in] platform_data The platform fields of the partition DB record to
|
||||
* be used for configuration. Can be NULL.
|
||||
*/
|
||||
void tfm_spm_hal_configure_default_isolation(
|
||||
const struct tfm_spm_partition_platform_data_t *platform_data);
|
||||
/**
|
||||
* \brief Configures the system debug properties.
|
||||
* The default configuration of this function should disable secure debug
|
||||
* when either DAUTH_NONE or DAUTH_NS_ONLY define is set. It is up to the
|
||||
* platform owner to decide if secure debug can be turned on in their
|
||||
* system, if DAUTH_FULL define is present.
|
||||
* The DAUTH_CHIP_DEFAULT define should not be considered a safe default
|
||||
* option unless explicitly noted by the chip vendor.
|
||||
* The implementation has to expect that one of those defines is going to
|
||||
* be set. Otherwise, a compile error needs to be triggered.
|
||||
*/
|
||||
void tfm_spm_hal_init_debug(void);
|
||||
|
||||
/**
|
||||
* \brief Enables the fault handlers
|
||||
*/
|
||||
void enable_fault_handlers(void);
|
||||
|
||||
/**
|
||||
* \brief Configures the system reset request properties
|
||||
*/
|
||||
void system_reset_cfg(void);
|
||||
|
||||
/**
|
||||
* \brief Configures all external interrupts to target the
|
||||
* NS state, apart for the ones associated to secure
|
||||
* peripherals (plus MPC and PPC)
|
||||
*/
|
||||
void nvic_interrupt_target_state_cfg(void);
|
||||
|
||||
/**
|
||||
* \brief This function enable the interrupts associated
|
||||
* to the secure peripherals (plus the isolation boundary violation
|
||||
* interrupts)
|
||||
*/
|
||||
void nvic_interrupt_enable(void);
|
||||
|
||||
/**
|
||||
* \brief Get the VTOR value of non-secure image
|
||||
*
|
||||
* \return Returns the address where the vector table of the non-secure image
|
||||
* is located
|
||||
*/
|
||||
uint32_t tfm_spm_hal_get_ns_VTOR(void);
|
||||
|
||||
/**
|
||||
* \brief Get the initial address of non-secure image main stack
|
||||
*
|
||||
* \return Returns the initial non-secure MSP
|
||||
*/
|
||||
uint32_t tfm_spm_hal_get_ns_MSP(void);
|
||||
|
||||
/**
|
||||
* \brief Get the entry point of the non-secure image
|
||||
*
|
||||
* \return Returns the address of the non-secure image entry point
|
||||
*/
|
||||
uint32_t tfm_spm_hal_get_ns_entry_point(void);
|
||||
|
||||
|
||||
#if TFM_LVL != 1
|
||||
/**
|
||||
* \brief Configure the sandbox for a partition.
|
||||
*
|
||||
* \param[in] memory_data The memory ranges from the partition DB for this
|
||||
* partition
|
||||
* \param[in] platform_data The platform fields of the partition DB record
|
||||
* for this partition. Can be NULL.
|
||||
*
|
||||
* \return Returns the result operation as per \ref spm_err_t
|
||||
*/
|
||||
enum spm_err_t tfm_spm_hal_partition_sandbox_config(
|
||||
const struct tfm_spm_partition_memory_data_t *memory_data,
|
||||
const struct tfm_spm_partition_platform_data_t *platform_data);
|
||||
|
||||
/**
|
||||
* \brief Deconfigure the sandbox for a partition.
|
||||
*
|
||||
* \param[in] memory_data The memory ranges from the partition DB for this
|
||||
* partition
|
||||
* \param[in] platform_data The platform fields of the partition DB record
|
||||
* for this partition. Can be NULL.
|
||||
*
|
||||
* \return Returns the result operation as per \ref spm_err_t
|
||||
*/
|
||||
enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
|
||||
const struct tfm_spm_partition_memory_data_t *memory_data,
|
||||
const struct tfm_spm_partition_platform_data_t *platform_data);
|
||||
|
||||
/**
|
||||
* \brief Set the share region mode
|
||||
*
|
||||
* \param[in] share The mode to set
|
||||
*
|
||||
* \return Returns the result operation as per \ref spm_err_t
|
||||
*/
|
||||
enum spm_err_t tfm_spm_hal_set_share_region(
|
||||
enum tfm_buffer_share_region_e share);
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_SPM_HAL_H__ */
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_ARCH_V8M_H__
|
||||
#define __TFM_ARCH_V8M_H__
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
#define XPSR_T32 0x01000000
|
||||
#define LR_UNPRIVILEGED 0xfffffffd
|
||||
|
||||
/* This header file collects the ARCH related operations. */
|
||||
struct tfm_state_context_base {
|
||||
uint32_t r0;
|
||||
uint32_t r1;
|
||||
uint32_t r2;
|
||||
uint32_t r3;
|
||||
uint32_t r12;
|
||||
uint32_t ra_lr;
|
||||
uint32_t ra;
|
||||
uint32_t xpsr;
|
||||
};
|
||||
|
||||
struct tfm_state_context_ext {
|
||||
uint32_t r4;
|
||||
uint32_t r5;
|
||||
uint32_t r6;
|
||||
uint32_t r7;
|
||||
uint32_t r8;
|
||||
uint32_t r9;
|
||||
uint32_t r10;
|
||||
uint32_t r11;
|
||||
uint32_t sp;
|
||||
uint32_t sp_limit;
|
||||
uint32_t dummy;
|
||||
uint32_t lr;
|
||||
};
|
||||
|
||||
struct tfm_state_context {
|
||||
struct tfm_state_context_ext ctxb;
|
||||
};
|
||||
|
||||
#define TFM_STATE_1ST_ARG(ctx) \
|
||||
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
|
||||
#define TFM_STATE_2ND_ARG(ctx) \
|
||||
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r1)
|
||||
#define TFM_STATE_3RD_ARG(ctx) \
|
||||
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r2)
|
||||
#define TFM_STATE_4TH_ARG(ctx) \
|
||||
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r3)
|
||||
#define TFM_STATE_RET_VAL(ctx) \
|
||||
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
|
||||
|
||||
__STATIC_INLINE void tfm_trigger_pendsv(void)
|
||||
{
|
||||
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
|
||||
}
|
||||
|
||||
void tfm_initialize_context(struct tfm_state_context *ctx,
|
||||
uint32_t r0, uint32_t ra,
|
||||
uint32_t sp, uint32_t sp_limit);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_INTERNAL_DEFINES_H__
|
||||
#define __TFM_INTERNAL_DEFINES_H__
|
||||
|
||||
/* IPC internal return status */
|
||||
#define IPC_SUCCESS 0
|
||||
#define IPC_ERROR_BAD_PARAMETERS (INT32_MIN)
|
||||
#define IPC_ERROR_SHORT_BUFFER (INT32_MIN + 1)
|
||||
#define IPC_ERROR_VERSION (INT32_MIN + 2)
|
||||
#define IPC_ERROR_MEMORY_CHECK (INT32_MIN + 3)
|
||||
#define IPC_ERROR_GENERIC (INT32_MIN + 0x1F)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_LIST_H__
|
||||
#define __TFM_LIST_H__
|
||||
|
||||
/* List structure */
|
||||
struct tfm_list_node_t {
|
||||
struct tfm_list_node_t *prev;
|
||||
struct tfm_list_node_t *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Initialize list head.
|
||||
*
|
||||
* \param[in] head List head need to be initialized.
|
||||
*/
|
||||
__STATIC_INLINE void tfm_list_init(struct tfm_list_node_t *head)
|
||||
{
|
||||
head->next = head;
|
||||
head->prev = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add one node to list tail.
|
||||
*
|
||||
* \param[in] head List head initialized by \ref tfm_list_init.
|
||||
* \param[in] node List node want to be added.
|
||||
*/
|
||||
__STATIC_INLINE void
|
||||
tfm_list_add_tail(struct tfm_list_node_t *head, struct tfm_list_node_t *node)
|
||||
{
|
||||
head->prev->next = node;
|
||||
node->prev = head->prev;
|
||||
head->prev = node;
|
||||
node->next = head;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if a list is empty.
|
||||
*
|
||||
* \param[in] head List head initialized by \ref tfm_list_init.
|
||||
*
|
||||
* \returns returns 1 for empty, or 0 for not.
|
||||
*/
|
||||
__STATIC_INLINE int32_t tfm_list_is_empty(struct tfm_list_node_t *head)
|
||||
{
|
||||
return (head->next == head);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Insert one node to list head.
|
||||
*
|
||||
* \param[in] head List head initialized by \ref tfm_list_init.
|
||||
* \param[in] node List node want to be inserted.
|
||||
*/
|
||||
__STATIC_INLINE void
|
||||
tfm_list_insert_first(struct tfm_list_node_t *head,
|
||||
struct tfm_list_node_t *node)
|
||||
{
|
||||
node->next = head->next;
|
||||
node->prev = head;
|
||||
head->next->prev = node;
|
||||
head->next = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieve the fist node from list.
|
||||
*
|
||||
* \param[in] head List head initialized by \ref tfm_list_init.
|
||||
*
|
||||
* \returns Returns the pointer to first list node.
|
||||
*/
|
||||
__STATIC_INLINE
|
||||
struct tfm_list_node_t *tfm_list_first_node(struct tfm_list_node_t *head)
|
||||
{
|
||||
return head->next;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Delete one node from list.
|
||||
*
|
||||
* \param[in] node List node want to be deleted.
|
||||
*/
|
||||
__STATIC_INLINE void tfm_list_del_node(struct tfm_list_node_t *node)
|
||||
{
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
|
||||
/* Go through each node of a list */
|
||||
#define TFM_LIST_FOR_EACH(node, head) \
|
||||
for (node = (head)->next; node != head; node = node->next)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_MESSAGE_QUEUE_H__
|
||||
#define __TFM_MESSAGE_QUEUE_H__
|
||||
|
||||
#ifndef TFM_MSG_QUEUE_MAX_MSG_NUM
|
||||
#define TFM_MSG_QUEUE_MAX_MSG_NUM 128
|
||||
#endif
|
||||
#define TFM_MSG_MAGIC 0x15154343
|
||||
/* Message struct to collect parameter from client */
|
||||
struct tfm_msg_body_t {
|
||||
int32_t magic;
|
||||
struct tfm_spm_service_t *service; /* RoT service pointer */
|
||||
psa_handle_t handle; /* Connected Service handle */
|
||||
struct tfm_event_ctx ack_mtx; /* Event for ack reponse */
|
||||
psa_msg_t msg; /* PSA message body */
|
||||
psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body */
|
||||
psa_outvec outvec[PSA_MAX_IOVEC];
|
||||
psa_outvec *caller_outvec; /*
|
||||
* Save caller outvec pointer for
|
||||
* write length update
|
||||
*/
|
||||
struct tfm_msg_body_t *next; /* List operators */
|
||||
};
|
||||
|
||||
struct tfm_msg_queue_t {
|
||||
struct tfm_msg_body_t *head; /* Queue head */
|
||||
struct tfm_msg_body_t *tail; /* Queue tail */
|
||||
uint32_t size; /* Number of the queue member */
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Enqueue a message into message queue.
|
||||
*
|
||||
* \param[in] queue Message queue, it will be initialized
|
||||
* if has not been initialized.
|
||||
* \param[in] node Message queue node want to be enqueue.
|
||||
*
|
||||
* \retval IPC_SUCCESS Success.
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
|
||||
*/
|
||||
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
|
||||
struct tfm_msg_body_t *node);
|
||||
|
||||
/**
|
||||
* \brief Dequeue a message from message queue.
|
||||
*
|
||||
* \param[in] queue Message queue.
|
||||
*
|
||||
* \retval node pointer Success.
|
||||
* \retval NULL Queue is NULL or size is zero.
|
||||
*/
|
||||
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue);
|
||||
|
||||
/**
|
||||
* \brief Check if a message queue is empty.
|
||||
*
|
||||
* \param[in] queue Message queue.
|
||||
*
|
||||
* \returns Returns 1 for empty, or 0 for not.
|
||||
*/
|
||||
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_POOLS_H__
|
||||
#define __TFM_POOLS_H__
|
||||
|
||||
/*
|
||||
* Resource pool - few known size resources allocation/free is required,
|
||||
* so pool is more applicable than heap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pool Instance:
|
||||
* [ Pool Instance ] + N * [ Pool Chunks ]
|
||||
*/
|
||||
struct tfm_pool_chunk_t {
|
||||
struct tfm_list_node_t list; /* Chunk list */
|
||||
void *pool; /* Point to the parent pool */
|
||||
uint8_t data[0]; /* Data indicator */
|
||||
};
|
||||
|
||||
struct tfm_pool_instance_t {
|
||||
size_t chunksz; /* Chunks size of pool member */
|
||||
struct tfm_list_node_t chunks_list; /* Chunk list head in pool */
|
||||
struct tfm_pool_chunk_t chunks[0]; /* Data indicator */
|
||||
};
|
||||
|
||||
/*
|
||||
* This will declares a static memory pool variable with chunk memory.
|
||||
* Parameters:
|
||||
* name - Variable name, will be used when register
|
||||
* chunksz - chunk size in bytes
|
||||
* num - Number of chunks
|
||||
*/
|
||||
#define TFM_POOL_DECLARE(name, chunksz, num) \
|
||||
static uint8_t name##_pool_buf[((chunksz) + \
|
||||
sizeof(struct tfm_pool_chunk_t)) * (num) \
|
||||
+ sizeof(struct tfm_pool_instance_t)] \
|
||||
__attribute__((aligned(4))); \
|
||||
static struct tfm_pool_instance_t *name = \
|
||||
(struct tfm_pool_instance_t *)name##_pool_buf
|
||||
|
||||
/* Get the head size of memory pool */
|
||||
#define POOL_HEAD_SIZE (sizeof(struct tfm_pool_instance_t) + \
|
||||
sizeof(struct tfm_pool_chunk_t))
|
||||
|
||||
/* Get the whole size of memory pool */
|
||||
#define POOL_BUFFER_SIZE(name) sizeof(name##_pool_buf)
|
||||
|
||||
/**
|
||||
* \brief Register a memory pool.
|
||||
*
|
||||
* \param[in] pool Pointer to memory pool declared by
|
||||
* \ref TFM_POOL_DECLARE
|
||||
* \param[in] poolsz Size of the pool buffer.
|
||||
* \param[in] chunksz Size of chunks.
|
||||
* \param[in] num Number of chunks.
|
||||
*
|
||||
* \retval IPC_SUCCESS Success.
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
|
||||
*/
|
||||
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
|
||||
size_t chunksz, size_t num);
|
||||
|
||||
/**
|
||||
* \brief Allocate a memory from pool.
|
||||
*
|
||||
* \param[in] pool pool pointer decleared by \ref TFM_POOL_DECLARE
|
||||
*
|
||||
* \retval buffer pointer Success.
|
||||
* \retval NULL Failed.
|
||||
*/
|
||||
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool);
|
||||
|
||||
/**
|
||||
* \brief Free the allocated memory.
|
||||
*
|
||||
* \param[in] ptr Buffer pointer want to free.
|
||||
*/
|
||||
void tfm_pool_free(void *ptr);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_SPM_H__
|
||||
#define __TFM_SPM_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "tfm_list.h"
|
||||
|
||||
#ifndef TFM_SPM_MAX_ROT_SERV_NUM
|
||||
#define TFM_SPM_MAX_ROT_SERV_NUM 28
|
||||
#endif
|
||||
#define TFM_VERSION_POLICY_RELAXED 0
|
||||
#define TFM_VERSION_POLICY_STRICT 1
|
||||
|
||||
#ifndef TFM_CONN_HANDLE_MAX_NUM
|
||||
#define TFM_CONN_HANDLE_MAX_NUM 32
|
||||
#endif
|
||||
|
||||
/* RoT connection handle list */
|
||||
struct tfm_conn_handle_t {
|
||||
psa_handle_t handle; /* Handle value */
|
||||
void *rhandle; /* Reverse handle value */
|
||||
struct tfm_list_node_t list; /* list node */
|
||||
};
|
||||
|
||||
/* Service database defined by manifest */
|
||||
struct tfm_spm_service_db_t {
|
||||
char *name; /* Service name */
|
||||
uint32_t partition_id; /* Partition ID which service belong to */
|
||||
psa_signal_t signal; /* Service signal */
|
||||
uint32_t sid; /* Service identifier */
|
||||
bool non_secure_client; /* If can be called by non secure client */
|
||||
uint32_t minor_version; /* Minor version */
|
||||
uint32_t minor_policy; /* Minor version policy */
|
||||
};
|
||||
|
||||
/* RoT Service data */
|
||||
struct tfm_spm_service_t {
|
||||
struct tfm_spm_service_db_t *service_db; /* Service database pointer */
|
||||
struct tfm_spm_ipc_partition_t *partition; /*
|
||||
* Point to secure partition
|
||||
* data
|
||||
*/
|
||||
struct tfm_list_node_t handle_list; /* Service handle list */
|
||||
struct tfm_msg_queue_t msg_queue; /* Message queue */
|
||||
struct tfm_list_node_t list; /* For list operation */
|
||||
};
|
||||
|
||||
/*
|
||||
* FixMe: This structure is for IPC partition which is different with library
|
||||
* mode partition. There needs to be an alignment for IPC partition database
|
||||
* and library mode database.
|
||||
*/
|
||||
/* Secure Partition data */
|
||||
struct tfm_spm_ipc_partition_t {
|
||||
int32_t index; /* Partition index */
|
||||
int32_t id; /* Secure partition ID */
|
||||
struct tfm_event_ctx signal_event; /* Event signal */
|
||||
uint32_t signals; /* Service signals had been triggered*/
|
||||
uint32_t signal_mask; /* Service signal mask passed by psa_wait() */
|
||||
struct tfm_list_node_t service_list;/* Service list */
|
||||
};
|
||||
|
||||
/*************************** Extended SPM functions **************************/
|
||||
|
||||
/**
|
||||
* \brief Get the running partition ID.
|
||||
*
|
||||
* \return Returns the partition ID
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_running_partition_id_ext(void);
|
||||
|
||||
/******************** Service handle management functions ********************/
|
||||
|
||||
/**
|
||||
* \brief Create connection handle for client connect
|
||||
*
|
||||
* \param[in] service Target service context pointer
|
||||
*
|
||||
* \retval PSA_NULL_HANDLE Create failed \ref PSA_NULL_HANDLE
|
||||
* \retval >0 Service handle created, \ref psa_handle_t
|
||||
*/
|
||||
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service);
|
||||
|
||||
/**
|
||||
* \brief Free connection handle which not used anymore.
|
||||
*
|
||||
* \param[in] service Target service context pointer
|
||||
* \param[in] conn_handle Connection handle created by
|
||||
* tfm_spm_create_conn_handle(), \ref psa_handle_t
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
|
||||
* \retval "Does not return" Panic for not find service by handle
|
||||
*/
|
||||
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle);
|
||||
|
||||
/**
|
||||
* \brief Set reverse handle value for connection.
|
||||
*
|
||||
* \param[in] service Target service context pointer
|
||||
* \param[in] conn_handle Connection handle created by
|
||||
* tfm_spm_create_conn_handle(), \ref psa_handle_t
|
||||
* \param[in] rhandle rhandle need to save
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
|
||||
* \retval "Does not return" Panic for not find handle node
|
||||
*/
|
||||
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle,
|
||||
void *rhandle);
|
||||
|
||||
/**
|
||||
* \brief Get reverse handle value from connection hanlde.
|
||||
*
|
||||
* \param[in] service Target service context pointer
|
||||
* \param[in] conn_handle Connection handle created by
|
||||
* tfm_spm_create_conn_handle(), \ref psa_handle_t
|
||||
*
|
||||
* \retval void * Success
|
||||
* \retval "Does not return" Panic for those:
|
||||
* service pointer are NULL
|
||||
* hanlde is \ref PSA_NULL_HANDLE
|
||||
* handle node does not be found
|
||||
*/
|
||||
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle);
|
||||
|
||||
/******************** Partition management functions *************************/
|
||||
|
||||
/**
|
||||
* \brief Get current running partition context.
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" Return the parttion context pointer
|
||||
* \ref spm_partition_t structures
|
||||
*/
|
||||
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void);
|
||||
|
||||
/**
|
||||
* \brief Get the service context by signal.
|
||||
*
|
||||
* \param[in] partition Partition context pointer
|
||||
* \ref spm_partition_t structures
|
||||
* \param[in] signal Signal associated with inputs to the Secure
|
||||
* Partition, \ref psa_signal_t
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" Target service context pointer,
|
||||
* \ref spm_service_t structures
|
||||
*/
|
||||
struct tfm_spm_service_t *
|
||||
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
|
||||
psa_signal_t signal);
|
||||
|
||||
/**
|
||||
* \brief Get the service context by service ID.
|
||||
*
|
||||
* \param[in] sid RoT Service identity
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" Target service context pointer,
|
||||
* \ref spm_service_t structures
|
||||
*/
|
||||
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid);
|
||||
|
||||
/**
|
||||
* \brief Get the service context by connection handle.
|
||||
*
|
||||
* \param[in] conn_handle Connection handle created by
|
||||
* tfm_spm_create_conn_handle()
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" Target service context pointer,
|
||||
* \ref spm_service_t structures
|
||||
*/
|
||||
struct tfm_spm_service_t *
|
||||
tfm_spm_get_service_by_handle(psa_handle_t conn_handle);
|
||||
|
||||
/**
|
||||
* \brief Get the partition context by partition ID.
|
||||
*
|
||||
* \param[in] partition_id Partition identity
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" Target partition context pointer,
|
||||
* \ref spm_partition_t structures
|
||||
*/
|
||||
struct tfm_spm_ipc_partition_t *
|
||||
tfm_spm_get_partition_by_id(int32_t partition_id);
|
||||
|
||||
/************************ Message functions **********************************/
|
||||
|
||||
/**
|
||||
* \brief Get message context by message handle.
|
||||
*
|
||||
* \param[in] msg_handle Message handle which is a reference generated
|
||||
* by the SPM to a specific message.
|
||||
*
|
||||
* \return The message body context pointer
|
||||
* \ref msg_body_t structures
|
||||
*/
|
||||
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle);
|
||||
|
||||
/**
|
||||
* \brief Create a message for PSA client call.
|
||||
*
|
||||
* \param[in] service Target service context pointer, which can be
|
||||
* obtained by partition management functions
|
||||
* \prarm[in] handle Connect handle return by psa_connect(). Should
|
||||
* be \ref PSA_NULL_HANDLE in psa_connect().
|
||||
* \param[in] type Message type, PSA_IPC_CONNECT, PSA_IPC_CALL or
|
||||
* PSA_IPC_DISCONNECT
|
||||
* \param[in] ns_caller Whether from NS caller
|
||||
* \param[in] invec Array of input \ref psa_invec structures
|
||||
* \param[in] in_len Number of input \ref psa_invec structures
|
||||
* \param[in] outvec Array of output \ref psa_outvec structures
|
||||
* \param[in] out_len Number of output \ref psa_outvec structures
|
||||
* \param[in] caller_outvec Array of caller output \ref psa_outvec structures
|
||||
*
|
||||
* \retval NULL Failed
|
||||
* \retval "Not NULL" New message body pointer \ref msg_body_t structures
|
||||
*/
|
||||
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
|
||||
psa_handle_t handle,
|
||||
uint32_t type, int32_t ns_caller,
|
||||
psa_invec *invec, size_t in_len,
|
||||
psa_outvec *outvec, size_t out_len,
|
||||
psa_outvec *caller_outvec);
|
||||
|
||||
/**
|
||||
* \brief Free message which unused anymore
|
||||
*
|
||||
* \param[in] msg Message pointer which want to free
|
||||
* \ref msg_body_t structures
|
||||
*
|
||||
* \retval void Success
|
||||
* \retval "Does not return" Failed
|
||||
*/
|
||||
void tfm_spm_free_msg(struct tfm_msg_body_t *msg);
|
||||
|
||||
/**
|
||||
* \brief Send message and wake up the SP who is waiting on
|
||||
* message queue, block the current thread and
|
||||
* scheduler triggered
|
||||
*
|
||||
* \param[in] service Target service context pointer, which can be
|
||||
* obtained by partition management functions
|
||||
* \param[in] msg message created by spm_create_msg()
|
||||
* \ref msg_body_t structures
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
|
||||
* \retval IPC_ERROR_GENERIC Failed to enqueue message to service message queue
|
||||
*/
|
||||
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
|
||||
struct tfm_msg_body_t *msg);
|
||||
|
||||
/**
|
||||
* \brief Check the client minor version according to
|
||||
* version policy
|
||||
*
|
||||
* \param[in] service Target service context pointer, which can be get
|
||||
* by partition management functions
|
||||
* \param[in] minor_version Client support minor version
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
|
||||
* \retval IPC_ERROR_VERSION Check failed
|
||||
*/
|
||||
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
|
||||
uint32_t minor_version);
|
||||
|
||||
/**
|
||||
* \brief Check the memory reference is valid.
|
||||
*
|
||||
* \param[in] buffer Pointer of memory reference
|
||||
* \param[in] len Length of memory reference in bytes
|
||||
* \param[in] ns_caller From non-secure caller
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
|
||||
* \retval IPC_ERROR_MEMORY_CHECK Check failed
|
||||
*/
|
||||
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller);
|
||||
|
||||
/* This function should be called before schedule function */
|
||||
void tfm_spm_init(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_SVCALLS_H__
|
||||
#define __TFM_SVCALLS_H__
|
||||
|
||||
/* Svcall for PSA Client APIs */
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_framework_version.
|
||||
*
|
||||
* \return version The version of the PSA Framework implementation
|
||||
* that is providing the runtime services to the
|
||||
* caller.
|
||||
*/
|
||||
uint32_t tfm_svcall_psa_framework_version(void);
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_version.
|
||||
*
|
||||
* \param[in] args Include all input arguments: sid.
|
||||
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
||||
* Or from secure client.
|
||||
*
|
||||
* \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
|
||||
* caller is not permitted to access the service.
|
||||
* \retval > 0 The minor version of the implemented RoT
|
||||
* Service.
|
||||
*/
|
||||
uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller);
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_connect.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* sid, minor_version.
|
||||
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
||||
* Or from secure client.
|
||||
*
|
||||
* \retval > 0 A handle for the connection.
|
||||
* \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
|
||||
* connection.
|
||||
* \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the
|
||||
* connection at the moment.
|
||||
* \retval "Does not return" The RoT Service ID and version are not
|
||||
* supported, or the caller is not permitted to
|
||||
* access the service.
|
||||
*/
|
||||
psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller);
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_call.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* handle, in_vec, in_len, out_vec, out_len.
|
||||
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
||||
* Or from secure client.
|
||||
*
|
||||
* \retval >=0 RoT Service-specific status value.
|
||||
* \retval <0 RoT Service-specific error code.
|
||||
* \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
|
||||
* Service. This indicates that either this or
|
||||
* a previous message was invalid.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg An invalid handle was passed.
|
||||
* \arg The connection is already handling a request.
|
||||
* \arg An invalid memory reference was provided.
|
||||
* \arg in_len + out_len > PSA_MAX_IOVEC.
|
||||
* \arg The message is unrecognized by the RoT
|
||||
* Service or incorrectly formatted.
|
||||
*/
|
||||
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller);
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_close.
|
||||
*
|
||||
* \param[in] args Include all input arguments: handle.
|
||||
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
||||
* Or from secure client.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg An invalid handle was provided that is not
|
||||
* the null handle.
|
||||
* \arg The connection is handling a request.
|
||||
*/
|
||||
void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller);
|
||||
|
||||
/**
|
||||
* \brief SVC handler for IPC functions
|
||||
*
|
||||
* \param[in] svc_num SVC number
|
||||
* \param[in] ctx Argument context
|
||||
*
|
||||
* \returns Return values from those who has,
|
||||
* or PSA_SUCCESS.
|
||||
*/
|
||||
int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_THREAD_H__
|
||||
#define __TFM_THREAD_H__
|
||||
|
||||
#include "tfm_arch_v8m.h"
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
/* Status code */
|
||||
#define THRD_STAT_CREATING 0
|
||||
#define THRD_STAT_RUNNING 1
|
||||
#define THRD_STAT_BLOCK 2
|
||||
#define THRD_STAT_DETACH 3
|
||||
#define THRD_STAT_INVALID 4
|
||||
|
||||
/* Security attribute - default as security */
|
||||
#define THRD_ATTR_SECURE_OFFSET 16
|
||||
#define THRD_ATTR_SECURE (0)
|
||||
#define THRD_ATTR_NON_SECURE (1 << THRD_ATTR_SECURE_OFFSET)
|
||||
|
||||
/* Lower value has higher priority */
|
||||
#define THRD_PRIOR_MASK 0xFF
|
||||
#define THRD_PRIOR_HIGHEST 0x0
|
||||
#define THRD_PRIOR_MEDIUM 0x7F
|
||||
#define THRD_PRIOR_LOWEST 0xFF
|
||||
|
||||
/* Error code */
|
||||
#define THRD_SUCCESS 0
|
||||
#define THRD_ERR_INVALID_PARAM 1
|
||||
|
||||
/* Thread entry function type */
|
||||
typedef void *(*tfm_thrd_func_t)(void *);
|
||||
|
||||
/* Thread context */
|
||||
struct tfm_thrd_ctx {
|
||||
tfm_thrd_func_t pfn; /* entry function */
|
||||
void *param; /* entry parameter */
|
||||
uint8_t *sp_base; /* stack bottom */
|
||||
uint8_t *sp_top; /* stack top */
|
||||
uint32_t prior; /* priority */
|
||||
uint32_t status; /* status */
|
||||
|
||||
struct tfm_state_context state_ctx; /* State context */
|
||||
struct tfm_thrd_ctx *next; /* next thread in list */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize a thread context with the necessary info.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of caller provided thread context
|
||||
* pfn - thread entry function
|
||||
* param - thread entry function parameter
|
||||
* sp_base - stack pointer base (higher address)
|
||||
* sp_top - stack pointer top (lower address)
|
||||
*
|
||||
* Notes :
|
||||
* Thread contex rely on caller allocated memory; initialize members in
|
||||
* context. This function does not insert thread into schedulable list.
|
||||
*/
|
||||
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
|
||||
tfm_thrd_func_t pfn, void *param,
|
||||
uint8_t *sp_base, uint8_t *sp_top);
|
||||
|
||||
/* Set thread priority.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
* prior - priority value (0~255)
|
||||
*
|
||||
* Notes :
|
||||
* Set thread priority. Priority is set to THRD_PRIOR_MEDIUM in
|
||||
* tfm_thrd_init().
|
||||
*/
|
||||
void __STATIC_INLINE tfm_thrd_priority(struct tfm_thrd_ctx *pth,
|
||||
uint32_t prior)
|
||||
{
|
||||
pth->prior &= ~THRD_PRIOR_MASK;
|
||||
pth->prior |= prior & THRD_PRIOR_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set thread security attribute.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
* attr_secure - THRD_ATTR_SECURE or THRD_ATTR_NON_SECURE
|
||||
*
|
||||
* Notes
|
||||
* Reuse prior of thread context to shift down non-secure thread priority.
|
||||
*/
|
||||
void __STATIC_INLINE tfm_thrd_secure(struct tfm_thrd_ctx *pth,
|
||||
uint32_t attr_secure)
|
||||
{
|
||||
pth->prior &= ~THRD_ATTR_NON_SECURE;
|
||||
pth->prior |= attr_secure;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set thread status.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
* new_status - new status of thread
|
||||
*
|
||||
* Return :
|
||||
* None
|
||||
*
|
||||
* Notes :
|
||||
* Thread status is not changed if invalid status value inputed.
|
||||
*/
|
||||
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status);
|
||||
|
||||
/*
|
||||
* Get thread status.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
*
|
||||
* Return :
|
||||
* Status of thread
|
||||
*/
|
||||
uint32_t __STATIC_INLINE tfm_thrd_get_status(struct tfm_thrd_ctx *pth)
|
||||
{
|
||||
return pth->status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set thread state return value.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
* retval - return value to be set for thread state
|
||||
*
|
||||
* Notes :
|
||||
* This API is useful for blocked syscall blocking thread. Syscall
|
||||
* could set its return value to the caller before caller goes.
|
||||
*/
|
||||
void __STATIC_INLINE tfm_thrd_set_retval(struct tfm_thrd_ctx *pth,
|
||||
uint32_t retval)
|
||||
{
|
||||
TFM_STATE_RET_VAL(&pth->state_ctx) = retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate thread context and insert it into schedulable list.
|
||||
*
|
||||
* Parameters :
|
||||
* pth - pointer of thread context
|
||||
*
|
||||
* Return :
|
||||
* THRD_SUCCESS for success. Or an error is returned.
|
||||
*
|
||||
* Notes :
|
||||
* This function validates thread info. It returns error if thread info
|
||||
* is not correct. Thread is avaliable after successful tfm_thrd_start().
|
||||
*/
|
||||
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth);
|
||||
|
||||
/*
|
||||
* Get current running thread.
|
||||
*
|
||||
* Return :
|
||||
* Current running thread context pointer.
|
||||
*/
|
||||
struct tfm_thrd_ctx *tfm_thrd_curr_thread(void);
|
||||
|
||||
/*
|
||||
* Get next running thread in list.
|
||||
*
|
||||
* Return :
|
||||
* Pointer of next thread to be run.
|
||||
*/
|
||||
struct tfm_thrd_ctx *tfm_thrd_next_thread(void);
|
||||
|
||||
/*
|
||||
* Activate a scheduling action after exception.
|
||||
*
|
||||
* Notes :
|
||||
* This function could be called multiple times before scheduling.
|
||||
*/
|
||||
void tfm_thrd_activate_schedule(void);
|
||||
|
||||
/*
|
||||
* Save current context into 'prev' thread and switch to 'next'.
|
||||
*
|
||||
* Parameters :
|
||||
* ctxb - latest caller context
|
||||
* prev - previous thread to be switched out
|
||||
* next - thread to be run
|
||||
*
|
||||
* Notes :
|
||||
* This function could be called multiple times before scheduling.
|
||||
*/
|
||||
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
|
||||
struct tfm_thrd_ctx *prev,
|
||||
struct tfm_thrd_ctx *next);
|
||||
|
||||
/*
|
||||
* Exit current running thread.
|
||||
*
|
||||
* Notes :
|
||||
* Remove current thread out of schedulable list.
|
||||
*/
|
||||
void tfm_thrd_do_exit(void);
|
||||
|
||||
/*
|
||||
* PendSV specified function.
|
||||
*
|
||||
* Parameters :
|
||||
* ctxb - State context storage pointer
|
||||
*
|
||||
* Notes:
|
||||
* This is a staging API. Scheduler should be called in SPM finally and
|
||||
* this function will be obsoleted later.
|
||||
*/
|
||||
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_UTILS_H__
|
||||
#define __TFM_UTILS_H__
|
||||
|
||||
/* CPU spin here */
|
||||
void tfm_panic(void);
|
||||
|
||||
/* Assert and spin */
|
||||
#define TFM_ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
printf("Assert:%s:%d", __FUNCTION__, __LINE__); \
|
||||
while (1) \
|
||||
; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Get container structure start address from member */
|
||||
#define TFM_GET_CONTAINER_PTR(ptr, type, member) \
|
||||
(type *)((unsigned long)(ptr) - offsetof(type, member))
|
||||
|
||||
int32_t tfm_bitcount(uint32_t n);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_WAIT_H__
|
||||
#define __TFM_WAIT_H__
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
|
||||
#define EVENT_MAGIC 0x65766e74
|
||||
#define EVENT_STAT_WAITED 0x0
|
||||
#define EVENT_STAT_SIGNALED 0x1
|
||||
|
||||
struct tfm_event_ctx {
|
||||
uint32_t magic; /* 'evnt' */
|
||||
struct tfm_thrd_ctx *owner; /* waiting thread */
|
||||
uint32_t status; /* status */
|
||||
uint32_t retval; /* return value */
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize an event context.
|
||||
*
|
||||
* Parameters :
|
||||
* pevt - pointer of event context caller provided
|
||||
* stat - initial status (EVENT_STAT_WAITED or EVENT_STAT_SIGNALED)
|
||||
*/
|
||||
void __STATIC_INLINE tfm_event_init(struct tfm_event_ctx *pevt, uint32_t stat)
|
||||
{
|
||||
pevt->magic = EVENT_MAGIC;
|
||||
pevt->status = stat;
|
||||
pevt->owner = NULL;
|
||||
pevt->retval = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait on an event.
|
||||
*
|
||||
* Parameters :
|
||||
* pevt - pointer of event context
|
||||
*
|
||||
* Notes :
|
||||
* Thread is blocked if event is not signaled.
|
||||
*/
|
||||
void tfm_event_wait(struct tfm_event_ctx *pevt);
|
||||
|
||||
/*
|
||||
* Signal an event.
|
||||
*
|
||||
* Parameters :
|
||||
* pevt - pointer of event context
|
||||
*
|
||||
* Notes :
|
||||
* Waiting thread on this event will be running.
|
||||
*/
|
||||
void tfm_event_signal(struct tfm_event_ctx *pevt);
|
||||
|
||||
/*
|
||||
* Peek an event status.
|
||||
*
|
||||
* Parameters :
|
||||
* pevt - pointer of event context
|
||||
*
|
||||
* Return :
|
||||
* Status of event.
|
||||
*
|
||||
* Notes :
|
||||
* This function is used for getting event status without blocking thread.
|
||||
*/
|
||||
uint32_t tfm_event_peek(struct tfm_event_ctx *pevt);
|
||||
|
||||
/*
|
||||
* Set event owner return value.
|
||||
*
|
||||
* Parameters :
|
||||
* pevt - pointer of event context
|
||||
* retval - return value of blocked owner thread
|
||||
*
|
||||
* Notes :
|
||||
* Thread return value is set while thread is to be running.
|
||||
*/
|
||||
void tfm_event_owner_retval(struct tfm_event_ctx *pevt, uint32_t retval);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_svc.h"
|
||||
#include "psa_client.h"
|
||||
|
||||
__attribute__((naked))
|
||||
uint32_t psa_framework_version(void)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_FRAMEWORK_VERSION));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
uint32_t psa_version(uint32_t sid)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_VERSION));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_CONNECT));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
psa_status_t psa_call(psa_handle_t handle,
|
||||
const psa_invec *in_vec,
|
||||
size_t in_len,
|
||||
psa_outvec *out_vec,
|
||||
size_t out_len)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_CALL));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_close(psa_handle_t handle)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_CLOSE));
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_svc.h"
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
|
||||
__attribute__((naked))
|
||||
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
|
||||
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_WAIT));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_GET));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_SET_RHANDLE));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
|
||||
void *buffer, size_t num_bytes)
|
||||
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_READ));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_SKIP));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
|
||||
const void *buffer, size_t num_bytes)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_WRITE));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_reply(psa_handle_t msg_handle, psa_status_t retval)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_REPLY));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_notify(int32_t partition_id)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_NOTIFY));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_clear(void)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_CLEAR));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
void psa_eoi(psa_signal_t irq_signal)
|
||||
{
|
||||
__ASM("SVC %0 \n"
|
||||
"BX LR \n"
|
||||
: : "I" (TFM_SVC_PSA_EOI));
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tfm_arch_v8m.h"
|
||||
#include "cmsis.h"
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "tfm_thread.h"
|
||||
|
||||
/* This file contains the ARCH code for ARM V8M */
|
||||
|
||||
/*
|
||||
* Thread exit zone.
|
||||
* This function is set as the return address of thread entry and only
|
||||
* privileged thread could return here. Un-privileged thread triggers
|
||||
* fault if it tries to jump here and it gets exit by fault handler.
|
||||
*
|
||||
* The reason of putting this function here is for fault handler checking.
|
||||
* Function address could be checked in fault handler to know it is a REAL
|
||||
* thread exit or just an exception.
|
||||
*/
|
||||
static void exit_zone(void)
|
||||
{
|
||||
tfm_thrd_do_exit();
|
||||
}
|
||||
|
||||
void tfm_initialize_context(struct tfm_state_context *ctx,
|
||||
uint32_t r0, uint32_t ra,
|
||||
uint32_t sp, uint32_t sp_limit)
|
||||
{
|
||||
/*
|
||||
* For security consideration, set unused registers into ZERO;
|
||||
* and only necessary registers are set here.
|
||||
*/
|
||||
struct tfm_state_context_base *p_ctxa =
|
||||
(struct tfm_state_context_base *)sp;
|
||||
|
||||
/*
|
||||
* Shift back SP to leave space for holding base context
|
||||
* since thread is kicked off through exception return.
|
||||
*/
|
||||
p_ctxa--;
|
||||
|
||||
/* Basic context is considerate at thread start.*/
|
||||
tfm_memset(p_ctxa, 0, sizeof(*p_ctxa));
|
||||
p_ctxa->r0 = r0;
|
||||
p_ctxa->ra = ra;
|
||||
p_ctxa->ra_lr = (uint32_t)exit_zone;
|
||||
p_ctxa->xpsr = XPSR_T32;
|
||||
|
||||
tfm_memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->ctxb.sp = (uint32_t)p_ctxa;
|
||||
ctx->ctxb.sp_limit = sp_limit;
|
||||
ctx->ctxb.lr = LR_UNPRIVILEGED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stack status at PendSV entry:
|
||||
*
|
||||
* [ R0 - R3 ]<- PSP
|
||||
* [ R12 ]
|
||||
* [ LR_of_RA ]
|
||||
* MSP->[ ........ ] [ RA ]
|
||||
* [ ........ ] [ XPSR ]
|
||||
* [ ........ ]
|
||||
* [ ........ ]
|
||||
*
|
||||
* Stack status before calling pendsv_do_schedule():
|
||||
*
|
||||
* MSP->[ R4 - R11 ]
|
||||
* [ PSP ]--->[ R0 - R3 ]
|
||||
* [ PSP Limit] [ R12 ]
|
||||
* [ R2(dummy)] [ LR_of_RA ]
|
||||
* [ LR ] [ RA ]
|
||||
* [ ........ ] [ XPSR ]
|
||||
* [ ........ ] [ ........ ]
|
||||
* [ ........ ]
|
||||
*
|
||||
* pendsv_do_schedule() updates stacked context into current thread and
|
||||
* replace stacked context with context of next thread.
|
||||
*
|
||||
* Scheduler does not support handler mode thread so take PSP/PSP_LIMIT as
|
||||
* thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
|
||||
* aligned.
|
||||
*/
|
||||
__attribute__((naked)) void PendSV_Handler(void)
|
||||
{
|
||||
__ASM(
|
||||
"mrs r0, psp \n"
|
||||
"mrs r1, psplim \n"
|
||||
"push {r0, r1, r2, lr} \n"
|
||||
"push {r4-r11} \n"
|
||||
"mov r0, sp \n"
|
||||
"bl tfm_pendsv_do_schedule \n"
|
||||
"pop {r4-r11} \n"
|
||||
"pop {r0, r1, r2, lr} \n"
|
||||
"msr psp, r0 \n"
|
||||
"msr psplim, r1 \n"
|
||||
"bx lr \n"
|
||||
);
|
||||
}
|
||||
|
||||
/* Reserved for future usage */
|
||||
__attribute__((naked)) void MemManage_Handler(void)
|
||||
{
|
||||
__ASM("b .");
|
||||
}
|
||||
|
||||
__attribute__((naked)) void BusFault_Handler(void)
|
||||
{
|
||||
__ASM("b .");
|
||||
}
|
||||
__attribute__((naked)) void UsageFault_Handler(void)
|
||||
{
|
||||
__ASM("b .");
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_wait.h"
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "tfm_internal_defines.h"
|
||||
#include "tfm_message_queue.h"
|
||||
|
||||
/* Message queue process */
|
||||
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
|
||||
struct tfm_msg_body_t *node)
|
||||
{
|
||||
if (!queue || !node) {
|
||||
return IPC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
if (queue->size == 0) {
|
||||
queue->head = node;
|
||||
queue->tail = node;
|
||||
} else {
|
||||
queue->tail->next = node;
|
||||
queue->tail = node;
|
||||
}
|
||||
queue->size++;
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue)
|
||||
{
|
||||
struct tfm_msg_body_t *pop_node;
|
||||
|
||||
if (!queue) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (queue->size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pop_node = queue->head;
|
||||
queue->head = queue->head->next;
|
||||
queue->size--;
|
||||
return pop_node;
|
||||
}
|
||||
|
||||
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue)
|
||||
{
|
||||
return queue->size == 0 ? 1 : 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_wait.h"
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "tfm_internal_defines.h"
|
||||
#include "cmsis_compiler.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "tfm_list.h"
|
||||
#include "tfm_pools.h"
|
||||
#include "secure_utilities.h"
|
||||
|
||||
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
|
||||
size_t chunksz, size_t num)
|
||||
{
|
||||
struct tfm_pool_chunk_t *pchunk;
|
||||
size_t i;
|
||||
|
||||
if (!pool || num == 0) {
|
||||
return IPC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
/* Ensure buffer is large enough */
|
||||
if (poolsz != ((chunksz + sizeof(struct tfm_pool_chunk_t)) * num +
|
||||
sizeof(struct tfm_pool_instance_t))) {
|
||||
return IPC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
/* Buffer should be BSS cleared but clear it again */
|
||||
tfm_memset(pool, 0, poolsz);
|
||||
|
||||
/* Chain pool chunks */
|
||||
tfm_list_init(&pool->chunks_list);
|
||||
|
||||
pchunk = (struct tfm_pool_chunk_t *)pool->chunks;
|
||||
for (i = 0; i < num; i++) {
|
||||
pchunk->pool = pool;
|
||||
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
|
||||
pchunk = (struct tfm_pool_chunk_t *)&pchunk->data[chunksz];
|
||||
}
|
||||
|
||||
/* Prepare instance and insert to pool list */
|
||||
pool->chunksz = chunksz;
|
||||
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool)
|
||||
{
|
||||
struct tfm_list_node_t *node;
|
||||
struct tfm_pool_chunk_t *pchunk;
|
||||
|
||||
if (!pool) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tfm_list_is_empty(&pool->chunks_list)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node = tfm_list_first_node(&pool->chunks_list);
|
||||
pchunk = TFM_GET_CONTAINER_PTR(node, struct tfm_pool_chunk_t, list);
|
||||
|
||||
/* Remove node from list node, it will be added when pool free */
|
||||
tfm_list_del_node(node);
|
||||
|
||||
return &pchunk->data;
|
||||
}
|
||||
|
||||
void tfm_pool_free(void *ptr)
|
||||
{
|
||||
struct tfm_pool_chunk_t *pchunk;
|
||||
struct tfm_pool_instance_t *pool;
|
||||
|
||||
pchunk = TFM_GET_CONTAINER_PTR(ptr, struct tfm_pool_chunk_t, data);
|
||||
pool = (struct tfm_pool_instance_t *)pchunk->pool;
|
||||
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
|
||||
}
|
||||
|
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "spm_api.h"
|
||||
#include "spm_db.h"
|
||||
#include "spm_db_setup.h"
|
||||
#include "tfm_internal_defines.h"
|
||||
#include "tfm_wait.h"
|
||||
#include "tfm_message_queue.h"
|
||||
#include "tfm_list.h"
|
||||
#include "tfm_pools.h"
|
||||
#include "tfm_spm.h"
|
||||
#include "tfm_spm_signal_defs.h"
|
||||
#include "tfm_thread.h"
|
||||
#include "region_defs.h"
|
||||
#include "tfm_nspm.h"
|
||||
|
||||
/*
|
||||
* IPC partitions.
|
||||
* FixMe: Need to get align with spm_partition_db_t.
|
||||
*/
|
||||
static struct tfm_spm_ipc_partition_t
|
||||
g_spm_ipc_partition[SPM_MAX_PARTITIONS] = {};
|
||||
|
||||
/* Extern SPM variable */
|
||||
extern struct spm_partition_db_t g_spm_partition_db;
|
||||
|
||||
/* Pools */
|
||||
TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
|
||||
TFM_CONN_HANDLE_MAX_NUM);
|
||||
TFM_POOL_DECLARE(spm_service_pool, sizeof(struct tfm_spm_service_t),
|
||||
TFM_SPM_MAX_ROT_SERV_NUM);
|
||||
TFM_POOL_DECLARE(msg_db_pool, sizeof(struct tfm_msg_body_t),
|
||||
TFM_MSG_QUEUE_MAX_MSG_NUM);
|
||||
|
||||
static struct tfm_spm_service_db_t g_spm_service_db[] = {
|
||||
#include "tfm_service_list.inc"
|
||||
};
|
||||
|
||||
/********************** SPM functions for handler mode ***********************/
|
||||
|
||||
/* Service handle management functions */
|
||||
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service)
|
||||
{
|
||||
struct tfm_conn_handle_t *node;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
|
||||
/* Get buffer for handle list structure from handle pool */
|
||||
node = (struct tfm_conn_handle_t *)tfm_pool_alloc(conn_handle_pool);
|
||||
if (!node) {
|
||||
return PSA_NULL_HANDLE;
|
||||
}
|
||||
|
||||
/* Global unique handle, use handle buffer address directly */
|
||||
node->handle = (psa_handle_t)node;
|
||||
|
||||
/* Add handle node to list for next psa functions */
|
||||
tfm_list_add_tail(&service->handle_list, &node->list);
|
||||
|
||||
return node->handle;
|
||||
}
|
||||
|
||||
static struct tfm_conn_handle_t *
|
||||
tfm_spm_find_conn_handle_node(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle)
|
||||
{
|
||||
struct tfm_conn_handle_t *handle_node;
|
||||
struct tfm_list_node_t *node, *head;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
|
||||
head = &service->handle_list;
|
||||
TFM_LIST_FOR_EACH(node, head) {
|
||||
handle_node = TFM_GET_CONTAINER_PTR(node, struct tfm_conn_handle_t,
|
||||
list);
|
||||
if (handle_node->handle == conn_handle) {
|
||||
return handle_node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle)
|
||||
{
|
||||
struct tfm_conn_handle_t *node;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
|
||||
/* There are many handles for each RoT Service */
|
||||
node = tfm_spm_find_conn_handle_node(service, conn_handle);
|
||||
if (!node) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* Remove node from handle list */
|
||||
tfm_list_del_node(&node->list);
|
||||
|
||||
node->rhandle = NULL;
|
||||
|
||||
/* Back handle buffer to pool */
|
||||
tfm_pool_free(node);
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle,
|
||||
void *rhandle)
|
||||
{
|
||||
struct tfm_conn_handle_t *node;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
/* Set reverse handle value only be allowed for a connected handle */
|
||||
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
|
||||
|
||||
/* There are many handles for each RoT Service */
|
||||
node = tfm_spm_find_conn_handle_node(service, conn_handle);
|
||||
if (!node) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
node->rhandle = rhandle;
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
|
||||
psa_handle_t conn_handle)
|
||||
{
|
||||
struct tfm_conn_handle_t *node;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
/* Get reverse handle value only be allowed for a connected handle */
|
||||
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
|
||||
|
||||
/* There are many handles for each RoT Service */
|
||||
node = tfm_spm_find_conn_handle_node(service, conn_handle);
|
||||
if (!node) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
return node->rhandle;
|
||||
}
|
||||
|
||||
/* Partition management functions */
|
||||
struct tfm_spm_service_t *
|
||||
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
|
||||
psa_signal_t signal)
|
||||
{
|
||||
struct tfm_list_node_t *node, *head;
|
||||
struct tfm_spm_service_t *service;
|
||||
|
||||
TFM_ASSERT(partition);
|
||||
|
||||
if (tfm_list_is_empty(&partition->service_list)) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
head = &partition->service_list;
|
||||
TFM_LIST_FOR_EACH(node, head) {
|
||||
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t, list);
|
||||
if (service->service_db->signal == signal) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid)
|
||||
{
|
||||
uint32_t i;
|
||||
struct tfm_list_node_t *node, *head;
|
||||
struct tfm_spm_service_t *service;
|
||||
|
||||
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
|
||||
/* Skip partition without IPC flag */
|
||||
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
|
||||
SPM_PART_FLAG_IPC) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
head = &g_spm_ipc_partition[i].service_list;
|
||||
TFM_LIST_FOR_EACH(node, head) {
|
||||
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t,
|
||||
list);
|
||||
if (service->service_db->sid == sid) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tfm_spm_service_t *
|
||||
tfm_spm_get_service_by_handle(psa_handle_t conn_handle)
|
||||
{
|
||||
uint32_t i;
|
||||
struct tfm_conn_handle_t *handle;
|
||||
struct tfm_list_node_t *service_node, *service_head;
|
||||
struct tfm_list_node_t *handle_node, *handle_head;
|
||||
struct tfm_spm_service_t *service;
|
||||
|
||||
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
|
||||
/* Skip partition without IPC flag */
|
||||
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
|
||||
SPM_PART_FLAG_IPC) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
service_head = &g_spm_ipc_partition[i].service_list;
|
||||
TFM_LIST_FOR_EACH(service_node, service_head) {
|
||||
service = TFM_GET_CONTAINER_PTR(service_node,
|
||||
struct tfm_spm_service_t, list);
|
||||
handle_head = &service->handle_list;
|
||||
TFM_LIST_FOR_EACH(handle_node, handle_head) {
|
||||
handle = TFM_GET_CONTAINER_PTR(handle_node,
|
||||
struct tfm_conn_handle_t, list);
|
||||
if (handle->handle == conn_handle) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tfm_spm_ipc_partition_t *
|
||||
tfm_spm_get_partition_by_id(int32_t partition_id)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
|
||||
if (g_spm_ipc_partition[i].id == partition_id) {
|
||||
return &g_spm_ipc_partition[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void)
|
||||
{
|
||||
uint32_t spid;
|
||||
|
||||
spid = tfm_spm_partition_get_running_partition_id_ext();
|
||||
|
||||
return tfm_spm_get_partition_by_id(spid);
|
||||
}
|
||||
|
||||
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
|
||||
uint32_t minor_version)
|
||||
{
|
||||
TFM_ASSERT(service);
|
||||
|
||||
switch (service->service_db->minor_policy) {
|
||||
case TFM_VERSION_POLICY_RELAXED:
|
||||
if (minor_version > service->service_db->minor_version) {
|
||||
return IPC_ERROR_VERSION;
|
||||
}
|
||||
break;
|
||||
case TFM_VERSION_POLICY_STRICT:
|
||||
if (minor_version != service->service_db->minor_version) {
|
||||
return IPC_ERROR_VERSION;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return IPC_ERROR_VERSION;
|
||||
}
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Message functions */
|
||||
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
|
||||
{
|
||||
/*
|
||||
* There may be one error handle passed by the caller in two conditions:
|
||||
* 1. Not a valid message handle.
|
||||
* 2. Handle between different Partitions. Partition A passes one handle
|
||||
* belong to other Partitions and tries to access other's data.
|
||||
* So, need do necessary checking to prevent those conditions.
|
||||
*/
|
||||
struct tfm_msg_body_t *msg;
|
||||
uint32_t partition_id;
|
||||
|
||||
msg = (struct tfm_msg_body_t *)msg_handle;
|
||||
if (!msg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* FixMe: For condition 1: using a magic number to define it's a message.
|
||||
* It needs to be an enhancement to check the handle belong to service.
|
||||
*/
|
||||
if (msg->magic != TFM_MSG_MAGIC) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For condition 2: check if the partition ID is same */
|
||||
partition_id = tfm_spm_partition_get_running_partition_id_ext();
|
||||
if (partition_id != msg->service->partition->id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
|
||||
psa_handle_t handle,
|
||||
uint32_t type, int32_t ns_caller,
|
||||
psa_invec *invec, size_t in_len,
|
||||
psa_outvec *outvec, size_t out_len,
|
||||
psa_outvec *caller_outvec)
|
||||
{
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
uint32_t i;
|
||||
|
||||
TFM_ASSERT(service);
|
||||
TFM_ASSERT(!(invec == NULL && in_len != 0));
|
||||
TFM_ASSERT(!(outvec == NULL && out_len != 0));
|
||||
TFM_ASSERT(in_len <= PSA_MAX_IOVEC);
|
||||
TFM_ASSERT(out_len <= PSA_MAX_IOVEC);
|
||||
TFM_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
|
||||
|
||||
/* Get message buffer from message pool */
|
||||
msg = (struct tfm_msg_body_t *)tfm_pool_alloc(msg_db_pool);
|
||||
if (!msg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clear message buffer before using it */
|
||||
tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
|
||||
|
||||
tfm_event_init(&msg->ack_mtx, EVENT_STAT_WAITED);
|
||||
msg->magic = TFM_MSG_MAGIC;
|
||||
msg->service = service;
|
||||
msg->handle = handle;
|
||||
msg->caller_outvec = caller_outvec;
|
||||
/* Get current partition id */
|
||||
if (ns_caller) {
|
||||
msg->msg.client_id = tfm_nspm_get_current_client_id();
|
||||
} else {
|
||||
msg->msg.client_id = tfm_spm_partition_get_running_partition_id_ext();
|
||||
}
|
||||
|
||||
/* Copy contents */
|
||||
msg->msg.type = type;
|
||||
|
||||
for (i = 0; i < in_len; i++) {
|
||||
msg->msg.in_size[i] = invec[i].len;
|
||||
msg->invec[i].base = invec[i].base;
|
||||
}
|
||||
|
||||
for (i = 0; i < out_len; i++) {
|
||||
msg->msg.out_size[i] = outvec[i].len;
|
||||
msg->outvec[i].base = outvec[i].base;
|
||||
/* Out len is used to record the writed number, set 0 here again */
|
||||
msg->outvec[i].len = 0;
|
||||
}
|
||||
|
||||
/* Use message address as handle */
|
||||
msg->msg.handle = (psa_handle_t)msg;
|
||||
|
||||
/* For connected handle, set rhandle to every message */
|
||||
if (handle != PSA_NULL_HANDLE) {
|
||||
msg->msg.rhandle = tfm_spm_get_rhandle(service, handle);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
void tfm_spm_free_msg(struct tfm_msg_body_t *msg)
|
||||
{
|
||||
tfm_pool_free(msg);
|
||||
}
|
||||
|
||||
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
|
||||
struct tfm_msg_body_t *msg)
|
||||
{
|
||||
TFM_ASSERT(service);
|
||||
TFM_ASSERT(msg);
|
||||
|
||||
/* Enqueue message to service message queue */
|
||||
if (tfm_msg_enqueue(&service->msg_queue, msg) != IPC_SUCCESS) {
|
||||
return IPC_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
/* Messages put. Update signals */
|
||||
service->partition->signals |= service->service_db->signal;
|
||||
|
||||
/* Save return value for blocked threads */
|
||||
tfm_event_owner_retval(&service->partition->signal_event,
|
||||
service->partition->signals &
|
||||
service->partition->signal_mask);
|
||||
|
||||
/* Wake waiting thread up */
|
||||
tfm_event_signal(&service->partition->signal_event);
|
||||
|
||||
tfm_event_wait(&msg->ack_mtx);
|
||||
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
/* SPM extend functions */
|
||||
uint32_t tfm_spm_partition_get_running_partition_id_ext(void)
|
||||
{
|
||||
struct tfm_thrd_ctx *pth = tfm_thrd_curr_thread();
|
||||
struct spm_partition_desc_t *partition;
|
||||
|
||||
partition = TFM_GET_CONTAINER_PTR(pth, struct spm_partition_desc_t,
|
||||
sp_thrd);
|
||||
return partition->static_data.partition_id;
|
||||
}
|
||||
|
||||
static struct tfm_thrd_ctx *
|
||||
tfm_spm_partition_get_thread_info_ext(uint32_t partition_idx)
|
||||
{
|
||||
return &g_spm_partition_db.partitions[partition_idx].sp_thrd;
|
||||
}
|
||||
|
||||
static uint32_t tfm_spm_partition_get_stack_size_ext(uint32_t partition_idx)
|
||||
{
|
||||
return g_spm_partition_db.partitions[partition_idx].stack_size;
|
||||
}
|
||||
|
||||
static uint32_t tfm_spm_partition_get_stack_limit_ext(uint32_t partition_idx)
|
||||
{
|
||||
return g_spm_partition_db.partitions[partition_idx].stack_limit;
|
||||
}
|
||||
|
||||
static uint32_t tfm_spm_partition_get_stack_base_ext(uint32_t partition_idx)
|
||||
{
|
||||
return tfm_spm_partition_get_stack_limit_ext(partition_idx) + tfm_spm_partition_get_stack_size_ext(partition_idx);
|
||||
}
|
||||
|
||||
static tfm_thrd_func_t
|
||||
tfm_spm_partition_get_init_func_ext(uint32_t partition_idx)
|
||||
{
|
||||
return (tfm_thrd_func_t)(g_spm_partition_db.partitions[partition_idx].
|
||||
static_data.partition_init);
|
||||
}
|
||||
|
||||
static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx)
|
||||
{
|
||||
return g_spm_partition_db.partitions[partition_idx].static_data.
|
||||
partition_priority;
|
||||
}
|
||||
|
||||
/* Macros to pick linker symbols and allow references to sections in all level*/
|
||||
#define REGION_DECLARE_EXT(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
||||
|
||||
REGION_DECLARE_EXT(Image$$, ARM_LIB_HEAP, $$ZI$$Base);
|
||||
REGION_DECLARE_EXT(Image$$, ARM_LIB_HEAP, $$ZI$$Limit);
|
||||
REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$Base);
|
||||
REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$Limit);
|
||||
REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||
REGION_DECLARE_EXT(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||
REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||
REGION_DECLARE_EXT(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
|
||||
|
||||
/*
|
||||
* \brief Check the memory whether in the given range.
|
||||
*
|
||||
* \param[in] buffer Pointer of memory reference
|
||||
* \param[in] len Length of memory reference in bytes
|
||||
* \param[in] base The base address
|
||||
* \param[in] limit The limit address, the first byte of next
|
||||
* area memory
|
||||
*
|
||||
* \retval IPC_SUCCESS Success
|
||||
* \retval IPC_ERROR_MEMORY_CHECK Check failed
|
||||
*/
|
||||
static int32_t memory_check_range(const void *buffer, size_t len,
|
||||
uintptr_t base, uintptr_t limit)
|
||||
{
|
||||
if (((uintptr_t)buffer >= base) &&
|
||||
((uintptr_t)((uint8_t *)buffer + len - 1) < limit)) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
return IPC_ERROR_MEMORY_CHECK;
|
||||
}
|
||||
|
||||
/* FixMe: This is only valid for TFM LVL 1 now */
|
||||
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller)
|
||||
{
|
||||
uintptr_t base, limit;
|
||||
|
||||
/* If len is zero, this indicates an empty buffer and base is ignored */
|
||||
if (len == 0) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
return IPC_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
|
||||
return IPC_ERROR_MEMORY_CHECK;
|
||||
}
|
||||
|
||||
if (ns_caller) {
|
||||
base = (uintptr_t)NS_DATA_START;
|
||||
limit = (uintptr_t)(NS_DATA_START + NS_DATA_SIZE);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
base = (uintptr_t)NS_CODE_START;
|
||||
limit = (uintptr_t)(NS_CODE_START + NS_CODE_SIZE);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
base = (uintptr_t)®ION_NAME(Image$$, ARM_LIB_HEAP, $$ZI$$Base);
|
||||
limit = (uintptr_t)®ION_NAME(Image$$, ARM_LIB_HEAP, $$ZI$$Limit);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
base = (uintptr_t)®ION_NAME(Image$$, ER_TFM_DATA, $$Base);
|
||||
limit = (uintptr_t)®ION_NAME(Image$$, ER_TFM_DATA, $$Limit);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
base = (uintptr_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||
limit = (uintptr_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
base = (uintptr_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||
limit = (uintptr_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH,
|
||||
$$ZI$$Limit);
|
||||
if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) {
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return IPC_ERROR_MEMORY_CHECK;
|
||||
}
|
||||
|
||||
/********************** SPM functions for thread mode ************************/
|
||||
|
||||
void tfm_spm_init(void)
|
||||
{
|
||||
uint32_t i, num;
|
||||
struct tfm_spm_ipc_partition_t *partition;
|
||||
struct tfm_spm_service_t *service;
|
||||
struct tfm_thrd_ctx *pth;
|
||||
|
||||
tfm_pool_init(conn_handle_pool,
|
||||
POOL_BUFFER_SIZE(conn_handle_pool),
|
||||
sizeof(struct tfm_conn_handle_t),
|
||||
TFM_CONN_HANDLE_MAX_NUM);
|
||||
tfm_pool_init(spm_service_pool, POOL_BUFFER_SIZE(spm_service_pool),
|
||||
sizeof(struct tfm_spm_service_t),
|
||||
TFM_SPM_MAX_ROT_SERV_NUM);
|
||||
tfm_pool_init(msg_db_pool, POOL_BUFFER_SIZE(msg_db_pool),
|
||||
sizeof(struct tfm_msg_body_t),
|
||||
TFM_MSG_QUEUE_MAX_MSG_NUM);
|
||||
|
||||
/* Init partition first for it will be used when init service */
|
||||
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
|
||||
if ((tfm_spm_partition_get_flags(i) & SPM_PART_FLAG_IPC) == 0) {
|
||||
continue;
|
||||
}
|
||||
g_spm_ipc_partition[i].index = i;
|
||||
g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
|
||||
tfm_event_init(&g_spm_ipc_partition[i].signal_event, EVENT_STAT_WAITED);
|
||||
tfm_list_init(&g_spm_ipc_partition[i].service_list);
|
||||
|
||||
pth = tfm_spm_partition_get_thread_info_ext(i);
|
||||
if (!pth) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
tfm_thrd_init(pth,
|
||||
tfm_spm_partition_get_init_func_ext(i),
|
||||
NULL,
|
||||
(uint8_t *)tfm_spm_partition_get_stack_base_ext(i),
|
||||
(uint8_t *)tfm_spm_partition_get_stack_limit_ext(i));
|
||||
pth->prior = tfm_spm_partition_get_priority_ext(i);
|
||||
|
||||
/* Kick off */
|
||||
if (tfm_thrd_start(pth) != THRD_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
}
|
||||
|
||||
/* Init Service */
|
||||
num = sizeof(g_spm_service_db) / sizeof(struct tfm_spm_service_db_t);
|
||||
for (i = 0; i < num; i++) {
|
||||
partition =
|
||||
tfm_spm_get_partition_by_id(g_spm_service_db[i].partition_id);
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
service = (struct tfm_spm_service_t *)tfm_pool_alloc(spm_service_pool);
|
||||
if (!service) {
|
||||
tfm_panic();
|
||||
}
|
||||
service->service_db = &g_spm_service_db[i];
|
||||
service->partition = partition;
|
||||
tfm_list_init(&service->handle_list);
|
||||
tfm_list_add_tail(&partition->service_list, &service->list);
|
||||
}
|
||||
|
||||
/* All thread inited.... trigger scheduler */
|
||||
tfm_thrd_activate_schedule();
|
||||
}
|
||||
|
|
@ -0,0 +1,976 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "tfm_svc.h"
|
||||
#include "tfm_svcalls.h"
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_wait.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "tfm_internal_defines.h"
|
||||
#include "tfm_message_queue.h"
|
||||
#include "tfm_spm.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_api.h"
|
||||
#include "tfm_secure_api.h"
|
||||
|
||||
#define PSA_TIMEOUT_MASK PSA_BLOCK
|
||||
|
||||
/************************* SVC handler for PSA Client APIs *******************/
|
||||
|
||||
uint32_t tfm_svcall_psa_framework_version(void)
|
||||
{
|
||||
return PSA_FRAMEWORK_VERSION;
|
||||
}
|
||||
|
||||
uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller)
|
||||
{
|
||||
uint32_t sid;
|
||||
struct tfm_spm_service_t *service;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
sid = (uint32_t)args[0];
|
||||
/*
|
||||
* It should return PSA_VERSION_NONE if the RoT Service is not
|
||||
* implemented.
|
||||
*/
|
||||
service = tfm_spm_get_service_by_sid(sid);
|
||||
if (!service) {
|
||||
return PSA_VERSION_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* It should return PSA_VERSION_NONE if the caller is not authorized
|
||||
* to access the RoT Service.
|
||||
*/
|
||||
if (ns_caller && !service->service_db->non_secure_client) {
|
||||
return PSA_VERSION_NONE;
|
||||
}
|
||||
|
||||
return service->service_db->minor_version;
|
||||
}
|
||||
|
||||
psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller)
|
||||
{
|
||||
uint32_t sid;
|
||||
uint32_t minor_version;
|
||||
struct tfm_spm_service_t *service;
|
||||
struct tfm_msg_body_t *msg;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
sid = (uint32_t)args[0];
|
||||
minor_version = (uint32_t)args[1];
|
||||
|
||||
/* It is a fatal error if the RoT Service does not exist on the platform */
|
||||
service = tfm_spm_get_service_by_sid(sid);
|
||||
if (!service) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the caller is not authorized to access the RoT
|
||||
* Service.
|
||||
*/
|
||||
if (ns_caller && !service->service_db->non_secure_client) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the version of the RoT Service requested is not
|
||||
* supported on the platform.
|
||||
*/
|
||||
if (tfm_spm_check_client_version(service, minor_version) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* No input or output needed for connect message */
|
||||
msg = tfm_spm_create_msg(service, PSA_NULL_HANDLE, PSA_IPC_CONNECT,
|
||||
ns_caller, NULL, 0, NULL, 0, NULL);
|
||||
if (!msg) {
|
||||
return PSA_NULL_HANDLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send message and wake up the SP who is waiting on message queue,
|
||||
* and scheduler triggered
|
||||
*/
|
||||
tfm_spm_send_event(service, msg);
|
||||
|
||||
return PSA_NULL_HANDLE;
|
||||
}
|
||||
|
||||
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller)
|
||||
{
|
||||
psa_handle_t handle;
|
||||
psa_invec *inptr, invecs[PSA_MAX_IOVEC];
|
||||
psa_outvec *outptr, outvecs[PSA_MAX_IOVEC];
|
||||
size_t in_num, out_num;
|
||||
struct tfm_spm_service_t *service;
|
||||
struct tfm_msg_body_t *msg;
|
||||
int i;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
handle = (psa_handle_t)args[0];
|
||||
if (!ns_caller) {
|
||||
inptr = (psa_invec *)args[1];
|
||||
in_num = (size_t)args[2];
|
||||
outptr = (psa_outvec *)args[3];
|
||||
/*
|
||||
* FixMe: 5th parameter is pushed at stack top before SVC; plus
|
||||
* exception stacked contents, 5th parameter is now at 8th position
|
||||
* in SVC handler. However, if thread mode applies FloatPoint, then
|
||||
* FloatPoint context is pushed into stack and then 5th parameter
|
||||
* will not be args[8].
|
||||
* Will refine it later.
|
||||
*/
|
||||
out_num = (size_t)args[8];
|
||||
} else {
|
||||
/*
|
||||
* FixMe: From non-secure caller, vec and len are composed into a new
|
||||
* struct parameter. Need to extract them.
|
||||
*/
|
||||
if (tfm_memory_check((void *)args[1], sizeof(uint32_t),
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
if (tfm_memory_check((void *)args[2], sizeof(uint32_t),
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
inptr = (psa_invec *)((psa_invec *)args[1])->base;
|
||||
in_num = ((psa_invec *)args[1])->len;
|
||||
outptr = (psa_outvec *)((psa_invec *)args[2])->base;
|
||||
out_num = ((psa_invec *)args[2])->len;
|
||||
}
|
||||
|
||||
/* It is a fatal error if in_len + out_len > PSA_MAX_IOVEC. */
|
||||
if (in_num + out_num > PSA_MAX_IOVEC) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* It is a fatal error if an invalid handle was passed. */
|
||||
service = tfm_spm_get_service_by_handle(handle);
|
||||
if (!service) {
|
||||
/* FixMe: Need to implement one mechanism to resolve this failure. */
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* It is a fatal error if an invalid memory reference was provide. */
|
||||
if (tfm_memory_check((void *)inptr, in_num * sizeof(psa_invec),
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
if (tfm_memory_check((void *)outptr, out_num * sizeof(psa_outvec),
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
tfm_memset(invecs, 0, sizeof(invecs));
|
||||
tfm_memset(outvecs, 0, sizeof(outvecs));
|
||||
|
||||
/* Copy the address out to avoid TOCTOU attacks. */
|
||||
tfm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
|
||||
tfm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
|
||||
|
||||
/*
|
||||
* It is a fatal error if an invalid payload memory reference
|
||||
* was provided.
|
||||
*/
|
||||
for (i = 0; i < in_num; i++) {
|
||||
if (tfm_memory_check((void *)invecs[i].base, invecs[i].len,
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
}
|
||||
for (i = 0; i < out_num; i++) {
|
||||
if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
|
||||
ns_caller) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FixMe: Need to check if the message is unrecognized by the RoT
|
||||
* Service or incorrectly formatted.
|
||||
*/
|
||||
msg = tfm_spm_create_msg(service, handle, PSA_IPC_CALL, ns_caller, invecs,
|
||||
in_num, outvecs, out_num, outptr);
|
||||
if (!msg) {
|
||||
/* FixMe: Need to implement one mechanism to resolve this failure. */
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* Send message and wake up the SP who is waiting on message queue,
|
||||
* and scheduler triggered
|
||||
*/
|
||||
if (tfm_spm_send_event(service, msg) != IPC_SUCCESS) {
|
||||
/* FixMe: Need to refine failure process here. */
|
||||
tfm_panic();
|
||||
}
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller)
|
||||
{
|
||||
psa_handle_t handle;
|
||||
struct tfm_spm_service_t *service;
|
||||
struct tfm_msg_body_t *msg;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
handle = args[0];
|
||||
/* It will have no effect if called with the NULL handle */
|
||||
if (handle == PSA_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if an invalid handle was provided that is not the
|
||||
* null handle..
|
||||
*/
|
||||
service = tfm_spm_get_service_by_handle(handle);
|
||||
if (!service) {
|
||||
/* FixMe: Need to implement one mechanism to resolve this failure. */
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* No input or output needed for close message */
|
||||
msg = tfm_spm_create_msg(service, handle, PSA_IPC_DISCONNECT, ns_caller,
|
||||
NULL, 0, NULL, 0, NULL);
|
||||
if (!msg) {
|
||||
/* FixMe: Need to implement one mechanism to resolve this failure. */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send message and wake up the SP who is waiting on message queue,
|
||||
* and scheduler triggered
|
||||
*/
|
||||
tfm_spm_send_event(service, msg);
|
||||
|
||||
/* Service handle is not used anymore */
|
||||
tfm_spm_free_conn_handle(service, handle);
|
||||
}
|
||||
|
||||
/*********************** SVC handler for PSA Service APIs ********************/
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_wait.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* signal_mask, timeout.
|
||||
*
|
||||
* \retval >0 At least one signal is asserted.
|
||||
* \retval 0 No signals are asserted. This is only seen when
|
||||
* a polling timeout is used.
|
||||
*/
|
||||
static psa_signal_t tfm_svcall_psa_wait(uint32_t *args)
|
||||
{
|
||||
psa_signal_t signal_mask;
|
||||
uint32_t timeout;
|
||||
struct tfm_spm_ipc_partition_t *partition = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
signal_mask = (psa_signal_t)args[0];
|
||||
timeout = args[1];
|
||||
|
||||
/*
|
||||
* Timeout[30:0] are reserved for future use.
|
||||
* SPM must ignore the value of RES.
|
||||
*/
|
||||
timeout &= PSA_TIMEOUT_MASK;
|
||||
|
||||
partition = tfm_spm_get_running_partition();
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expected signals are included in signal wait mask, ignored signals
|
||||
* should not be set and affect caller thread status. Save this mask for
|
||||
* further checking while signals are ready to be set.
|
||||
*/
|
||||
partition->signal_mask = signal_mask;
|
||||
|
||||
/*
|
||||
* tfm_event_wait() blocks the caller thread if no signals are available.
|
||||
* In this case, the return value of this function is temporary set into
|
||||
* runtime context. After new signal(s) are available, the return value
|
||||
* is updated with the available signal(s) and blocked thread gets to run.
|
||||
*/
|
||||
if ((timeout == PSA_BLOCK) && ((partition->signals & signal_mask) == 0)) {
|
||||
tfm_event_wait(&partition->signal_event);
|
||||
}
|
||||
|
||||
return partition->signals & signal_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_get.
|
||||
*
|
||||
* \param[in] args Include all input arguments: signal, msg.
|
||||
*
|
||||
* \retval PSA_SUCCESS Success, *msg will contain the delivered
|
||||
* message.
|
||||
* \retval PSA_ERR_NOMSG Message could not be delivered.
|
||||
* \retval "Does not return" The call is invalid because one or more of the
|
||||
* following are true:
|
||||
* \arg signal has more than a single bit set.
|
||||
* \arg signal does not correspond to a RoT Service.
|
||||
* \arg The RoT Service signal is not currently
|
||||
* asserted.
|
||||
* \arg The msg pointer provided is not a valid memory
|
||||
* reference.
|
||||
*/
|
||||
static psa_status_t tfm_svcall_psa_get(uint32_t *args)
|
||||
{
|
||||
psa_signal_t signal;
|
||||
psa_msg_t *msg = NULL;
|
||||
struct tfm_spm_service_t *service = NULL;
|
||||
struct tfm_msg_body_t *tmp_msg = NULL;
|
||||
struct tfm_spm_ipc_partition_t *partition = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
signal = (psa_signal_t)args[0];
|
||||
msg = (psa_msg_t *)args[1];
|
||||
|
||||
/*
|
||||
* Only one message could be retrieved every time for psa_get(). It is a
|
||||
* fatal error if the input signal has more than a signal bit set.
|
||||
*/
|
||||
if (tfm_bitcount(signal) != 1) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the input msg pointer is not a valid memory
|
||||
* reference.
|
||||
*/
|
||||
if (tfm_memory_check((void *)msg, sizeof(psa_msg_t),
|
||||
false) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
partition = tfm_spm_get_running_partition();
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the caller call psa_get() when no message has
|
||||
* been set. The caller must call this function after a RoT Service signal
|
||||
* is returned by psa_wait().
|
||||
*/
|
||||
if (partition->signals == 0) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the RoT Service signal is not currently asserted.
|
||||
*/
|
||||
if ((partition->signals & signal) == 0) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get Rot service by signal from partition. It is a fatal error if geting
|
||||
* failed which mean the input signal is not correspond to a RoT service.
|
||||
*/
|
||||
service = tfm_spm_get_service_by_signal(partition, signal);
|
||||
if (!service) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
tmp_msg = tfm_msg_dequeue(&service->msg_queue);
|
||||
if (!tmp_msg) {
|
||||
return PSA_ERR_NOMSG;
|
||||
}
|
||||
|
||||
tfm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));
|
||||
|
||||
/*
|
||||
* There may be mutiple messages for this RoT Service signal, do not clear
|
||||
* its mask until no remaining message.
|
||||
*/
|
||||
if (tfm_msg_queue_is_empty(&service->msg_queue)) {
|
||||
partition->signals &= ~signal;
|
||||
}
|
||||
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_set_rhandle.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* msg_handle, rhandle.
|
||||
*
|
||||
* \retval void Success, rhandle will be provided with all
|
||||
* subsequent messages delivered on this
|
||||
* connection.
|
||||
* \retval "Does not return" msg_handle is invalid.
|
||||
*/
|
||||
static void tfm_svcall_psa_set_rhandle(uint32_t *args)
|
||||
{
|
||||
psa_handle_t msg_handle;
|
||||
void *rhandle = NULL;
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
msg_handle = (psa_handle_t)args[0];
|
||||
rhandle = (void *)args[1];
|
||||
|
||||
/* It is a fatal error if message handle is invalid */
|
||||
msg = tfm_spm_get_msg_from_handle(msg_handle);
|
||||
if (!msg) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* Connection handle is not created while SP is processing PSA_IPC_CONNECT
|
||||
* message. Store reverse handle temporarily and re-set it after the
|
||||
* connection created.
|
||||
*/
|
||||
if (msg->handle != PSA_NULL_HANDLE) {
|
||||
tfm_spm_set_rhandle(msg->service, msg->handle, rhandle);
|
||||
} else {
|
||||
msg->msg.rhandle = rhandle;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_read.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* msg_handle, invec_idx, buffer, num_bytes.
|
||||
*
|
||||
* \retval >0 Number of bytes copied.
|
||||
* \retval 0 There was no remaining data in this input
|
||||
* vector.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg invec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
* \arg the memory reference for buffer is invalid or
|
||||
* not writable.
|
||||
*/
|
||||
static size_t tfm_svcall_psa_read(uint32_t *args)
|
||||
{
|
||||
psa_handle_t msg_handle;
|
||||
uint32_t invec_idx;
|
||||
void *buffer = NULL;
|
||||
size_t num_bytes;
|
||||
size_t bytes;
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
msg_handle = (psa_handle_t)args[0];
|
||||
invec_idx = args[1];
|
||||
buffer = (void *)args[2];
|
||||
num_bytes = (size_t)args[3];
|
||||
|
||||
/* It is a fatal error if message handle is invalid */
|
||||
msg = tfm_spm_get_msg_from_handle(msg_handle);
|
||||
if (!msg) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if message handle does not refer to a PSA_IPC_CALL
|
||||
* message
|
||||
*/
|
||||
if (msg->msg.type != PSA_IPC_CALL) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if invec_idx is equal to or greater than
|
||||
* PSA_MAX_IOVEC
|
||||
*/
|
||||
if (invec_idx >= PSA_MAX_IOVEC) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* There was no remaining data in this input vector */
|
||||
if (msg->msg.in_size[invec_idx] == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the memory reference for buffer is invalid or
|
||||
* not writable
|
||||
*/
|
||||
/* FixMe: write permission check to be added */
|
||||
if (tfm_memory_check(buffer, num_bytes, false) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
bytes = num_bytes > msg->msg.in_size[invec_idx] ?
|
||||
msg->msg.in_size[invec_idx] : num_bytes;
|
||||
|
||||
tfm_memcpy(buffer, msg->invec[invec_idx].base, bytes);
|
||||
|
||||
/* There maybe some remaining data */
|
||||
msg->invec[invec_idx].base += bytes;
|
||||
msg->msg.in_size[invec_idx] -= bytes;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_skip.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* msg_handle, invec_idx, num_bytes.
|
||||
*
|
||||
* \retval >0 Number of bytes skipped.
|
||||
* \retval 0 There was no remaining data in this input
|
||||
* vector.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg invec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
*/
|
||||
static size_t tfm_svcall_psa_skip(uint32_t *args)
|
||||
{
|
||||
psa_handle_t msg_handle;
|
||||
uint32_t invec_idx;
|
||||
size_t num_bytes;
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
msg_handle = (psa_handle_t)args[0];
|
||||
invec_idx = args[1];
|
||||
num_bytes = (size_t)args[2];
|
||||
|
||||
/* It is a fatal error if message handle is invalid */
|
||||
msg = tfm_spm_get_msg_from_handle(msg_handle);
|
||||
if (!msg) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if message handle does not refer to a PSA_IPC_CALL
|
||||
* message
|
||||
*/
|
||||
if (msg->msg.type != PSA_IPC_CALL) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if invec_idx is equal to or greater than
|
||||
* PSA_MAX_IOVEC
|
||||
*/
|
||||
if (invec_idx >= PSA_MAX_IOVEC) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* There was no remaining data in this input vector */
|
||||
if (msg->msg.in_size[invec_idx] == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If num_bytes is greater than the remaining size of the input vector then
|
||||
* the remaining size of the input vector is used.
|
||||
*/
|
||||
if (num_bytes > msg->msg.in_size[invec_idx]) {
|
||||
num_bytes = msg->msg.in_size[invec_idx];
|
||||
}
|
||||
|
||||
/* There maybe some remaining data */
|
||||
msg->invec[invec_idx].base += num_bytes;
|
||||
msg->msg.in_size[invec_idx] -= num_bytes;
|
||||
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_write.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* msg_handle, outvec_idx, buffer, num_bytes.
|
||||
*
|
||||
* \retval void Success
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg outvec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
* \arg The memory reference for buffer is invalid.
|
||||
* \arg The call attempts to write data past the end
|
||||
* of the client output vector.
|
||||
*/
|
||||
static void tfm_svcall_psa_write(uint32_t *args)
|
||||
{
|
||||
psa_handle_t msg_handle;
|
||||
uint32_t outvec_idx;
|
||||
void *buffer = NULL;
|
||||
size_t num_bytes;
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
msg_handle = (psa_handle_t)args[0];
|
||||
outvec_idx = args[1];
|
||||
buffer = (void *)args[2];
|
||||
num_bytes = (size_t)args[3];
|
||||
|
||||
/* It is a fatal error if message handle is invalid */
|
||||
msg = tfm_spm_get_msg_from_handle(msg_handle);
|
||||
if (!msg) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if message handle does not refer to a PSA_IPC_CALL
|
||||
* message
|
||||
*/
|
||||
if (msg->msg.type != PSA_IPC_CALL) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if outvec_idx is equal to or greater than
|
||||
* PSA_MAX_IOVEC
|
||||
*/
|
||||
if (outvec_idx >= PSA_MAX_IOVEC) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the call attempts to write data past the end of
|
||||
* the client output vector
|
||||
*/
|
||||
if (num_bytes > msg->msg.out_size[outvec_idx] -
|
||||
msg->outvec[outvec_idx].len) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* It is a fatal error if the memory reference for buffer is valid */
|
||||
if (tfm_memory_check(buffer, num_bytes, false) != IPC_SUCCESS) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
tfm_memcpy(msg->outvec[outvec_idx].base + msg->outvec[outvec_idx].len,
|
||||
buffer, num_bytes);
|
||||
|
||||
/* Update the write number */
|
||||
msg->outvec[outvec_idx].len += num_bytes;
|
||||
}
|
||||
|
||||
static void update_caller_outvec_len(struct tfm_msg_body_t *msg)
|
||||
{
|
||||
int32_t i = 0;
|
||||
|
||||
/*
|
||||
* FixeMe: abstract these part into dedicated functions to avoid
|
||||
* accessing thread context in psa layer
|
||||
*/
|
||||
TFM_ASSERT(msg->ack_mtx.owner->status == THRD_STAT_BLOCK);
|
||||
|
||||
while (msg->msg.out_size[i] != 0) {
|
||||
TFM_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
|
||||
msg->caller_outvec[i].len = msg->outvec[i].len;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_reply.
|
||||
*
|
||||
* \param[in] args Include all input arguments:
|
||||
* msg_handle, status.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg An invalid status code is specified for the
|
||||
* type of message.
|
||||
*/
|
||||
static void tfm_svcall_psa_reply(uint32_t *args)
|
||||
{
|
||||
psa_handle_t msg_handle;
|
||||
psa_status_t status;
|
||||
struct tfm_spm_service_t *service = NULL;
|
||||
struct tfm_msg_body_t *msg = NULL;
|
||||
psa_handle_t connect_handle;
|
||||
int32_t ret = PSA_SUCCESS;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
msg_handle = (psa_handle_t)args[0];
|
||||
status = (psa_status_t)args[1];
|
||||
|
||||
/* It is a fatal error if message handle is invalid */
|
||||
msg = tfm_spm_get_msg_from_handle(msg_handle);
|
||||
if (!msg) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* RoT Service information is needed in this function, stored it in message
|
||||
* body structure. Only two parameters are passed in this function: handle
|
||||
* and status, so it is useful and simply to do like this.
|
||||
*/
|
||||
service = msg->service;
|
||||
if (!service) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* Three type of message are passed in this function: CONNECT, CALL,
|
||||
* DISCONNECT. It needs to process differently for each type.
|
||||
*/
|
||||
switch (msg->msg.type) {
|
||||
case PSA_IPC_CONNECT:
|
||||
/*
|
||||
* Reply to PSA_IPC_CONNECT message. Connect handle is created if the
|
||||
* input status is PSA_SUCCESS. Others return values are based on the
|
||||
* input status.
|
||||
*/
|
||||
if (status == PSA_SUCCESS) {
|
||||
connect_handle = tfm_spm_create_conn_handle(service);
|
||||
if (connect_handle == PSA_NULL_HANDLE) {
|
||||
tfm_panic();
|
||||
}
|
||||
ret = connect_handle;
|
||||
|
||||
/* Set reverse handle after connection created if needed. */
|
||||
if (msg->msg.rhandle) {
|
||||
tfm_spm_set_rhandle(service, connect_handle, msg->msg.rhandle);
|
||||
}
|
||||
} else if (status == PSA_CONNECTION_REFUSED) {
|
||||
ret = PSA_CONNECTION_REFUSED;
|
||||
} else if (status == PSA_CONNECTION_BUSY) {
|
||||
ret = PSA_CONNECTION_BUSY;
|
||||
} else {
|
||||
tfm_panic();
|
||||
}
|
||||
break;
|
||||
case PSA_IPC_CALL:
|
||||
/* Reply to PSA_IPC_CALL message. Return values are based on status */
|
||||
if (status == PSA_SUCCESS) {
|
||||
ret = PSA_SUCCESS;
|
||||
} else if (status == PSA_DROP_CONNECTION) {
|
||||
ret = PSA_DROP_CONNECTION;
|
||||
} else if ((status >= (INT32_MIN + 1)) &&
|
||||
(status <= (INT32_MIN + 127))) {
|
||||
tfm_panic();
|
||||
} else if ((status >= (INT32_MIN + 128)) && (status <= -1)) {
|
||||
ret = status;
|
||||
} else if ((status >= 1) && (status <= INT32_MAX)) {
|
||||
ret = status;
|
||||
} else {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* The total number of bytes written to a single parameter must be
|
||||
* reported to the client by updating the len member of the psa_outvec
|
||||
* structure for the parameter before returning from psa_call().
|
||||
*/
|
||||
update_caller_outvec_len(msg);
|
||||
break;
|
||||
case PSA_IPC_DISCONNECT:
|
||||
/*
|
||||
* If the message type is PSA_IPC_DISCONNECT, then the status code is
|
||||
* ignored
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* Save return value for blocked threads */
|
||||
tfm_event_owner_retval(&msg->ack_mtx, ret);
|
||||
|
||||
/* Wake waiting thread up */
|
||||
tfm_event_signal(&msg->ack_mtx);
|
||||
|
||||
/* Message should not be unsed anymore */
|
||||
tfm_spm_free_msg(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_notify.
|
||||
*
|
||||
* \param[in] args Include all input arguments: partition_id.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" partition_id does not correspond to a Secure
|
||||
* Partition.
|
||||
*/
|
||||
static void tfm_svcall_psa_notify(uint32_t *args)
|
||||
{
|
||||
int32_t partition_id;
|
||||
struct tfm_spm_ipc_partition_t *partition = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
partition_id = (int32_t)args[0];
|
||||
|
||||
/*
|
||||
* The value of partition_id must be greater than zero as the target of
|
||||
* notification must be a Secure Partition, providing a Non-secure
|
||||
* Partition ID is a fatal error.
|
||||
*/
|
||||
if (!TFM_CLIENT_ID_IS_S(partition_id)) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if partition_id does not correspond to a Secure
|
||||
* Partition.
|
||||
*/
|
||||
partition = tfm_spm_get_partition_by_id(partition_id);
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
partition->signals |= PSA_DOORBELL;
|
||||
|
||||
/*
|
||||
* The target partition may be blocked with waiting for signals after
|
||||
* called psa_wait(). Set the return value with the available signals
|
||||
* before wake it up with tfm_event_signal().
|
||||
*/
|
||||
tfm_event_owner_retval(&partition->signal_event,
|
||||
partition->signals & partition->signal_mask);
|
||||
|
||||
/* Wake waiting thread up */
|
||||
tfm_event_signal(&partition->signal_event);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_clear.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The Secure Partition's doorbell signal is not
|
||||
* currently asserted.
|
||||
*/
|
||||
static void tfm_svcall_psa_clear(uint32_t *args)
|
||||
{
|
||||
struct tfm_spm_ipc_partition_t *partition = NULL;
|
||||
|
||||
partition = tfm_spm_get_running_partition();
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* It is a fatal error if the Secure Partition's doorbell signal is not
|
||||
* currently asserted.
|
||||
*/
|
||||
if ((partition->signals & PSA_DOORBELL) == 0) {
|
||||
tfm_panic();
|
||||
}
|
||||
partition->signals &= ~PSA_DOORBELL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief SVC handler for \ref psa_eoi.
|
||||
*
|
||||
* \param[in] args Include all input arguments: irq_signal.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg irq_signal is not an interrupt signal.
|
||||
* \arg irq_signal indicates more than one signal.
|
||||
* \arg irq_signal is not currently asserted.
|
||||
*/
|
||||
static void tfm_svcall_psa_eoi(uint32_t *args)
|
||||
{
|
||||
psa_signal_t irq_signal;
|
||||
struct tfm_spm_ipc_partition_t *partition = NULL;
|
||||
|
||||
TFM_ASSERT(args != NULL);
|
||||
irq_signal = (psa_signal_t)args[0];
|
||||
|
||||
partition = tfm_spm_get_running_partition();
|
||||
if (!partition) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/*
|
||||
* FixMe: It is a fatal error if passed signal is not an interrupt signal.
|
||||
*/
|
||||
|
||||
/* It is a fatal error if passed signal indicates more than one signals. */
|
||||
if (tfm_bitcount(partition->signals) != 1) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
/* It is a fatal error if passed signal is not currently asserted */
|
||||
if ((partition->signals & irq_signal) == 0) {
|
||||
tfm_panic();
|
||||
}
|
||||
|
||||
partition->signals &= ~irq_signal;
|
||||
|
||||
/* FixMe: re-enable interrupt */
|
||||
}
|
||||
|
||||
int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx)
|
||||
{
|
||||
switch (svc_num) {
|
||||
case TFM_SVC_SCHEDULE:
|
||||
tfm_thrd_activate_schedule();
|
||||
break;
|
||||
case TFM_SVC_PSA_FRAMEWORK_VERSION:
|
||||
return tfm_svcall_psa_framework_version();
|
||||
case TFM_SVC_PSA_VERSION:
|
||||
return tfm_svcall_psa_version(ctx, 0);
|
||||
case TFM_SVC_PSA_CONNECT:
|
||||
return tfm_svcall_psa_connect(ctx, 0);
|
||||
case TFM_SVC_PSA_CALL:
|
||||
return tfm_svcall_psa_call(ctx, 0);
|
||||
case TFM_SVC_PSA_CLOSE:
|
||||
tfm_svcall_psa_close(ctx, 0);
|
||||
break;
|
||||
case TFM_SVC_PSA_WAIT:
|
||||
return tfm_svcall_psa_wait(ctx);
|
||||
case TFM_SVC_PSA_GET:
|
||||
return tfm_svcall_psa_get(ctx);
|
||||
case TFM_SVC_PSA_SET_RHANDLE:
|
||||
tfm_svcall_psa_set_rhandle(ctx);
|
||||
break;
|
||||
case TFM_SVC_PSA_READ:
|
||||
return tfm_svcall_psa_read(ctx);
|
||||
case TFM_SVC_PSA_SKIP:
|
||||
return tfm_svcall_psa_skip(ctx);
|
||||
case TFM_SVC_PSA_WRITE:
|
||||
tfm_svcall_psa_write(ctx);
|
||||
break;
|
||||
case TFM_SVC_PSA_REPLY:
|
||||
tfm_svcall_psa_reply(ctx);
|
||||
break;
|
||||
case TFM_SVC_PSA_NOTIFY:
|
||||
tfm_svcall_psa_notify(ctx);
|
||||
break;
|
||||
case TFM_SVC_PSA_CLEAR:
|
||||
tfm_svcall_psa_clear(ctx);
|
||||
break;
|
||||
case TFM_SVC_PSA_EOI:
|
||||
tfm_svcall_psa_eoi(ctx);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return PSA_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_arch_v8m.h"
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "secure_utilities.h"
|
||||
|
||||
/* Force ZERO in case ZI(bss) clear is missing */
|
||||
static struct tfm_thrd_ctx *p_thrd_head = NULL;
|
||||
static struct tfm_thrd_ctx *p_runn_head = NULL;
|
||||
static struct tfm_thrd_ctx *p_curr_thrd = NULL;
|
||||
|
||||
/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
|
||||
#define LIST_HEAD p_thrd_head
|
||||
#define RUNN_HEAD p_runn_head
|
||||
#define CURR_THRD p_curr_thrd
|
||||
|
||||
/* To get next running thread for scheduler */
|
||||
struct tfm_thrd_ctx *tfm_thrd_next_thread(void)
|
||||
{
|
||||
struct tfm_thrd_ctx *pth = RUNN_HEAD;
|
||||
|
||||
/*
|
||||
* First RUNNING thread has highest priority since threads are sorted with
|
||||
* priority.
|
||||
*/
|
||||
while (pth && pth->status != THRD_STAT_RUNNING) {
|
||||
pth = pth->next;
|
||||
}
|
||||
|
||||
return pth;
|
||||
}
|
||||
|
||||
/* To get current thread for caller */
|
||||
struct tfm_thrd_ctx *tfm_thrd_curr_thread()
|
||||
{
|
||||
return CURR_THRD;
|
||||
}
|
||||
|
||||
/* Insert a new thread into list by descending priority (Highest at head) */
|
||||
static void insert_by_prior(struct tfm_thrd_ctx **head,
|
||||
struct tfm_thrd_ctx *node)
|
||||
{
|
||||
if (*head == NULL || (node->prior <= (*head)->prior)) {
|
||||
node->next = *head;
|
||||
*head = node;
|
||||
} else {
|
||||
struct tfm_thrd_ctx *iter = *head;
|
||||
|
||||
while (iter->next && (node->prior > iter->next->prior)) {
|
||||
iter = iter->next;
|
||||
}
|
||||
node->next = iter->next;
|
||||
iter->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set first running thread as head to reduce enumerate
|
||||
* depth while searching for a first running thread.
|
||||
*/
|
||||
static void update_running_head(struct tfm_thrd_ctx **runn,
|
||||
struct tfm_thrd_ctx *node)
|
||||
{
|
||||
if ((node->status == THRD_STAT_RUNNING) &&
|
||||
(*runn == NULL || (node->prior <= (*runn)->prior))) {
|
||||
*runn = node;
|
||||
} else {
|
||||
*runn = tfm_thrd_next_thread();
|
||||
}
|
||||
}
|
||||
|
||||
/* Set context members only. No validation here */
|
||||
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
|
||||
tfm_thrd_func_t pfn, void *param,
|
||||
uint8_t *sp_base, uint8_t *sp_top)
|
||||
{
|
||||
pth->prior = THRD_PRIOR_MEDIUM;
|
||||
pth->status = THRD_STAT_CREATING;
|
||||
pth->pfn = pfn;
|
||||
pth->param = param;
|
||||
pth->sp_base = sp_base;
|
||||
pth->sp_top = sp_top;
|
||||
}
|
||||
|
||||
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth)
|
||||
{
|
||||
/* Validate parameters before really start */
|
||||
if ((pth->status != THRD_STAT_CREATING) ||
|
||||
(pth->pfn == NULL) ||
|
||||
(pth->sp_base == NULL) ||
|
||||
(pth->sp_top == NULL)) {
|
||||
return THRD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
/* Thread management runs in handler mode; set context for thread mode. */
|
||||
tfm_initialize_context(&pth->state_ctx,
|
||||
(uint32_t)pth->param, (uint32_t)pth->pfn,
|
||||
(uint32_t)pth->sp_base, (uint32_t)pth->sp_top);
|
||||
|
||||
/* Insert a new thread with priority */
|
||||
insert_by_prior(&LIST_HEAD, pth);
|
||||
|
||||
/* Mark it as RUNNING after insertion */
|
||||
tfm_thrd_set_status(pth, THRD_STAT_RUNNING);
|
||||
|
||||
return THRD_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status)
|
||||
{
|
||||
TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID);
|
||||
|
||||
pth->status = new_status;
|
||||
update_running_head(&RUNN_HEAD, pth);
|
||||
}
|
||||
|
||||
/*
|
||||
* TEMP WORKAROUND: The caller function who called thread module init needs to
|
||||
* be returned. The caller is not a thread. Create a dummy IDLE thread to
|
||||
* collect caller context; and schedule back to the caller with this context
|
||||
* after all other real threads blocked.
|
||||
*
|
||||
* This WORKAROUND needs to be removed after IPC NSPM takes place.
|
||||
*/
|
||||
#define DUMMY_IDLE_TAG 0xDEEDDEED
|
||||
static uint8_t idle_stack[32] __attribute__((aligned(8)));
|
||||
static struct tfm_thrd_ctx idle_thread;
|
||||
static struct tfm_thrd_ctx *init_idle_thread(struct tfm_thrd_ctx *pth)
|
||||
{
|
||||
/*
|
||||
* IDLE thread is a thread with the lowest priority.
|
||||
* It gets scheduled after all other higher priority threads get blocked.
|
||||
* The entry of IDLE thread is a dummy and has no mean.
|
||||
*/
|
||||
tfm_thrd_init(pth, (tfm_thrd_func_t)DUMMY_IDLE_TAG, NULL,
|
||||
(uint8_t *)&idle_stack[32], (uint8_t *)idle_stack);
|
||||
tfm_thrd_priority(pth, THRD_PRIOR_LOWEST);
|
||||
tfm_thrd_start(pth);
|
||||
return pth;
|
||||
}
|
||||
|
||||
/* Scheduling won't happen immediately but after the exception returns */
|
||||
void tfm_thrd_activate_schedule(void)
|
||||
{
|
||||
/*
|
||||
* The current thread can be NULL only when initializing. Create the IDLE
|
||||
* thread and set it as the current thread to collect caller context.
|
||||
*/
|
||||
if (CURR_THRD == NULL) {
|
||||
CURR_THRD = init_idle_thread(&idle_thread);
|
||||
}
|
||||
|
||||
tfm_trigger_pendsv();
|
||||
}
|
||||
|
||||
/* Remove current thread out of the schedulable list */
|
||||
void tfm_thrd_do_exit(void)
|
||||
{
|
||||
CURR_THRD->status = THRD_STAT_DETACH;
|
||||
tfm_trigger_pendsv();
|
||||
}
|
||||
|
||||
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
|
||||
struct tfm_thrd_ctx *prev,
|
||||
struct tfm_thrd_ctx *next)
|
||||
{
|
||||
/* Update latest context into the current thread context */
|
||||
tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
|
||||
/* Update background context with next thread's context */
|
||||
tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
|
||||
/* Set current thread indicator with next thread */
|
||||
CURR_THRD = next;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is a reference implementation for PendSV handler in
|
||||
* isolation level 1. More jobs (sandboxing e.g.) need to be done while
|
||||
* scheduling in other isolation levels.
|
||||
*/
|
||||
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb)
|
||||
{
|
||||
struct tfm_thrd_ctx *pth = tfm_thrd_next_thread();
|
||||
|
||||
/* Swith context if another thread ready to run */
|
||||
if (pth && pth != CURR_THRD) {
|
||||
tfm_thrd_context_switch(ctxb, CURR_THRD, pth);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_utils.h"
|
||||
|
||||
void tfm_panic(void)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
int32_t tfm_bitcount(uint32_t n)
|
||||
{
|
||||
int32_t count = 0;
|
||||
uint8_t tmp;
|
||||
|
||||
while (n) {
|
||||
tmp = n & 0xFF;
|
||||
while (tmp) {
|
||||
count += tmp & 0x1;
|
||||
tmp >>= 1;
|
||||
}
|
||||
n >>= 8;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include "tfm_arch_v8m.h"
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_utils.h"
|
||||
#include "tfm_wait.h"
|
||||
|
||||
void tfm_event_wait(struct tfm_event_ctx *pevt)
|
||||
{
|
||||
struct tfm_thrd_ctx *curr_thrd = tfm_thrd_curr_thread();
|
||||
|
||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
||||
|
||||
if (pevt->status == EVENT_STAT_WAITED) {
|
||||
pevt->owner = curr_thrd;
|
||||
pevt->retval = TFM_STATE_1ST_ARG(&pevt->owner->state_ctx);
|
||||
tfm_thrd_set_status(pevt->owner, THRD_STAT_BLOCK);
|
||||
tfm_thrd_activate_schedule();
|
||||
}
|
||||
|
||||
pevt->status = EVENT_STAT_WAITED;
|
||||
}
|
||||
|
||||
/* Peek the status to see if caller would block. */
|
||||
uint32_t tfm_event_peek(struct tfm_event_ctx *pevt)
|
||||
{
|
||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
||||
|
||||
return pevt->status;
|
||||
}
|
||||
|
||||
void tfm_event_signal(struct tfm_event_ctx *pevt)
|
||||
{
|
||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
||||
|
||||
pevt->status = EVENT_STAT_SIGNALED;
|
||||
|
||||
/*
|
||||
* Wake the blocked owner up and keep the status as EVENT_STAT_WAITED
|
||||
* if there is an owner. Or the second event wait caller will return
|
||||
* without block since status is EVENT_STAT_SIGNALED.
|
||||
*/
|
||||
if (pevt->owner && pevt->owner->status == THRD_STAT_BLOCK) {
|
||||
tfm_thrd_set_status(pevt->owner, THRD_STAT_RUNNING);
|
||||
tfm_thrd_set_retval(pevt->owner, pevt->retval);
|
||||
pevt->status = EVENT_STAT_WAITED;
|
||||
tfm_thrd_activate_schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void tfm_event_owner_retval(struct tfm_event_ctx *pmtx, uint32_t retval)
|
||||
{
|
||||
TFM_ASSERT(pmtx && pmtx->magic == EVENT_MAGIC);
|
||||
|
||||
pmtx->retval = retval;
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SECURE_UTILITIES_H__
|
||||
#define __SECURE_UTILITIES_H__
|
||||
|
||||
#include "cmsis_compiler.h"
|
||||
#include "tfm_svc.h"
|
||||
#include "string.h"
|
||||
|
||||
#define EXC_RETURN_INDICATOR (0xF << 28)
|
||||
#define EXC_RETURN_SECURITY_STACK_STATUS_MASK (0x3 << 5)
|
||||
#define EXC_RETURN_SECURE_STACK (1 << 6)
|
||||
#define EXC_RETURN_FPU_FRAME_BASIC (1 << 4)
|
||||
#define EXC_RETURN_MODE_THREAD (1 << 3)
|
||||
#define EXC_RETURN_STACK_PROCESS (1 << 2)
|
||||
#define EXC_RETURN_EXC_SECURE (1)
|
||||
|
||||
#define EXC_NUM_THREAD_MODE (0)
|
||||
#define EXC_NUM_SVCALL (11)
|
||||
#define EXC_NUM_PENDSV (14)
|
||||
#define EXC_NUM_SYSTICK (15)
|
||||
|
||||
#define printf(...)
|
||||
|
||||
/* Disable NS exceptions by setting NS PRIMASK to 1 */
|
||||
#define TFM_NS_EXC_DISABLE() __TZ_set_PRIMASK_NS(1)
|
||||
/* Enable NS exceptions by setting NS PRIMASK to 0 */
|
||||
#define TFM_NS_EXC_ENABLE() __TZ_set_PRIMASK_NS(0)
|
||||
|
||||
struct tfm_exc_stack_t {
|
||||
uint32_t R0;
|
||||
uint32_t R1;
|
||||
uint32_t R2;
|
||||
uint32_t R3;
|
||||
uint32_t R12;
|
||||
uint32_t LR;
|
||||
uint32_t RetAddr;
|
||||
uint32_t XPSR;
|
||||
};
|
||||
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
|
||||
#else
|
||||
/* FixMe: redirect to secure log area */
|
||||
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
|
||||
#endif
|
||||
|
||||
#define LOG_MSG_THR(MSG) \
|
||||
__ASM("MOV r0, %0\n" \
|
||||
"SVC %1\n" \
|
||||
: : "r" (MSG), "I" (TFM_SVC_PRINT))
|
||||
|
||||
#define LOG_MSG(MSG) \
|
||||
do { \
|
||||
if (__get_active_exc_num()) { \
|
||||
LOG_MSG_HDLR(MSG); \
|
||||
} else { \
|
||||
LOG_MSG_THR(MSG); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
|
||||
#else
|
||||
/* FixMe: redirect to secure log area */
|
||||
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Get Link Register
|
||||
* \details Returns the value of the Link Register (LR)
|
||||
* \return LR value
|
||||
*/
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE uint32_t __get_LR(void)
|
||||
{
|
||||
register uint32_t result;
|
||||
|
||||
__ASM volatile ("MOV %0, LR\n" : "=r" (result));
|
||||
return result;
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
__STATIC_INLINE uint32_t __get_active_exc_num(void)
|
||||
{
|
||||
IPSR_Type IPSR;
|
||||
|
||||
/* if non-zero, exception is active. NOT banked S/NS */
|
||||
IPSR.w = __get_IPSR();
|
||||
return IPSR.b.ISR;
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline))
|
||||
__STATIC_INLINE void __set_CONTROL_SPSEL(int32_t SPSEL)
|
||||
{
|
||||
CONTROL_Type ctrl;
|
||||
|
||||
ctrl.w = __get_CONTROL();
|
||||
ctrl.b.SPSEL = SPSEL;
|
||||
__set_CONTROL(ctrl.w);
|
||||
__asm("ISB");
|
||||
}
|
||||
|
||||
/* FIXME: The following functions are wrappers around standard C library
|
||||
* functions: memcpy, memcmp, memset
|
||||
* In long term standard C library might be removed from TF-M project or
|
||||
* replaced with a secure implementation due to security concerns.
|
||||
*/
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
void tfm_memcpy(void *dest, const void *src, uint32_t size)
|
||||
{
|
||||
memcpy(dest, src, size);
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
int32_t tfm_memcmp(const void * ptr1, const void * ptr2, size_t num)
|
||||
{
|
||||
return (memcmp(ptr1, ptr2, num));
|
||||
}
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
void * tfm_memset(void * ptr, int value, size_t num)
|
||||
{
|
||||
return (memset(ptr, value, num));
|
||||
}
|
||||
|
||||
#endif /* __SECURE_UTILITIES_H__ */
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bl2/include/tfm_boot_status.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_internal.h"
|
||||
#include "tfm_api.h"
|
||||
#include "flash_layout.h"
|
||||
#include "secure_fw/spm/spm_api.h"
|
||||
|
||||
/*!
|
||||
* \def BOOT_DATA_VALID
|
||||
*
|
||||
* \brief Indicates that shared data between bootloader and runtime firmware was
|
||||
* passed the sanity check with success.
|
||||
*/
|
||||
#define BOOT_DATA_VALID (1u)
|
||||
|
||||
/*!
|
||||
* \def BOOT_DATA_INVALID
|
||||
*
|
||||
* \brief Indicates that shared data between bootloader and runtime firmware was
|
||||
* failed on sanity check.
|
||||
*/
|
||||
#define BOOT_DATA_INVALID (0u)
|
||||
|
||||
/*!
|
||||
* \var is_boot_data_valid
|
||||
*
|
||||
* \brief Indicates the status of shared data between bootloader and runtime
|
||||
* firmware
|
||||
*/
|
||||
static uint32_t is_boot_data_valid = BOOT_DATA_INVALID;
|
||||
|
||||
void tfm_core_validate_boot_data(void)
|
||||
{
|
||||
struct shared_data_tlv_header *tlv_header;
|
||||
|
||||
tlv_header = (struct shared_data_tlv_header *)BOOT_TFM_SHARED_DATA_BASE;
|
||||
|
||||
/* FixMe: Enhance sanity check of shared memory area, it might be invalid:
|
||||
* - temporal exposure of RAM to non-secure actors
|
||||
* - mismatched addresses
|
||||
* - version mismatch between bootloader and runtime binary
|
||||
* - etc.
|
||||
*/
|
||||
if (tlv_header->tlv_magic == SHARED_DATA_TLV_INFO_MAGIC) {
|
||||
is_boot_data_valid = BOOT_DATA_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
void tfm_core_get_boot_data_handler(uint32_t args[])
|
||||
{
|
||||
uint8_t tlv_major = (uint8_t)args[0];
|
||||
uint8_t *ptr = (uint8_t *)args[1];
|
||||
uint16_t buf_size = (uint16_t)args[2];
|
||||
uint8_t *buf_start = ptr;
|
||||
uint32_t running_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
struct shared_data_tlv_header *tlv_header;
|
||||
struct shared_data_tlv_entry *tlv_entry;
|
||||
uintptr_t tlv_end, offset;
|
||||
uint32_t res;
|
||||
|
||||
/* Make sure that the output pointer points to a memory area that is owned
|
||||
* by the partition
|
||||
*/
|
||||
res = tfm_core_check_buffer_access(running_partition_idx,
|
||||
(void*)buf_start,
|
||||
buf_size,
|
||||
2);
|
||||
if (!res) {
|
||||
/* Not in accessible range, return error */
|
||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
/* FixMe: Check whether caller has access right to given tlv_major_type */
|
||||
|
||||
if (is_boot_data_valid != BOOT_DATA_VALID) {
|
||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the boundaries of TLV section */
|
||||
tlv_header = (struct shared_data_tlv_header *)BOOT_TFM_SHARED_DATA_BASE;
|
||||
tlv_end = BOOT_TFM_SHARED_DATA_BASE + tlv_header->tlv_tot_len;
|
||||
offset = BOOT_TFM_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
|
||||
|
||||
/* Add header to output buffer as well */
|
||||
if (buf_size < SHARED_DATA_HEADER_SIZE) {
|
||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
} else {
|
||||
tfm_memcpy(ptr, tlv_header, SHARED_DATA_HEADER_SIZE);
|
||||
ptr += SHARED_DATA_HEADER_SIZE;
|
||||
}
|
||||
|
||||
/* Iterates over the TLV section and copy TLVs with requested major
|
||||
* type to the provided buffer.
|
||||
*/
|
||||
for(; offset < tlv_end; offset += tlv_entry->tlv_len) {
|
||||
tlv_entry = (struct shared_data_tlv_entry *)offset;
|
||||
if (tlv_entry->tlv_major_type == tlv_major) {
|
||||
/* Check buffer overflow */
|
||||
if ((ptr - buf_start + tlv_entry->tlv_len) > buf_size) {
|
||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
tfm_memcpy(ptr, (const void *)tlv_entry, tlv_entry->tlv_len);
|
||||
|
||||
ptr += tlv_entry->tlv_len;
|
||||
tlv_header->tlv_tot_len += tlv_entry->tlv_len;
|
||||
}
|
||||
}
|
||||
args[0] = TFM_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "region_defs.h"
|
||||
#include "tfm_core.h"
|
||||
#include "tfm_internal.h"
|
||||
#include "tfm_api.h"
|
||||
#include "platform/include/tfm_spm_hal.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "secure_fw/spm/spm_api.h"
|
||||
#include "secure_fw/include/tfm_spm_services_api.h"
|
||||
#ifdef TFM_PSA_API
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "tfm_thread.h"
|
||||
#include "tfm_wait.h"
|
||||
#include "tfm_message_queue.h"
|
||||
#include "tfm_spm.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Avoids the semihosting issue
|
||||
* FixMe: describe 'semihosting issue'
|
||||
*/
|
||||
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
|
||||
__asm(" .global __ARM_use_no_argv\n");
|
||||
#endif
|
||||
|
||||
#if defined ( __GNUC__ )
|
||||
/* The macro cmse_nsfptr_create defined in the gcc library uses the non-standard
|
||||
* gcc C lanuage extension 'typeof'. TF-M is built with '-std=c99' so typeof
|
||||
* cannot be used in the code. As a workaround cmse_nsfptr_create is redefined
|
||||
* here to use only standard language elements. */
|
||||
#undef cmse_nsfptr_create
|
||||
#define cmse_nsfptr_create(p) ((intptr_t) (p) & ~1)
|
||||
#endif
|
||||
|
||||
#ifndef TFM_LVL
|
||||
#error TFM_LVL is not defined!
|
||||
#endif
|
||||
#if (TFM_LVL != 1) && (TFM_LVL != 3)
|
||||
#error Only TFM_LVL 1 and 3 are supported!
|
||||
#endif
|
||||
|
||||
/* Macros to pick linker symbols and allow to form the partition data base */
|
||||
#define REGION(a, b, c) a##b##c
|
||||
#define REGION_NAME(a, b, c) REGION(a, b, c)
|
||||
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
||||
|
||||
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
|
||||
|
||||
void configure_ns_code(void)
|
||||
{
|
||||
/* SCB_NS.VTOR points to the Non-secure vector table base address */
|
||||
SCB_NS->VTOR = tfm_spm_hal_get_ns_VTOR();
|
||||
|
||||
/* Setups Main stack pointer of the non-secure code */
|
||||
uint32_t ns_msp = tfm_spm_hal_get_ns_MSP();
|
||||
|
||||
__TZ_set_MSP_NS(ns_msp);
|
||||
|
||||
/* Get the address of non-secure code entry point to jump there */
|
||||
uint32_t entry_ptr = tfm_spm_hal_get_ns_entry_point();
|
||||
|
||||
/* Clears LSB of the function address to indicate the function-call
|
||||
* will perform the switch from secure to non-secure
|
||||
*/
|
||||
ns_entry = (nsfptr_t) cmse_nsfptr_create(entry_ptr);
|
||||
}
|
||||
|
||||
int32_t tfm_core_init(void)
|
||||
{
|
||||
/* Enables fault handlers */
|
||||
enable_fault_handlers();
|
||||
|
||||
/* Configures the system reset request properties */
|
||||
system_reset_cfg();
|
||||
|
||||
/* Configures debug authentication */
|
||||
tfm_spm_hal_init_debug();
|
||||
|
||||
__enable_irq();
|
||||
|
||||
LOG_MSG("Secure image initializing!");
|
||||
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
printf("TFM level is: %d\r\n", TFM_LVL);
|
||||
#endif
|
||||
|
||||
tfm_core_validate_boot_data();
|
||||
|
||||
tfm_spm_hal_init_isolation_hw();
|
||||
|
||||
configure_ns_code();
|
||||
|
||||
/* Configures all interrupts to retarget NS state, except for
|
||||
* secure peripherals
|
||||
*/
|
||||
nvic_interrupt_target_state_cfg();
|
||||
/* Enable secure peripherals interrupts */
|
||||
nvic_interrupt_enable();
|
||||
|
||||
tfm_scratch_area =
|
||||
(uint8_t *)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||
tfm_scratch_area_size =
|
||||
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit) -
|
||||
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t tfm_core_set_secure_exception_priorities(void)
|
||||
{
|
||||
uint32_t VECTKEY;
|
||||
SCB_Type *scb = SCB;
|
||||
uint32_t AIRCR;
|
||||
|
||||
/* Set PRIS flag is AIRCR */
|
||||
AIRCR = scb->AIRCR;
|
||||
VECTKEY = (~AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
|
||||
scb->AIRCR = SCB_AIRCR_PRIS_Msk |
|
||||
VECTKEY |
|
||||
(AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
|
||||
|
||||
/* FixMe: Explicitly set secure fault and Secure SVC priority to highest */
|
||||
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx)
|
||||
{
|
||||
uint32_t *res_ptr = (uint32_t *)&svc_ctx->R0;
|
||||
|
||||
/* FixMe: check if caller partition is permitted to make an SPM request */
|
||||
|
||||
switch (svc_ctx->R0) {
|
||||
case TFM_SPM_REQUEST_RESET_VOTE:
|
||||
/* FixMe: this is a placeholder for checks to be performed before
|
||||
* allowing execution of reset
|
||||
*/
|
||||
*res_ptr = TFM_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tfm_core_init();
|
||||
|
||||
tfm_spm_db_init();
|
||||
|
||||
tfm_spm_hal_setup_isolation_hw();
|
||||
|
||||
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_RUNNING);
|
||||
|
||||
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
|
||||
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
|
||||
|
||||
__set_PSPLIM(psp_stack_bottom);
|
||||
|
||||
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 TFM_PSA_API
|
||||
tfm_spm_init();
|
||||
#endif
|
||||
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
/* Jumps to non-secure code */
|
||||
LOG_MSG("Jumping to non-secure code...");
|
||||
#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.
|
||||
*/
|
||||
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_CLOSED);
|
||||
tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
|
||||
SPM_PARTITION_STATE_RUNNING);
|
||||
|
||||
/* Prioritise secure exceptions to avoid NS being able to pre-empt secure
|
||||
* SVC or SecureFault
|
||||
*/
|
||||
tfm_core_set_secure_exception_priorities();
|
||||
|
||||
jump_to_ns_code();
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_CORE_H__
|
||||
#define __TFM_CORE_H__
|
||||
|
||||
#include "arm_cmse.h"
|
||||
#include "tfm_svc.h"
|
||||
#include "secure_utilities.h"
|
||||
|
||||
extern int32_t tfm_scratch_area_size;
|
||||
extern uint8_t *tfm_scratch_area;
|
||||
|
||||
#endif /* __TFM_CORE_H__ */
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "arm_acle.h"
|
||||
#include "tfm_svc.h"
|
||||
#include "tfm_secure_api.h"
|
||||
#include "region_defs.h"
|
||||
#include "tfm_api.h"
|
||||
#include "tfm_internal.h"
|
||||
#ifdef TFM_PSA_API
|
||||
#include <stdbool.h>
|
||||
#include "tfm_svcalls.h"
|
||||
#endif
|
||||
|
||||
/* This SVC handler is called when a secure partition requests access to a
|
||||
* buffer area
|
||||
*/
|
||||
extern int32_t tfm_core_set_buffer_area_handler(const uint32_t args[]);
|
||||
#ifdef TFM_PSA_API
|
||||
extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
|
||||
#endif
|
||||
|
||||
struct tfm_fault_context_s {
|
||||
uint32_t R0;
|
||||
uint32_t R1;
|
||||
uint32_t R2;
|
||||
uint32_t R3;
|
||||
uint32_t R12;
|
||||
uint32_t LR;
|
||||
uint32_t ReturnAddress;
|
||||
uint32_t RETPSR;
|
||||
} tfm_fault_context;
|
||||
|
||||
#if defined(__ARM_ARCH_8M_MAIN__)
|
||||
/**
|
||||
* \brief Overwrites default Secure fault handler.
|
||||
*/
|
||||
void SecureFault_Handler(void)
|
||||
{
|
||||
/* figure out context from which we landed in fault handler */
|
||||
uint32_t lr = __get_LR();
|
||||
uint32_t sp;
|
||||
|
||||
if (lr & EXC_RETURN_SECURE_STACK) {
|
||||
if (lr & EXC_RETURN_STACK_PROCESS) {
|
||||
sp = __get_PSP();
|
||||
} else {
|
||||
sp = __get_MSP();
|
||||
}
|
||||
} else {
|
||||
if (lr & EXC_RETURN_STACK_PROCESS) {
|
||||
sp = __TZ_get_PSP_NS();
|
||||
} else {
|
||||
sp = __TZ_get_MSP_NS();
|
||||
}
|
||||
}
|
||||
|
||||
/* Only save the context if sp is valid */
|
||||
if ((sp >= S_DATA_START &&
|
||||
sp <= S_DATA_LIMIT - sizeof(tfm_fault_context) + 1) ||
|
||||
(sp >= NS_DATA_START &&
|
||||
sp <= NS_DATA_LIMIT - sizeof(tfm_fault_context) + 1)) {
|
||||
tfm_memcpy(&tfm_fault_context,
|
||||
(const void *)sp,
|
||||
sizeof(tfm_fault_context));
|
||||
}
|
||||
|
||||
LOG_MSG("Oops... Secure fault!!! You're not going anywhere!");
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
#elif defined(__ARM_ARCH_8M_BASE__)
|
||||
/**
|
||||
* \brief Overwrites default Hard fault handler.
|
||||
*
|
||||
* In case of a baseline implementation fault conditions that would generate a
|
||||
* SecureFault in a mainline implementation instead generate a Secure HardFault.
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* In a baseline implementation there is no way, to find out whether this is
|
||||
* a hard fault triggered directly, or another fault that has been
|
||||
* escalated.
|
||||
*/
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error "Unsupported ARM Architecture."
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_ARCH_8M_MAIN__)
|
||||
__attribute__((naked)) void SVC_Handler(void)
|
||||
{
|
||||
__ASM(
|
||||
"TST lr, #4\n" /* Check store SP in thread mode to r0 */
|
||||
"IT EQ\n"
|
||||
"BXEQ lr\n"
|
||||
"MRS r0, PSP\n"
|
||||
"MOV r1, lr\n"
|
||||
"BL SVCHandler_main\n"
|
||||
"BX r0\n"
|
||||
);
|
||||
}
|
||||
#elif defined(__ARM_ARCH_8M_BASE__)
|
||||
__attribute__((naked)) void SVC_Handler(void)
|
||||
{
|
||||
__ASM(
|
||||
".syntax unified\n"
|
||||
"MOVS r0, #4\n" /* Check store SP in thread mode to r0 */
|
||||
"MOV r1, lr\n"
|
||||
"TST r0, r1\n"
|
||||
"BEQ handler\n"
|
||||
"MRS r0, PSP\n" /* Coming from thread mode */
|
||||
"B sp_stored\n"
|
||||
"handler:\n"
|
||||
"BX lr\n" /* Coming from handler mode */
|
||||
"sp_stored:\n"
|
||||
"MOV r1, lr\n"
|
||||
"BL SVCHandler_main\n"
|
||||
"BX r0\n"
|
||||
);
|
||||
}
|
||||
#else
|
||||
#error "Unsupported ARM Architecture."
|
||||
#endif
|
||||
|
||||
uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr)
|
||||
{
|
||||
uint8_t svc_number;
|
||||
/*
|
||||
* Stack contains:
|
||||
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
|
||||
* First argument (r0) is svc_args[0]
|
||||
*/
|
||||
if (lr & EXC_RETURN_SECURE_STACK) {
|
||||
/* SV called directly from secure context. Check instruction for
|
||||
* svc_number
|
||||
*/
|
||||
svc_number = ((uint8_t *)svc_args[6])[-2];
|
||||
} else {
|
||||
/* Secure SV executing with NS return.
|
||||
* NS cannot directly trigger S SVC so this should not happen
|
||||
* FixMe: check for security implications
|
||||
*/
|
||||
return lr;
|
||||
}
|
||||
switch (svc_number) {
|
||||
case TFM_SVC_SFN_REQUEST:
|
||||
lr = tfm_core_partition_request_svc_handler(svc_args, lr);
|
||||
break;
|
||||
case TFM_SVC_SFN_RETURN:
|
||||
lr = tfm_core_partition_return_handler(lr);
|
||||
break;
|
||||
case TFM_SVC_VALIDATE_SECURE_CALLER:
|
||||
tfm_core_validate_secure_caller_handler(svc_args);
|
||||
break;
|
||||
case TFM_SVC_GET_CALLER_CLIENT_ID:
|
||||
tfm_core_get_caller_client_id_handler(svc_args);
|
||||
break;
|
||||
case TFM_SVC_SPM_REQUEST:
|
||||
tfm_core_spm_request_handler((struct tfm_exc_stack_t *)svc_args);
|
||||
break;
|
||||
case TFM_SVC_MEMORY_CHECK:
|
||||
tfm_core_memory_permission_check_handler(svc_args);
|
||||
break;
|
||||
case TFM_SVC_SET_SHARE_AREA:
|
||||
tfm_core_set_buffer_area_handler(svc_args);
|
||||
break;
|
||||
#ifdef TFM_PSA_API
|
||||
case TFM_SVC_IPC_REQUEST:
|
||||
tfm_psa_ipc_request_handler(svc_args);
|
||||
break;
|
||||
#endif
|
||||
case TFM_SVC_PRINT:
|
||||
printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
|
||||
break;
|
||||
case TFM_SVC_GET_BOOT_DATA:
|
||||
tfm_core_get_boot_data_handler(svc_args);
|
||||
break;
|
||||
#ifdef TFM_PSA_API
|
||||
case TFM_SVC_PSA_FRAMEWORK_VERSION:
|
||||
case TFM_SVC_PSA_VERSION:
|
||||
case TFM_SVC_PSA_CONNECT:
|
||||
case TFM_SVC_PSA_CALL:
|
||||
case TFM_SVC_PSA_CLOSE:
|
||||
case TFM_SVC_PSA_WAIT:
|
||||
case TFM_SVC_PSA_GET:
|
||||
case TFM_SVC_PSA_SET_RHANDLE:
|
||||
case TFM_SVC_PSA_READ:
|
||||
case TFM_SVC_PSA_SKIP:
|
||||
case TFM_SVC_PSA_WRITE:
|
||||
case TFM_SVC_PSA_REPLY:
|
||||
case TFM_SVC_PSA_NOTIFY:
|
||||
case TFM_SVC_PSA_CLEAR:
|
||||
case TFM_SVC_PSA_EOI:
|
||||
svc_args[0] = SVC_Handler_IPC(svc_number, svc_args);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOG_MSG("Unknown SVC number requested!");
|
||||
break;
|
||||
}
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
void tfm_access_violation_handler(void)
|
||||
{
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include "secure_utilities.h"
|
||||
|
||||
#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;
|
||||
|
||||
/**
|
||||
* \brief Signal that secure partition initialisation is finished
|
||||
*/
|
||||
void tfm_secure_api_init_done(void);
|
||||
|
||||
/**
|
||||
* \brief Jumps to non-secure code.
|
||||
*/
|
||||
void jump_to_ns_code(void);
|
||||
|
||||
/**
|
||||
* \brief Called if veneer is running in thread mode
|
||||
*/
|
||||
uint32_t tfm_core_partition_request_svc_handler(
|
||||
uint32_t *svc_args, uint32_t lr);
|
||||
|
||||
/**
|
||||
* \brief Called when secure service returns
|
||||
*/
|
||||
uint32_t tfm_core_partition_return_handler(uint32_t lr);
|
||||
|
||||
/**
|
||||
* \brief Called by secure service to check if client is secure
|
||||
*/
|
||||
void tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
|
||||
|
||||
/**
|
||||
* \brief Stores caller's client id in state context
|
||||
*/
|
||||
void tfm_core_get_caller_client_id_handler(const uint32_t svc_args[]);
|
||||
|
||||
/**
|
||||
* \brief Checks if a secure service's access to a memory location is permitted
|
||||
*/
|
||||
void tfm_core_memory_permission_check_handler(const uint32_t svc_args[]);
|
||||
|
||||
/**
|
||||
* \brief Handle an SPM request by a secure service
|
||||
*/
|
||||
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx);
|
||||
|
||||
/**
|
||||
* \brief Check whether a buffer is ok for writing to by the privileged API
|
||||
* function.
|
||||
*
|
||||
* This function checks whether the caller partition owns the buffer, can write
|
||||
* to it, and the buffer has proper alignment.
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] start_addr The start address of the buffer
|
||||
* \param[in] len The length of the buffer
|
||||
* \param[in] alignment The expected alignment (in bits)
|
||||
*
|
||||
* \return 1 if the check passes, 0 otherwise.
|
||||
*
|
||||
* \note For a 0 long buffer the check fails.
|
||||
*/
|
||||
int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
|
||||
void *start_addr,
|
||||
size_t len,
|
||||
uint32_t alignment);
|
||||
|
||||
/**
|
||||
* \brief Retrieve secure partition related data from shared memory area, which
|
||||
* stores shared data between bootloader and runtime firmware.
|
||||
*
|
||||
* \param[in] args Pointer to stack frame, which carries input parameters.
|
||||
*/
|
||||
void tfm_core_get_boot_data_handler(uint32_t args[]);
|
||||
|
||||
/**
|
||||
* \brief Validate the content of shared memory area, which stores the shared
|
||||
* data between bootloader and runtime firmware.
|
||||
*/
|
||||
void tfm_core_validate_boot_data(void);
|
||||
|
||||
#endif /* __TFM_INTERNAL_H__ */
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_api.h"
|
||||
|
||||
#ifndef TFM_MAX_NS_THREAD_COUNT
|
||||
#define TFM_MAX_NS_THREAD_COUNT 8
|
||||
#endif
|
||||
#define INVALID_CLIENT_ID 0
|
||||
|
||||
#define DEFAULT_NS_CLIENT_ID ((int32_t)-1)
|
||||
|
||||
#define INVALID_NS_CLIENT_IDX (-1)
|
||||
#define DEFAULT_NS_CLIENT_IDX 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 free_index = 0U;
|
||||
static int32_t active_ns_client_idx = INVALID_NS_CLIENT_IDX;
|
||||
|
||||
static int get_next_ns_client_id()
|
||||
{
|
||||
#ifdef TFM_NS_CLIENT_IDENTIFICATION
|
||||
static int32_t next_ns_client_id = DEFAULT_NS_CLIENT_ID;
|
||||
|
||||
if (next_ns_client_id > 0)
|
||||
{
|
||||
next_ns_client_id = DEFAULT_NS_CLIENT_ID;
|
||||
}
|
||||
return next_ns_client_id--;
|
||||
#else
|
||||
return DEFAULT_NS_CLIENT_ID;
|
||||
#endif
|
||||
}
|
||||
|
||||
void tfm_nspm_configure_clients(void)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
/* Default to one NS client */
|
||||
free_index = 1;
|
||||
NsClientIdList[0].ns_client_id = get_next_ns_client_id();
|
||||
for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
|
||||
NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
|
||||
}
|
||||
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
|
||||
}
|
||||
|
||||
int32_t tfm_nspm_get_current_client_id()
|
||||
{
|
||||
if (active_ns_client_idx == INVALID_NS_CLIENT_IDX)
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
return NsClientIdList[active_ns_client_idx].ns_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 */
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
LOG_MSG("NS RTOS initialized TZ RTOS context management");
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
for (i = 1; 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 = INVALID_NS_CLIENT_IDX;
|
||||
/* 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 = get_next_ns_client_id();
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("TZ_AllocModuleContext_S called, returning id %d\r\n",
|
||||
NsClientIdList[free_index].ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("TZ_FreeModuleContext_S called for id %d\r\n",
|
||||
NsClientIdList[index].ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
if (active_ns_client_idx == index) {
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("Freeing active NS client, NS inactive\r\n");
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
LOG_MSG("TZ_LoadContext_S called");
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
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_idx = index;
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("TZ_LoadContext_S called for id %d\r\n",
|
||||
NsClientIdList[index].ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
LOG_MSG("TZ_StoreContext_S called");
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
/* 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_idx != index) {
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("TZ_StoreContext_S called for id %d, active id: %d\r\n",
|
||||
NsClientIdList[index].ns_client_id,
|
||||
NsClientIdList[active_ns_client_idx].ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
return 0U;
|
||||
}
|
||||
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("TZ_StoreContext_S called for id %d\r\n",
|
||||
NsClientIdList[index].ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
|
||||
|
||||
return 1U; // Success
|
||||
}
|
||||
|
||||
#ifdef TFM_NS_CLIENT_IDENTIFICATION
|
||||
__attribute__((cmse_nonsecure_entry))
|
||||
enum tfm_status_e tfm_register_client_id (int32_t ns_client_id)
|
||||
{
|
||||
int current_client_id;
|
||||
|
||||
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
|
||||
/* This veneer should only be called by NS RTOS in handler mode */
|
||||
return TFM_ERROR_NS_THREAD_MODE_CALL;
|
||||
}
|
||||
|
||||
if (ns_client_id >= 0) {
|
||||
/* The client ID is invalid */
|
||||
return TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (active_ns_client_idx < 0) {
|
||||
/* No client is active */
|
||||
return TFM_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
current_client_id = NsClientIdList[active_ns_client_idx].ns_client_id;
|
||||
if (current_client_id >= 0 ) {
|
||||
/* The client ID is invalid */
|
||||
return TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
NsClientIdList[active_ns_client_idx].ns_client_id = ns_client_id;
|
||||
#ifdef PRINT_NSPM_DEBUG
|
||||
printf("tfm_register_client_id called with id %d\r\n", ns_client_id);
|
||||
#endif /* PRINT_NSPM_DEBUG */
|
||||
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_NSPM_H__
|
||||
#define __TFM_NSPM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \brief initialise the NS context database
|
||||
*/
|
||||
void tfm_nspm_configure_clients(void);
|
||||
|
||||
/**
|
||||
* \brief Get the client ID of the current NS client
|
||||
*
|
||||
* \return The client id of the current NS client. 0 (invalid client id) is
|
||||
* returned in case of error.
|
||||
*/
|
||||
int32_t tfm_nspm_get_current_client_id(void);
|
||||
|
||||
#endif /* __TFM_NSPM_H__ */
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_PLATFORM_CORE_API_H__
|
||||
#define __TFM_PLATFORM_CORE_API_H__
|
||||
|
||||
/**
|
||||
* \brief Should be called in case of access violation.
|
||||
*
|
||||
* There might be platform specific means, by which it is possible on a
|
||||
* subsystem to detect access violation. For example a platform can have a
|
||||
* Peripheral Protection Controller, to detect unauthorised accesses to
|
||||
* peripheral registers. Setting up the protection, and handling the violation
|
||||
* is implemented in platform specific code. However TF-M should be able to
|
||||
* decide how to proceed if a violation happens. So to notify TF-M, platform
|
||||
* code have to call this function, if a violation happens.
|
||||
*/
|
||||
void tfm_access_violation_handler(void);
|
||||
|
||||
#endif /* __TFM_PLATFORM_CORE_API_H__ */
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "psa_client.h"
|
||||
#include "psa_service.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_secure_api.h"
|
||||
#include "tfm_api.h"
|
||||
#include "tfm_svcalls.h"
|
||||
|
||||
/* FixMe: check if this is really needed */
|
||||
extern int32_t tfm_secure_lock;
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
int32_t tfm_psa_veneer_sanity_check(struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
if (desc_ptr->ns_caller) {
|
||||
if (tfm_secure_lock != 0) {
|
||||
/* Secure domain is already locked!
|
||||
* FixMe: Decide if this is a fault or permitted in case of PSA
|
||||
* API usage
|
||||
*/
|
||||
return TFM_ERROR_SECURE_DOMAIN_LOCKED;
|
||||
}
|
||||
} else {
|
||||
/* Secure partition should not call a different secure partition
|
||||
* using TFM PSA veneers
|
||||
*/
|
||||
return TFM_ERROR_INVALID_EXC_MODE;
|
||||
}
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
|
||||
/* Veneer implementation */
|
||||
|
||||
#define TFM_CORE_NS_IPC_REQUEST_VENEER(fn, a, b, c, d) \
|
||||
return tfm_core_ns_ipc_request(fn, (int32_t)a, (int32_t)b, \
|
||||
(int32_t)c, (int32_t)d)
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
int32_t tfm_core_ns_ipc_request(void *fn, int32_t arg1, int32_t arg2,
|
||||
int32_t arg3, int32_t arg4)
|
||||
{
|
||||
int32_t args[4] = {arg1, arg2, arg3, arg4};
|
||||
volatile struct tfm_sfn_req_s desc;
|
||||
struct tfm_sfn_req_s *desc_ptr = &desc;
|
||||
int32_t res;
|
||||
|
||||
desc.sfn = fn;
|
||||
desc.args = args;
|
||||
desc.ns_caller = cmse_nonsecure_caller();
|
||||
|
||||
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE)
|
||||
{
|
||||
/* FIXME: Proper error handling to be implemented */
|
||||
return TFM_ERROR_INVALID_EXC_MODE;
|
||||
} else {
|
||||
__ASM("MOV r0, %1\n"
|
||||
"SVC %2\n"
|
||||
"MOV %0, r0\n"
|
||||
: "=r" (res)
|
||||
: "r" (desc_ptr), "I" (TFM_SVC_IPC_REQUEST)
|
||||
: "r0");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* FixMe: these functions need to have different attributes compared to those
|
||||
* legacy veneers which may be called by secure partitions.
|
||||
* They won't call legacy SFN but instead will be handlers for TF-M
|
||||
*/
|
||||
|
||||
__tfm_secure_gateway_attributes__
|
||||
uint32_t tfm_psa_framework_version_veneer(void)
|
||||
{
|
||||
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_framework_version, 0, 0,
|
||||
0, 0);
|
||||
}
|
||||
|
||||
__tfm_secure_gateway_attributes__
|
||||
uint32_t tfm_psa_version_veneer(uint32_t sid)
|
||||
{
|
||||
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_version, sid, 0, 0, 0);
|
||||
}
|
||||
|
||||
__tfm_secure_gateway_attributes__
|
||||
psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
|
||||
{
|
||||
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_connect, sid,
|
||||
minor_version, 0, 0);
|
||||
}
|
||||
|
||||
__tfm_secure_gateway_attributes__
|
||||
psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
|
||||
const psa_invec *in_vecs,
|
||||
psa_outvec *out_vecs)
|
||||
{
|
||||
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_call, handle, in_vecs,
|
||||
out_vecs, 0);
|
||||
}
|
||||
|
||||
__tfm_secure_gateway_attributes__
|
||||
psa_status_t tfm_psa_close_veneer(psa_handle_t handle)
|
||||
{
|
||||
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_close, handle, 0, 0, 0);
|
||||
}
|
||||
|
||||
void tfm_psa_ipc_request_handler(uint32_t svc_ctx[])
|
||||
{
|
||||
uint32_t *r0_ptr = svc_ctx;
|
||||
|
||||
/* The only argument to the SVC call is stored in the stacked r0 */
|
||||
struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) *r0_ptr;
|
||||
|
||||
if(tfm_psa_veneer_sanity_check(desc_ptr) != TFM_SUCCESS) {
|
||||
/* FixMe: consider error handling - this may be critical error */
|
||||
*r0_ptr = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store SVC return value in stacked r0 */
|
||||
*r0_ptr = desc_ptr->sfn((int32_t)desc_ptr->args,
|
||||
desc_ptr->ns_caller,
|
||||
0,
|
||||
0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,799 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "cmsis.h"
|
||||
#include "tfm_secure_api.h"
|
||||
#include "tfm_nspm.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "secure_fw/spm/spm_api.h"
|
||||
#include "region_defs.h"
|
||||
#include "tfm_api.h"
|
||||
|
||||
#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
|
||||
|
||||
#ifndef TFM_LVL
|
||||
#error TFM_LVL is not defined!
|
||||
#endif
|
||||
|
||||
#if TFM_LVL == 1
|
||||
/* Macros to pick linker symbols and allow references to sections */
|
||||
#define REGION(a, b, c) a##b##c
|
||||
#define REGION_NAME(a, b, c) REGION(a, b, c)
|
||||
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
||||
|
||||
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||
#endif
|
||||
|
||||
/* This is the "Big Lock" on the secure side, to guarantee single entry
|
||||
* to SPE
|
||||
*/
|
||||
int32_t tfm_secure_lock;
|
||||
static int32_t tfm_secure_api_initializing = 1;
|
||||
|
||||
static int32_t *prepare_partition_ctx(
|
||||
struct tfm_exc_stack_t *svc_ctx,
|
||||
struct tfm_sfn_req_s *desc_ptr,
|
||||
int32_t *dst)
|
||||
{
|
||||
/* XPSR = as was when called, but make sure it's thread mode */
|
||||
*(--dst) = svc_ctx->XPSR & 0xFFFFFE00;
|
||||
/* ReturnAddress = resume veneer in new context */
|
||||
*(--dst) = svc_ctx->RetAddr;
|
||||
/* LR = sfn address */
|
||||
*(--dst) = (int32_t)desc_ptr->sfn;
|
||||
/* R12 = don't care */
|
||||
*(--dst) = 0;
|
||||
|
||||
/* R0-R3 = sfn arguments */
|
||||
int32_t i = 4;
|
||||
|
||||
while (i > 0) {
|
||||
i--;
|
||||
*(--dst) = (uint32_t)desc_ptr->args[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void restore_caller_ctx(
|
||||
struct tfm_exc_stack_t *svc_ctx,
|
||||
struct tfm_exc_stack_t *target_ctx)
|
||||
{
|
||||
/* ReturnAddress = resume veneer after second SVC */
|
||||
target_ctx->RetAddr = svc_ctx->RetAddr;
|
||||
|
||||
/* R0 = function return value */
|
||||
target_ctx->R0 = svc_ctx->R0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
||||
uint32_t excReturn)
|
||||
{
|
||||
uint32_t caller_partition_idx = desc_ptr->caller_part_idx;
|
||||
const struct spm_partition_runtime_data_t *curr_part_data;
|
||||
uint32_t caller_flags;
|
||||
register uint32_t partition_idx;
|
||||
uint32_t psp = __get_PSP();
|
||||
uint32_t partition_psp, partition_psplim;
|
||||
uint32_t partition_state;
|
||||
uint32_t partition_flags;
|
||||
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
||||
uint32_t caller_partition_id;
|
||||
int32_t client_id;
|
||||
|
||||
caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
|
||||
|
||||
/* Check partition state consistency */
|
||||
if (((caller_flags & SPM_PART_FLAG_APP_ROT) != 0)
|
||||
!= (!desc_ptr->ns_caller)) {
|
||||
/* Partition state inconsistency detected */
|
||||
return TFM_SECURE_LOCK_FAILED;
|
||||
}
|
||||
|
||||
if((caller_flags & SPM_PART_FLAG_APP_ROT) == 0) {
|
||||
/* Disable NS exception handling while secure service is running.
|
||||
* FixMe:
|
||||
* This restriction is applied to limit the number of possible attack
|
||||
* vectors.
|
||||
* To be removed when pre-emption and context management issues have
|
||||
* been analysed and resolved.
|
||||
*/
|
||||
TFM_NS_EXC_DISABLE();
|
||||
}
|
||||
|
||||
partition_idx = get_partition_idx(desc_ptr->sp_id);
|
||||
|
||||
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);
|
||||
caller_partition_id = tfm_spm_partition_get_partition_id(
|
||||
caller_partition_idx);
|
||||
|
||||
if (tfm_secure_api_initializing) {
|
||||
#if TFM_LVL != 1
|
||||
/* Make thread mode unprivileged while untrusted partition init is
|
||||
* executed
|
||||
*/
|
||||
if ((partition_flags & SPM_PART_FLAG_PSA_ROT) == 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)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||
partition_psplim =
|
||||
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||
#else
|
||||
partition_psp = curr_part_data->stack_ptr;
|
||||
partition_psplim = tfm_spm_partition_get_stack_bottom(partition_idx);
|
||||
#endif
|
||||
/* Store the context for the partition call */
|
||||
tfm_spm_partition_set_caller_partition_idx(partition_idx,
|
||||
caller_partition_idx);
|
||||
tfm_spm_partition_store_context(caller_partition_idx, psp, excReturn);
|
||||
|
||||
if ((caller_flags & SPM_PART_FLAG_APP_ROT)) {
|
||||
tfm_spm_partition_set_caller_client_id(partition_idx,
|
||||
caller_partition_id);
|
||||
} else {
|
||||
client_id = tfm_nspm_get_current_client_id();
|
||||
if (client_id >= 0)
|
||||
{
|
||||
return TFM_SECURE_LOCK_FAILED;
|
||||
}
|
||||
tfm_spm_partition_set_caller_client_id(partition_idx, client_id);
|
||||
}
|
||||
|
||||
#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->ns_caller) || (tfm_secure_api_initializing)) {
|
||||
/* Prepare the partition context, update stack ptr */
|
||||
psp = (uint32_t)prepare_partition_ctx(
|
||||
svc_ctx, desc_ptr, (int32_t *)partition_psp);
|
||||
__set_PSP(psp);
|
||||
__set_PSPLIM(partition_psplim);
|
||||
}
|
||||
#else
|
||||
/* Prepare the partition context, update stack ptr */
|
||||
psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
|
||||
(int32_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_return_from_partition(uint32_t *excReturn)
|
||||
{
|
||||
uint32_t current_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
const struct spm_partition_runtime_data_t *curr_part_data, *ret_part_data;
|
||||
uint32_t current_partition_flags;
|
||||
uint32_t return_partition_idx;
|
||||
uint32_t return_partition_flags;
|
||||
uint32_t psp = __get_PSP();
|
||||
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
||||
|
||||
if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
|
||||
return TFM_SECURE_UNLOCK_FAILED;
|
||||
}
|
||||
|
||||
curr_part_data = tfm_spm_partition_get_runtime_data(current_partition_idx);
|
||||
return_partition_idx = curr_part_data->caller_partition_idx;
|
||||
|
||||
if (return_partition_idx == SPM_INVALID_PARTITION_IDX) {
|
||||
return TFM_SECURE_UNLOCK_FAILED;
|
||||
}
|
||||
|
||||
ret_part_data = tfm_spm_partition_get_runtime_data(return_partition_idx);
|
||||
|
||||
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((return_partition_flags & SPM_PART_FLAG_APP_ROT) == 0) {
|
||||
/* Re-enable NS exceptions when secure service returns to NS client.
|
||||
* FixMe:
|
||||
* To be removed when pre-emption and context management issues have
|
||||
* been analysed and resolved.
|
||||
*/
|
||||
TFM_NS_EXC_ENABLE();
|
||||
}
|
||||
|
||||
#if (TFM_LVL != 1) && (TFM_LVL != 2)
|
||||
/* Deconfigure completed partition environment */
|
||||
tfm_spm_partition_sandbox_deconfig(current_partition_idx);
|
||||
if (tfm_secure_api_initializing) {
|
||||
/* Restore privilege for thread mode during TF-M init. This is only
|
||||
* have to be done if the partition is not trusted.
|
||||
*/
|
||||
if ((current_partition_flags & SPM_PART_FLAG_PSA_ROT) == 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_APP_ROT) {
|
||||
/* 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_APP_ROT) ||
|
||||
(tfm_secure_api_initializing)) {
|
||||
/* In TFM level 1 context restore is only done when
|
||||
* returning to NS or after initialization
|
||||
*/
|
||||
/* Restore caller context */
|
||||
restore_caller_ctx(svc_ctx,
|
||||
(struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
|
||||
*excReturn = ret_part_data->lr;
|
||||
__set_PSP(ret_part_data->stack_ptr);
|
||||
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
|
||||
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
|
||||
__set_PSPLIM(psp_stack_bottom);
|
||||
|
||||
}
|
||||
#else
|
||||
/* Restore caller context */
|
||||
restore_caller_ctx(svc_ctx,
|
||||
(struct tfm_exc_stack_t *)ret_part_data->stack_ptr);
|
||||
*excReturn = ret_part_data->lr;
|
||||
__set_PSP(ret_part_data->stack_ptr);
|
||||
__set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
|
||||
/* Clear the context entry before returning */
|
||||
tfm_spm_partition_set_stack(
|
||||
current_partition_idx, psp - sizeof(struct tfm_exc_stack_t));
|
||||
#endif
|
||||
|
||||
tfm_spm_partition_cleanup_context(current_partition_idx);
|
||||
|
||||
tfm_spm_partition_set_state(current_partition_idx,
|
||||
SPM_PARTITION_STATE_IDLE);
|
||||
tfm_spm_partition_set_state(return_partition_idx,
|
||||
SPM_PARTITION_STATE_RUNNING);
|
||||
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_secure_api_error_handler(void)
|
||||
{
|
||||
ERROR_MSG("Security violation when calling secure API");
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t tfm_check_sfn_req_integrity(struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
if ((desc_ptr == NULL) ||
|
||||
(desc_ptr->sp_id == 0) ||
|
||||
(desc_ptr->sfn == NULL)) {
|
||||
/* invalid parameter */
|
||||
return TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t tfm_core_check_sfn_req_rules(
|
||||
struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
/* Check partition idx validity */
|
||||
if (desc_ptr->caller_part_idx == SPM_INVALID_PARTITION_IDX) {
|
||||
return TFM_ERROR_NO_ACTIVE_PARTITION;
|
||||
}
|
||||
|
||||
if ((desc_ptr->ns_caller) && (tfm_secure_lock != 0)) {
|
||||
/* Secure domain is already locked!
|
||||
* This should only happen if caller is secure partition!
|
||||
* FixMe: This scenario is a potential security breach
|
||||
* Take appropriate action!
|
||||
*/
|
||||
return TFM_ERROR_SECURE_DOMAIN_LOCKED;
|
||||
}
|
||||
|
||||
if (tfm_secure_api_initializing) {
|
||||
int32_t id =
|
||||
tfm_spm_partition_get_partition_id(desc_ptr->caller_part_idx);
|
||||
|
||||
if ((id != TFM_SP_CORE_ID) || (tfm_secure_lock != 0)) {
|
||||
/* Invalid request during system initialization */
|
||||
ERROR_MSG("Invalid service request during initialization!");
|
||||
return TFM_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
return TFM_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_secure_api_init_done(void)
|
||||
{
|
||||
tfm_secure_api_initializing = 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
|
||||
}
|
||||
|
||||
int32_t tfm_core_sfn_request_handler(
|
||||
struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn)
|
||||
{
|
||||
int32_t res;
|
||||
|
||||
res = tfm_check_sfn_req_integrity(desc_ptr);
|
||||
if (res != TFM_SUCCESS) {
|
||||
ERROR_MSG("Invalid service request!");
|
||||
return TFM_ERROR_STATUS(res);
|
||||
}
|
||||
|
||||
__disable_irq();
|
||||
desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
|
||||
|
||||
res = tfm_core_check_sfn_req_rules(desc_ptr);
|
||||
if (res != TFM_SUCCESS) {
|
||||
/* FixMe: error compartmentalization TBD */
|
||||
tfm_spm_partition_set_state(
|
||||
desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
|
||||
__enable_irq();
|
||||
ERROR_MSG("Unauthorized service request!");
|
||||
return TFM_ERROR_STATUS(res);
|
||||
}
|
||||
|
||||
res = tfm_start_partition(desc_ptr, excReturn);
|
||||
if (res != TFM_SUCCESS) {
|
||||
/* FixMe: consider possible fault scenarios */
|
||||
__enable_irq();
|
||||
ERROR_MSG("Failed to process service request!");
|
||||
return TFM_ERROR_STATUS(res);
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#if TFM_LVL == 1
|
||||
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
int32_t res;
|
||||
int32_t *args;
|
||||
int32_t retVal;
|
||||
|
||||
/* No excReturn value is needed as no exception handling is used */
|
||||
res = tfm_core_sfn_request_handler(desc_ptr, 0);
|
||||
|
||||
if (res != TFM_SUCCESS) {
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
/* Secure partition to secure partition call in TFM level 1 */
|
||||
args = desc_ptr->args;
|
||||
retVal = desc_ptr->sfn(args[0], args[1], args[2], args[3]);
|
||||
|
||||
/* return handler should restore original exc_return value... */
|
||||
res = tfm_return_from_partition(NULL);
|
||||
if (res == TFM_SUCCESS) {
|
||||
/* If unlock successful, pass SS return value to caller */
|
||||
res = retVal;
|
||||
} else {
|
||||
/* Unlock errors indicate ctx database corruption or unknown
|
||||
* anomalies. Halt execution
|
||||
*/
|
||||
ERROR_MSG("Secure API error during unlock!");
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
void tfm_core_validate_secure_caller_handler(uint32_t *svc_args)
|
||||
{
|
||||
|
||||
int32_t res = TFM_ERROR_GENERIC;
|
||||
uint32_t running_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
const struct spm_partition_runtime_data_t *curr_part_data =
|
||||
tfm_spm_partition_get_runtime_data(running_partition_idx);
|
||||
uint32_t running_partition_flags =
|
||||
tfm_spm_partition_get_flags(running_partition_idx);
|
||||
uint32_t caller_partition_flags =
|
||||
tfm_spm_partition_get_flags(curr_part_data->caller_partition_idx);
|
||||
|
||||
if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
|
||||
/* This handler shouldn't be called from outside partition context.
|
||||
* Partitions are only allowed to run while S domain is locked.
|
||||
*/
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Store return value in r0 */
|
||||
if (caller_partition_flags & SPM_PART_FLAG_APP_ROT) {
|
||||
res = TFM_SUCCESS;
|
||||
}
|
||||
svc_args[0] = res;
|
||||
}
|
||||
|
||||
int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
|
||||
void *start_addr,
|
||||
size_t len,
|
||||
uint32_t alignment)
|
||||
{
|
||||
uintptr_t start_addr_value = (uintptr_t)start_addr;
|
||||
uintptr_t end_addr_value = (uintptr_t)start_addr + len;
|
||||
uintptr_t alignment_mask;
|
||||
|
||||
alignment_mask = (((uintptr_t)1) << alignment) - 1;
|
||||
|
||||
/* Check that the pointer is aligned properly */
|
||||
if (start_addr_value & alignment_mask) {
|
||||
/* not aligned, return error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Protect against overflow (and zero len) */
|
||||
if (end_addr_value <= start_addr_value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if TFM_LVL == 1
|
||||
/* For privileged partition execution, all secure data memory and stack
|
||||
* is accessible
|
||||
*/
|
||||
if (start_addr_value >= S_DATA_START &&
|
||||
end_addr_value <= (S_DATA_START + S_DATA_SIZE)) {
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
/* For non-privileged execution the partition's data and stack is
|
||||
* accessible
|
||||
*/
|
||||
if (start_addr_value >=
|
||||
tfm_spm_partition_get_stack_bottom(partition_idx) &&
|
||||
end_addr_value <=
|
||||
tfm_spm_partition_get_stack_top(partition_idx)) {
|
||||
return 1;
|
||||
}
|
||||
if (start_addr_value >=
|
||||
tfm_spm_partition_get_rw_start(partition_idx) &&
|
||||
end_addr_value <=
|
||||
tfm_spm_partition_get_rw_limit(partition_idx)) {
|
||||
return 1;
|
||||
}
|
||||
if (start_addr_value >=
|
||||
tfm_spm_partition_get_zi_start(partition_idx) &&
|
||||
end_addr_value <=
|
||||
tfm_spm_partition_get_zi_limit(partition_idx)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tfm_core_get_caller_client_id_handler(uint32_t *svc_args)
|
||||
{
|
||||
uintptr_t result_ptr_value = svc_args[0];
|
||||
uint32_t running_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
const uint32_t running_partition_flags =
|
||||
tfm_spm_partition_get_flags(running_partition_idx);
|
||||
const struct spm_partition_runtime_data_t *curr_part_data =
|
||||
tfm_spm_partition_get_runtime_data(running_partition_idx);
|
||||
int res = 0;
|
||||
|
||||
if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
|
||||
/* This handler shouldn't be called from outside partition context.
|
||||
* Partitions are only allowed to run while S domain is locked.
|
||||
*/
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure that the output pointer points to a memory area that is owned
|
||||
* by the partition
|
||||
*/
|
||||
res = tfm_core_check_buffer_access(running_partition_idx,
|
||||
(void *)result_ptr_value,
|
||||
sizeof(curr_part_data->caller_client_id),
|
||||
2);
|
||||
if (!res) {
|
||||
/* Not in accessible range, return error */
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
*((int32_t *)result_ptr_value) = curr_part_data->caller_client_id;
|
||||
|
||||
/* Store return value in r0 */
|
||||
svc_args[0] = TFM_SUCCESS;
|
||||
}
|
||||
|
||||
void tfm_core_memory_permission_check_handler(uint32_t *svc_args)
|
||||
{
|
||||
uint32_t ptr = svc_args[0];
|
||||
uint32_t size = svc_args[1];
|
||||
int32_t access = svc_args[2];
|
||||
|
||||
uint32_t max_buf_size, ptr_start, range_limit, range_check = false;
|
||||
int32_t res;
|
||||
uint32_t running_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
const struct spm_partition_runtime_data_t *curr_part_data =
|
||||
tfm_spm_partition_get_runtime_data(running_partition_idx);
|
||||
uint32_t running_partition_flags =
|
||||
tfm_spm_partition_get_flags(running_partition_idx);
|
||||
int32_t flags = 0;
|
||||
void *rangeptr;
|
||||
|
||||
if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT) || (size == 0)) {
|
||||
/* This handler should only be called from a secure partition. */
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
if (curr_part_data->share != TFM_BUFFER_SHARE_PRIV) {
|
||||
flags |= CMSE_MPU_UNPRIV;
|
||||
}
|
||||
|
||||
if (access == TFM_MEMORY_ACCESS_RW) {
|
||||
flags |= CMSE_MPU_READWRITE;
|
||||
} else {
|
||||
flags |= CMSE_MPU_READ;
|
||||
}
|
||||
|
||||
/* Check if partition access to address would fail */
|
||||
rangeptr = cmse_check_address_range((void *)ptr, size, flags);
|
||||
|
||||
/* Get regions associated with address */
|
||||
cmse_address_info_t addr_info = cmse_TT((void *)ptr);
|
||||
|
||||
if (rangeptr == NULL) {
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr_info.flags.secure) {
|
||||
#if TFM_LVL == 1
|
||||
/* For privileged partition execution, all secure data memory is
|
||||
* accessible
|
||||
*/
|
||||
max_buf_size = S_DATA_SIZE;
|
||||
ptr_start = S_DATA_START;
|
||||
range_limit = S_DATA_LIMIT;
|
||||
#else
|
||||
/* Only scratch is permitted in secure memory */
|
||||
max_buf_size = (uint32_t)tfm_scratch_area_size;
|
||||
ptr_start = (uint32_t)tfm_scratch_area;
|
||||
range_limit = (uint32_t)tfm_scratch_area + tfm_scratch_area_size - 1;
|
||||
#endif
|
||||
range_check = true;
|
||||
} else {
|
||||
if (!addr_info.flags.sau_region_valid) {
|
||||
/* If address is NS, TF-M expects SAU to be configured
|
||||
*/
|
||||
svc_args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
switch (addr_info.flags.sau_region) {
|
||||
case TFM_NS_REGION_CODE:
|
||||
if (access == TFM_MEMORY_ACCESS_RW) {
|
||||
res = TFM_ERROR_INVALID_PARAMETER;
|
||||
} else {
|
||||
/* Currently TF-M does not support checks for NS Memory
|
||||
* accesses by partitions
|
||||
*/
|
||||
res = TFM_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case TFM_NS_REGION_DATA:
|
||||
/* Currently TF-M does not support checks for NS Memory
|
||||
* accesses by partitions
|
||||
*/
|
||||
res = TFM_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
/* Only NS data and code regions can be accessed as buffers */
|
||||
res = TFM_ERROR_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (range_check == true) {
|
||||
if ((size <= max_buf_size) && (ptr >= ptr_start)
|
||||
&& (ptr <= range_limit + 1 - size)) {
|
||||
res = TFM_SUCCESS;
|
||||
} else {
|
||||
res = TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store return value in r0 */
|
||||
svc_args[0] = res;
|
||||
}
|
||||
|
||||
/* This SVC handler is called if veneer is running in thread mode */
|
||||
uint32_t tfm_core_partition_request_svc_handler(
|
||||
struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
|
||||
{
|
||||
if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
|
||||
/* Service request SVC called with MSP active.
|
||||
* Either invalid configuration for Thread mode or SVC called
|
||||
* from Handler mode, which is not supported.
|
||||
* FixMe: error severity TBD
|
||||
*/
|
||||
ERROR_MSG("Service request SVC called with MSP active!");
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
|
||||
|
||||
if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
return EXC_RETURN_SECURE_FUNCTION;
|
||||
}
|
||||
|
||||
/* This SVC handler is called when sfn returns */
|
||||
uint32_t tfm_core_partition_return_handler(uint32_t lr)
|
||||
{
|
||||
int32_t res;
|
||||
|
||||
if (!(lr & EXC_RETURN_STACK_PROCESS)) {
|
||||
/* Partition return SVC called with MSP active.
|
||||
* This should not happen!
|
||||
*/
|
||||
ERROR_MSG("Partition return SVC called with MSP active!");
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
/* Store return value from secure partition */
|
||||
int32_t retVal = *(int32_t *)__get_PSP();
|
||||
|
||||
if ((retVal > TFM_SUCCESS) &&
|
||||
(retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
|
||||
/* Secure function returned a reserved value */
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
LOG_MSG("Invalid return value from secure partition!");
|
||||
#endif
|
||||
/* FixMe: error can be traced to specific secure partition
|
||||
* and Core is not compromised. Error handling flow can be
|
||||
* refined
|
||||
*/
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
res = tfm_return_from_partition(&lr);
|
||||
if (res != TFM_SUCCESS) {
|
||||
/* Unlock errors indicate ctx database corruption or unknown anomalies
|
||||
* Halt execution
|
||||
*/
|
||||
ERROR_MSG("Secure API error during unlock!");
|
||||
tfm_secure_api_error_handler();
|
||||
}
|
||||
|
||||
return lr;
|
||||
}
|
||||
|
||||
void tfm_core_set_buffer_area_handler(uint32_t *args)
|
||||
{
|
||||
/* r0 is stored in args[0] in exception stack frame
|
||||
* Store input parameter before writing return value to that address
|
||||
*/
|
||||
enum tfm_buffer_share_region_e share;
|
||||
uint32_t running_partition_idx =
|
||||
tfm_spm_partition_get_running_partition_idx();
|
||||
const struct spm_partition_runtime_data_t *curr_part_data =
|
||||
tfm_spm_partition_get_runtime_data(running_partition_idx);
|
||||
uint32_t caller_partition_idx = curr_part_data->caller_partition_idx;
|
||||
uint32_t running_partition_flags =
|
||||
tfm_spm_partition_get_flags(running_partition_idx);
|
||||
uint32_t caller_partition_flags =
|
||||
tfm_spm_partition_get_flags(caller_partition_idx);
|
||||
|
||||
/* tfm_core_set_buffer_area() returns int32_t */
|
||||
int32_t *res_ptr = (int32_t *)&args[0];
|
||||
|
||||
if (!(running_partition_flags & SPM_PART_FLAG_APP_ROT)) {
|
||||
/* This handler should only be called from a secure partition. */
|
||||
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case TFM_BUFFER_SHARE_DEFAULT:
|
||||
share = (!(caller_partition_flags & SPM_PART_FLAG_APP_ROT)) ?
|
||||
(TFM_BUFFER_SHARE_NS_CODE) : (TFM_BUFFER_SHARE_SCRATCH);
|
||||
break;
|
||||
case TFM_BUFFER_SHARE_SCRATCH:
|
||||
case TFM_BUFFER_SHARE_NS_CODE:
|
||||
share = args[0];
|
||||
break;
|
||||
default:
|
||||
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tfm_spm_partition_set_share(running_partition_idx, share) ==
|
||||
SPM_ERR_OK) {
|
||||
*res_ptr = TFM_SUCCESS;
|
||||
} else {
|
||||
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_SECURE_API_H__
|
||||
#define __TFM_SECURE_API_H__
|
||||
|
||||
#include "arm_cmse.h"
|
||||
#include "tfm_svc.h"
|
||||
#include "secure_utilities.h"
|
||||
#include "tfm_core.h"
|
||||
#include "tfm_api.h"
|
||||
|
||||
/*!
|
||||
* \def __tfm_secure_gateway_attributes__
|
||||
*
|
||||
* \brief Attributes for secure gateway functions
|
||||
*/
|
||||
#define __tfm_secure_gateway_attributes__ \
|
||||
__attribute__((cmse_nonsecure_entry, noinline, section("SFN")))
|
||||
|
||||
/* Hide specific errors if not debugging */
|
||||
#ifdef TFM_CORE_DEBUG
|
||||
#define TFM_ERROR_STATUS(status) (status)
|
||||
#else
|
||||
#define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY)
|
||||
#endif
|
||||
|
||||
#ifndef TFM_LVL
|
||||
#error TFM_LVL is not defined!
|
||||
#endif
|
||||
|
||||
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 sp_id;
|
||||
sfn_t sfn;
|
||||
int32_t *args;
|
||||
uint32_t caller_part_idx;
|
||||
int32_t ns_caller : 1;
|
||||
};
|
||||
|
||||
enum tfm_buffer_share_region_e {
|
||||
TFM_BUFFER_SHARE_DISABLE,
|
||||
TFM_BUFFER_SHARE_NS_CODE,
|
||||
TFM_BUFFER_SHARE_SCRATCH,
|
||||
TFM_BUFFER_SHARE_PRIV, /* only for TCB in level 2, all in level 1 */
|
||||
TFM_BUFFER_SHARE_DEFAULT,
|
||||
};
|
||||
|
||||
enum tfm_ns_region_e {
|
||||
TFM_NS_REGION_CODE = 0,
|
||||
TFM_NS_REGION_DATA,
|
||||
TFM_NS_REGION_VENEER,
|
||||
TFM_NS_REGION_PERIPH_1,
|
||||
TFM_NS_REGION_PERIPH_2,
|
||||
TFM_NS_SECONDARY_IMAGE_REGION,
|
||||
};
|
||||
|
||||
enum tfm_memory_access_e {
|
||||
TFM_MEMORY_ACCESS_RO = 1,
|
||||
TFM_MEMORY_ACCESS_RW = 2,
|
||||
};
|
||||
|
||||
extern int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share);
|
||||
|
||||
extern int32_t tfm_core_validate_secure_caller(void);
|
||||
|
||||
extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
|
||||
|
||||
extern int32_t tfm_core_memory_permission_check(
|
||||
void *ptr, uint32_t size, int32_t access);
|
||||
|
||||
extern int32_t tfm_core_get_boot_data(uint8_t major_type, void *ptr,
|
||||
uint32_t len);
|
||||
|
||||
int32_t tfm_core_sfn_request(struct tfm_sfn_req_s *desc_ptr);
|
||||
|
||||
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
|
||||
|
||||
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
|
||||
return tfm_core_partition_request(id, fn, (int32_t)a, (int32_t)b, \
|
||||
(int32_t)c, (int32_t)d)
|
||||
|
||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||
int32_t tfm_core_partition_request(uint32_t id, void *fn,
|
||||
int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
|
||||
{
|
||||
int32_t args[4] = {arg1, arg2, arg3, arg4};
|
||||
struct tfm_sfn_req_s desc, *desc_ptr = &desc;
|
||||
|
||||
desc.sp_id = id;
|
||||
desc.sfn = fn;
|
||||
desc.args = args;
|
||||
desc.ns_caller = cmse_nonsecure_caller();
|
||||
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
|
||||
/* FixMe: Error severity TBD */
|
||||
return TFM_ERROR_GENERIC;
|
||||
} else {
|
||||
#if TFM_LVL == 1
|
||||
if (desc.ns_caller) {
|
||||
return tfm_core_sfn_request(desc_ptr);
|
||||
} else {
|
||||
return tfm_core_sfn_request_thread_mode(desc_ptr);
|
||||
}
|
||||
#else
|
||||
return tfm_core_sfn_request(desc_ptr);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __TFM_SECURE_API_H__ */
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <arm_cmse.h>
|
||||
|
||||
#include "tfm_svc.h"
|
||||
#include "tfm_secure_api.h"
|
||||
#include "tfm_internal.h"
|
||||
#include "secure_fw/include/tfm_spm_services_api.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();
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH_8M_MAIN__)
|
||||
__attribute__((naked)) int32_t tfm_core_sfn_request(
|
||||
struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
__ASM(
|
||||
"PUSH {r4-r12, lr}\n"
|
||||
"SVC %[SVC_REQ]\n"
|
||||
"MOV r4, #0\n"
|
||||
"MOV r5, #0\n"
|
||||
"MOV r6, #0\n"
|
||||
"MOV r7, #0\n"
|
||||
"MOV r8, #0\n"
|
||||
"MOV r9, #0\n"
|
||||
"MOV r10, #0\n"
|
||||
"MOV r11, #0\n"
|
||||
"BLX lr\n"
|
||||
"SVC %[SVC_RET]\n"
|
||||
"POP {r4-r12, pc}\n"
|
||||
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
|
||||
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
|
||||
: "r0");
|
||||
}
|
||||
#elif defined(__ARM_ARCH_8M_BASE__)
|
||||
__attribute__((naked)) int32_t tfm_core_sfn_request(
|
||||
struct tfm_sfn_req_s *desc_ptr)
|
||||
{
|
||||
__ASM(
|
||||
".syntax unified\n"
|
||||
"PUSH {lr}\n"
|
||||
"PUSH {r4-r7}\n"
|
||||
"MOV r4, r8\n"
|
||||
"MOV r5, r9\n"
|
||||
"MOV r6, r10\n"
|
||||
"MOV r7, r11\n"
|
||||
"PUSH {r4-r7}\n"
|
||||
"MOV r4, r12\n"
|
||||
"PUSH {r4}\n"
|
||||
"SVC %[SVC_REQ]\n"
|
||||
"MOVS r4, #0\n"
|
||||
"MOV r5, r4\n"
|
||||
"MOV r6, r4\n"
|
||||
"MOV r7, r4\n"
|
||||
"MOV r8, r4\n"
|
||||
"MOV r9, r4\n"
|
||||
"MOV r10, r4\n"
|
||||
"MOV r11, r4\n"
|
||||
"BLX lr\n"
|
||||
"SVC %[SVC_RET]\n"
|
||||
"POP {r4}\n"
|
||||
"MOV r12, r4\n"
|
||||
"POP {r4-r7}\n"
|
||||
"MOV r8, r4\n"
|
||||
"MOV r9, r5\n"
|
||||
"MOV r10, r6\n"
|
||||
"MOV r11, r7\n"
|
||||
"POP {r4-r7}\n"
|
||||
"POP {pc}\n"
|
||||
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
|
||||
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
|
||||
: "r0");
|
||||
}
|
||||
#else
|
||||
#error "Unsupported ARM Architecture."
|
||||
#endif
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_core_memory_permission_check(
|
||||
void *ptr, uint32_t len, int32_t access)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX lr\n"
|
||||
: : "I" (TFM_SVC_MEMORY_CHECK));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX LR\n"
|
||||
: : "I" (TFM_SVC_GET_CALLER_CLIENT_ID));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_spm_request_reset_vote(void)
|
||||
{
|
||||
__ASM(
|
||||
"MOVS R0, %0\n"
|
||||
"B tfm_spm_request\n"
|
||||
: : "I" (TFM_SPM_REQUEST_RESET_VOTE));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_spm_request(void)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX lr\n"
|
||||
: : "I" (TFM_SVC_SPM_REQUEST));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_core_validate_secure_caller(void)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX lr\n"
|
||||
: : "I" (TFM_SVC_VALIDATE_SECURE_CALLER));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX lr\n"
|
||||
: : "I" (TFM_SVC_SET_SHARE_AREA));
|
||||
}
|
||||
|
||||
__attribute__((naked))
|
||||
int32_t tfm_core_get_boot_data(uint8_t major_type, void *ptr, uint32_t len)
|
||||
{
|
||||
__ASM(
|
||||
"SVC %0\n"
|
||||
"BX lr\n"
|
||||
: : "I" (TFM_SVC_GET_BOOT_DATA));
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_SVC_H__
|
||||
#define __TFM_SVC_H__
|
||||
|
||||
#include "cmsis.h"
|
||||
|
||||
typedef enum {
|
||||
TFM_SVC_SFN_REQUEST = 0,
|
||||
TFM_SVC_SFN_RETURN,
|
||||
TFM_SVC_VALIDATE_SECURE_CALLER,
|
||||
TFM_SVC_GET_CALLER_CLIENT_ID,
|
||||
TFM_SVC_MEMORY_CHECK,
|
||||
TFM_SVC_SET_SHARE_AREA,
|
||||
TFM_SVC_SPM_REQUEST,
|
||||
TFM_SVC_PRINT,
|
||||
TFM_SVC_GET_BOOT_DATA,
|
||||
#ifdef TFM_PSA_API
|
||||
TFM_SVC_IPC_REQUEST,
|
||||
TFM_SVC_SCHEDULE,
|
||||
/* PSA Client SVC */
|
||||
TFM_SVC_PSA_FRAMEWORK_VERSION,
|
||||
TFM_SVC_PSA_VERSION,
|
||||
TFM_SVC_PSA_CONNECT,
|
||||
TFM_SVC_PSA_CALL,
|
||||
TFM_SVC_PSA_CLOSE,
|
||||
/* PSA Service SVC */
|
||||
TFM_SVC_PSA_WAIT,
|
||||
TFM_SVC_PSA_GET,
|
||||
TFM_SVC_PSA_SET_RHANDLE,
|
||||
TFM_SVC_PSA_READ,
|
||||
TFM_SVC_PSA_SKIP,
|
||||
TFM_SVC_PSA_WRITE,
|
||||
TFM_SVC_PSA_REPLY,
|
||||
TFM_SVC_PSA_NOTIFY,
|
||||
TFM_SVC_PSA_CLEAR,
|
||||
TFM_SVC_PSA_EOI,
|
||||
#endif
|
||||
} tfm_svc_number_t;
|
||||
|
||||
#define SVC(code) __ASM("svc %0" : : "I" (code))
|
||||
|
||||
#endif /* __TFM_SVC_H__ */
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_SPM_SERVICES_API_H__
|
||||
#define __TFM_SPM_SERVICES_API_H__
|
||||
|
||||
enum tfm_spm_request_type_t {
|
||||
TFM_SPM_REQUEST_RESET_VOTE,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Request a vote from SPM on a system reset
|
||||
*
|
||||
* \return Returns 0 if request is accepted, any other value means reject
|
||||
*/
|
||||
int32_t tfm_spm_request_reset_vote(void);
|
||||
|
||||
#endif /* __TFM_SPM_SERVICES_API_H__ */
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, 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_APP_ROT | SPM_PART_FLAG_PSA_ROT;
|
||||
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
|
||||
++g_spm_partition_db.partition_count;
|
||||
|
||||
/* Add user-defined secure partitions */
|
||||
#include "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];
|
||||
#ifdef TFM_PSA_API
|
||||
if (part->static_data.partition_flags & SPM_PART_FLAG_IPC) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SPM_API_H__
|
||||
#define __SPM_API_H__
|
||||
|
||||
/* This file contains the apis exported by the SPM to tfm core */
|
||||
#include "spm_partition_defs.h"
|
||||
#include "secure_fw/core/tfm_secure_api.h"
|
||||
|
||||
#define SPM_INVALID_PARTITION_IDX (~0U)
|
||||
|
||||
enum spm_err_t {
|
||||
SPM_ERR_OK = 0,
|
||||
SPM_ERR_PARTITION_DB_NOT_INIT,
|
||||
SPM_ERR_PARTITION_ALREADY_ACTIVE,
|
||||
SPM_ERR_PARTITION_NOT_AVAILABLE,
|
||||
SPM_ERR_INVALID_CONFIG,
|
||||
};
|
||||
|
||||
enum spm_part_state_t {
|
||||
SPM_PARTITION_STATE_UNINIT = 0,
|
||||
SPM_PARTITION_STATE_IDLE,
|
||||
SPM_PARTITION_STATE_RUNNING,
|
||||
SPM_PARTITION_STATE_SUSPENDED,
|
||||
SPM_PARTITION_STATE_BLOCKED,
|
||||
SPM_PARTITION_STATE_CLOSED
|
||||
};
|
||||
|
||||
enum spm_part_flag_mask_t {
|
||||
SPM_PART_FLAG_APP_ROT = 0x01,
|
||||
SPM_PART_FLAG_PSA_ROT = 0x02,
|
||||
SPM_PART_FLAG_IPC = 0x04
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Runtime context information of a partition
|
||||
*/
|
||||
struct spm_partition_runtime_data_t {
|
||||
uint32_t partition_state;
|
||||
uint32_t caller_partition_idx;
|
||||
int32_t caller_client_id;
|
||||
uint32_t share;
|
||||
uint32_t stack_ptr;
|
||||
uint32_t lr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns the index of the partition with the given partition ID.
|
||||
*
|
||||
* \param[in] partition_id Partition id
|
||||
*
|
||||
* \return the partition idx if partition_id is valid,
|
||||
* \ref SPM_INVALID_PARTITION_IDX othervise
|
||||
*/
|
||||
uint32_t get_partition_idx(uint32_t partition_id);
|
||||
|
||||
/**
|
||||
* \brief Configure isolated sandbox for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Error code \ref spm_err_t
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Deconfigure sandbox for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Error code \ref spm_err_t
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get bottom of stack region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Stack region bottom value
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get top of stack region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Stack region top value
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the id of the partition for its index from the db
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Partition ID for that partition
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the flags associated with a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return Flags associated with the partition
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the start of the zero-initialised region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition idx
|
||||
*
|
||||
* \return Start of the zero-initialised region
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the limit of the zero-initialised region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition idx
|
||||
*
|
||||
* \return Limit of the zero-initialised region
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
* \note The address returned is not part of the region.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the start of the read-write region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition idx
|
||||
*
|
||||
* \return Start of the read-write region
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the limit of the read-write region for a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition idx
|
||||
*
|
||||
* \return Limit of the read-write region
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
* \note The address returned is not part of the region.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Get the current runtime data of a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \return The runtime data of the specified partition
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
const struct spm_partition_runtime_data_t *
|
||||
tfm_spm_partition_get_runtime_data(uint32_t partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Returns the index of the partition that has running state
|
||||
*
|
||||
* \return The index of the partition with the running state, if there is any
|
||||
* set. 0 otherwise.
|
||||
*/
|
||||
uint32_t tfm_spm_partition_get_running_partition_idx(void);
|
||||
|
||||
/**
|
||||
* \brief Save stack pointer for partition in database
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] stack_ptr Stack pointer to be stored
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
void tfm_spm_partition_set_stack(uint32_t partition_id, uint32_t stack_ptr);
|
||||
|
||||
/**
|
||||
* \brief Save stack pointer and link register for partition in database
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] stack_ptr Stack pointer to be stored
|
||||
* \param[in] lr Link register to be stored
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
void tfm_spm_partition_store_context(uint32_t partition_idx,
|
||||
uint32_t stack_ptr, uint32_t lr);
|
||||
|
||||
/**
|
||||
* \brief Set the current state of a partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] state The state to be set
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
* \note The \ref state has to have the value set of \ref spm_part_state_t.
|
||||
*/
|
||||
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
|
||||
|
||||
/**
|
||||
* \brief Set the caller partition index for a given partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] caller_partition_idx The index of the caller partition
|
||||
*
|
||||
* \note This function doesn't check if any of the partition_idxs are valid.
|
||||
*/
|
||||
void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
|
||||
uint32_t caller_partition_idx);
|
||||
|
||||
/**
|
||||
* \brief Set the caller client ID for a given partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] caller_client_id The ID of the calling client
|
||||
*
|
||||
* \note This function doesn't check if any of the partition_idxs are valid.
|
||||
*/
|
||||
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
|
||||
int32_t caller_client_id);
|
||||
|
||||
/**
|
||||
* \brief Set the buffer share region of the partition
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
* \param[in] share The buffer share region to be set
|
||||
*
|
||||
* \return Error code \ref spm_err_t
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
* \note share has to have the value set of \ref tfm_buffer_share_region_e
|
||||
*/
|
||||
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
|
||||
uint32_t share);
|
||||
|
||||
/**
|
||||
* \brief Initialize partition database
|
||||
*
|
||||
* \return Error code \ref spm_err_t
|
||||
*/
|
||||
enum spm_err_t tfm_spm_db_init(void);
|
||||
|
||||
/**
|
||||
* \brief Execute partition init function
|
||||
*
|
||||
* \return Error code \ref spm_err_t
|
||||
*/
|
||||
enum spm_err_t tfm_spm_partition_init(void);
|
||||
|
||||
/**
|
||||
* \brief Clears the context info from the database for a partition.
|
||||
*
|
||||
* \param[in] partition_idx Partition index
|
||||
*
|
||||
* \note This function doesn't check if partition_idx is valid.
|
||||
*/
|
||||
void tfm_spm_partition_cleanup_context(uint32_t partition_idx);
|
||||
|
||||
#endif /*__SPM_API_H__ */
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SPM_DB_H__
|
||||
#define __SPM_DB_H__
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
#include "tfm_thread.h"
|
||||
#endif
|
||||
|
||||
struct spm_partition_desc_t;
|
||||
struct spm_partition_db_t;
|
||||
|
||||
uint32_t get_partition_idx(uint32_t partition_id);
|
||||
|
||||
typedef int32_t(*sp_init_function)(void);
|
||||
|
||||
#define TFM_PARTITION_TYPE_APP "APPLICATION-ROT"
|
||||
#define TFM_PARTITION_TYPE_PSA "PSA-ROT"
|
||||
|
||||
#define TFM_STACK_SIZE 1024
|
||||
|
||||
#ifdef TFM_PSA_API
|
||||
enum tfm_partition_priority {
|
||||
TFM_PRIORITY_LOW = THRD_PRIOR_LOWEST,
|
||||
TFM_PRIORITY_NORMAL = THRD_PRIOR_MEDIUM,
|
||||
TFM_PRIORITY_HIGH = THRD_PRIOR_HIGHEST,
|
||||
};
|
||||
#else
|
||||
enum tfm_partition_priority {
|
||||
TFM_PRIORITY_LOW = 0xFF,
|
||||
TFM_PRIORITY_NORMAL = 0x7F,
|
||||
TFM_PRIORITY_HIGH = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
#define TFM_PRIORITY(LEVEL) TFM_PRIORITY_##LEVEL
|
||||
|
||||
/**
|
||||
* Holds the fields of the partition DB used by the SPM code. The values of
|
||||
* these fields are calculated at compile time, and set during initialisation
|
||||
* phase.
|
||||
*/
|
||||
struct spm_partition_static_data_t {
|
||||
uint32_t partition_id;
|
||||
uint32_t partition_flags;
|
||||
uint32_t partition_priority;
|
||||
sp_init_function partition_init;
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds the fields that define a partition for SPM. The fields are further
|
||||
* divided to structures, to keep the related fields close to each other.
|
||||
*/
|
||||
struct spm_partition_desc_t {
|
||||
struct spm_partition_static_data_t static_data;
|
||||
struct spm_partition_runtime_data_t runtime_data;
|
||||
struct tfm_spm_partition_platform_data_t *platform_data;
|
||||
#if TFM_LVL != 1
|
||||
struct tfm_spm_partition_memory_data_t memory_data;
|
||||
#endif
|
||||
#ifdef TFM_PSA_API
|
||||
struct tfm_thrd_ctx sp_thrd;
|
||||
/*
|
||||
* stack_limit points to starting address of the partitions' stack plus the partitions' stack size.
|
||||
*/
|
||||
uint32_t stack_limit;
|
||||
uint32_t stack_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Macros to pick linker symbols and allow to form the partition data base */
|
||||
#define REGION(a, b, c) a##b##c
|
||||
#define REGION_NAME(a, b, c) REGION(a, b, c)
|
||||
#if TFM_LVL == 1
|
||||
#define REGION_DECLARE(a, b, c)
|
||||
#else
|
||||
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
||||
#define PART_REGION_ADDR(partition, region) \
|
||||
(uint32_t)®ION_NAME(Image$$, partition, region)
|
||||
#endif
|
||||
|
||||
#endif /* __SPM_DB_H__ */
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SPM_DB_SETUP_H__
|
||||
#define __SPM_DB_SETUP_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "spm_db.h"
|
||||
|
||||
/**
|
||||
* \brief Get the index of a partition.
|
||||
*
|
||||
* Gets the index of a partition in the partition db based on the partition ID
|
||||
* provided as a parameter.
|
||||
*
|
||||
* \param[in] partition_id The ID of the partition
|
||||
*
|
||||
* \return \ref INVALID_PARTITION_IDX if the provided ID is invalid. The index
|
||||
* of the partition otherwise.
|
||||
*/
|
||||
uint32_t get_partition_idx(uint32_t partition_id);
|
||||
|
||||
struct spm_partition_db_t {
|
||||
uint32_t is_init;
|
||||
uint32_t partition_count;
|
||||
uint32_t running_partition_idx;
|
||||
struct spm_partition_desc_t partitions[SPM_MAX_PARTITIONS];
|
||||
};
|
||||
|
||||
#define PARTITION_INIT_STATIC_DATA(data, partition, flags, id, priority) \
|
||||
do { \
|
||||
data.partition_id = partition##_ID; \
|
||||
data.partition_flags = flags; \
|
||||
data.partition_priority = TFM_PRIORITY(priority); \
|
||||
} while (0)
|
||||
|
||||
#if TFM_LVL == 1
|
||||
#define PARTITION_INIT_MEMORY_DATA(data, partition)
|
||||
#else
|
||||
#define PARTITION_INIT_MEMORY_DATA(data, partition) \
|
||||
do { \
|
||||
data.code_start = PART_REGION_ADDR(partition, $$Base); \
|
||||
data.code_limit = PART_REGION_ADDR(partition, $$Limit); \
|
||||
data.ro_start = PART_REGION_ADDR(partition, $$RO$$Base); \
|
||||
data.ro_limit = PART_REGION_ADDR(partition, $$RO$$Limit); \
|
||||
data.rw_start = PART_REGION_ADDR(partition, _DATA$$RW$$Base); \
|
||||
data.rw_limit = PART_REGION_ADDR(partition, _DATA$$RW$$Limit); \
|
||||
data.zi_start = PART_REGION_ADDR(partition, _DATA$$ZI$$Base); \
|
||||
data.zi_limit = PART_REGION_ADDR(partition, _DATA$$ZI$$Limit); \
|
||||
data.stack_bottom = PART_REGION_ADDR(partition, _STACK$$ZI$$Base); \
|
||||
data.stack_top = PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#if TFM_LVL == 1
|
||||
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
|
||||
do { \
|
||||
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
|
||||
} while (0)
|
||||
#else
|
||||
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
|
||||
do { \
|
||||
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
|
||||
data.stack_ptr = \
|
||||
PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define PARTITION_DECLARE(partition, flag, type, id, priority, part_stack_size) \
|
||||
do { \
|
||||
REGION_DECLARE(Image$$, partition, $$Base); \
|
||||
REGION_DECLARE(Image$$, partition, $$Limit); \
|
||||
REGION_DECLARE(Image$$, partition, $$RO$$Base); \
|
||||
REGION_DECLARE(Image$$, partition, $$RO$$Limit); \
|
||||
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Base); \
|
||||
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Limit); \
|
||||
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Base); \
|
||||
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Limit); \
|
||||
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Base); \
|
||||
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Limit); \
|
||||
int32_t flags = flag; \
|
||||
if (tfm_memcmp(type, TFM_PARTITION_TYPE_APP, \
|
||||
strlen(TFM_PARTITION_TYPE_APP)) == 0) { \
|
||||
flags |= SPM_PART_FLAG_APP_ROT; \
|
||||
} else if (tfm_memcmp(type, TFM_PARTITION_TYPE_PSA, \
|
||||
strlen(TFM_PARTITION_TYPE_PSA)) == 0) { \
|
||||
flags |= SPM_PART_FLAG_PSA_ROT | SPM_PART_FLAG_APP_ROT; \
|
||||
} else { \
|
||||
return SPM_ERR_INVALID_CONFIG; \
|
||||
} \
|
||||
struct spm_partition_desc_t *part_ptr; \
|
||||
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) { \
|
||||
return SPM_ERR_INVALID_CONFIG; \
|
||||
} \
|
||||
__attribute__((section(".data.partitions_stacks"))) \
|
||||
static uint8_t partition##_stack[part_stack_size] __attribute__((aligned(8))); \
|
||||
part_ptr = &(g_spm_partition_db.partitions[ \
|
||||
g_spm_partition_db.partition_count]); \
|
||||
part_ptr->stack_limit = (uint32_t)partition##_stack; \
|
||||
part_ptr->stack_size = part_stack_size; \
|
||||
PARTITION_INIT_STATIC_DATA(part_ptr->static_data, partition, flags, \
|
||||
id, priority); \
|
||||
PARTITION_INIT_RUNTIME_DATA(part_ptr->runtime_data, partition); \
|
||||
PARTITION_INIT_MEMORY_DATA(part_ptr->memory_data, partition); \
|
||||
++g_spm_partition_db.partition_count; \
|
||||
} while (0)
|
||||
|
||||
#define PARTITION_ADD_INIT_FUNC(partition, init_func) \
|
||||
do { \
|
||||
extern int32_t init_func(void); \
|
||||
uint32_t partition_idx = get_partition_idx(partition##_ID); \
|
||||
struct spm_partition_desc_t *part_ptr = \
|
||||
&(g_spm_partition_db.partitions[partition_idx]); \
|
||||
part_ptr->static_data.partition_init = init_func; \
|
||||
} while (0)
|
||||
|
||||
#define PARTITION_ADD_PERIPHERAL(partition, peripheral) \
|
||||
do { \
|
||||
uint32_t partition_idx = get_partition_idx(partition##_ID); \
|
||||
struct spm_partition_desc_t *part_ptr = \
|
||||
&(g_spm_partition_db.partitions[partition_idx]); \
|
||||
part_ptr->platform_data = peripheral; \
|
||||
} while (0)
|
||||
|
||||
#endif /* __SPM_DB_SETUP_H__ */
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SPM_PARTITION_DEFS_H__
|
||||
#define __SPM_PARTITION_DEFS_H__
|
||||
|
||||
/* FixMe: allocations to be settled.
|
||||
* 8 bits reserved by TFM for secure partition Id in this prototype
|
||||
*/
|
||||
#define TFM_SP_BASE 256
|
||||
|
||||
/* A reserved partition ID that is used for uninitialised data */
|
||||
#define INVALID_PARTITION_ID (~0U)
|
||||
|
||||
/* ***** partition ID-s internal to the TFM ***** */
|
||||
#define TFM_INTERNAL_PARTITIONS (2)
|
||||
|
||||
/* 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_SP_NON_SECURE_ID (0)
|
||||
/* A dummy partition for TFM_SP_CORE is created to handle secure partition
|
||||
* calls done directly from the core, before NS execution started.
|
||||
*/
|
||||
#define TFM_SP_CORE_ID (1)
|
||||
|
||||
#include "tfm_partition_defs.inc"
|
||||
|
||||
/* This limit is only used to define the size of the database reserved for
|
||||
* partitions. There's no requirement that it match the number of partitions
|
||||
* that get registered in a specific build
|
||||
*/
|
||||
#define SPM_MAX_PARTITIONS (TFM_MAX_USER_PARTITIONS + TFM_INTERNAL_PARTITIONS)
|
||||
|
||||
#endif /* __SPM_PARTITION_DEFS_H__ */
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license,
|
||||
as can be found in: LICENSE-bsd-3-clause.txt
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
Copyright 2019 Arm Limited and affiliates.
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PSA_CLIENT_H__
|
||||
#define __PSA_CLIENT_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/*********************** PSA Client Macros and Types *************************/
|
||||
|
||||
#define PSA_FRAMEWORK_VERSION (0x0100)
|
||||
|
||||
#define PSA_VERSION_NONE (0)
|
||||
|
||||
/* PSA response types */
|
||||
#define PSA_SUCCESS (0)
|
||||
#define PSA_CONNECTION_REFUSED (INT32_MIN + 1)
|
||||
#define PSA_CONNECTION_BUSY (INT32_MIN + 2)
|
||||
#define PSA_DROP_CONNECTION (INT32_MIN)
|
||||
|
||||
/* PSA message handles */
|
||||
#define PSA_NULL_HANDLE ((psa_handle_t)0)
|
||||
|
||||
typedef int32_t psa_status_t;
|
||||
typedef int32_t psa_handle_t;
|
||||
|
||||
/**
|
||||
* A read-only input memory region provided to an RoT Service.
|
||||
*/
|
||||
typedef struct psa_invec {
|
||||
const void *base; /*!< the start address of the memory buffer */
|
||||
size_t len; /*!< the size in bytes */
|
||||
} psa_invec;
|
||||
|
||||
/**
|
||||
* A writable output memory region provided to an RoT Service.
|
||||
*/
|
||||
typedef struct psa_outvec {
|
||||
void *base; /*!< the start address of the memory buffer */
|
||||
size_t len; /*!< the size in bytes */
|
||||
} psa_outvec;
|
||||
|
||||
/*************************** PSA Client API **********************************/
|
||||
|
||||
/**
|
||||
* \brief Retrieve the version of the PSA Framework API that is implemented.
|
||||
*
|
||||
* \return version The version of the PSA Framework implementation
|
||||
* that is providing the runtime services to the
|
||||
* caller. The major and minor version are encoded
|
||||
* as follows:
|
||||
* \arg version[15:8] -- major version number.
|
||||
* \arg version[7:0] -- minor version number.
|
||||
*/
|
||||
uint32_t psa_framework_version(void);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the minor version of an RoT Service or indicate that it is
|
||||
* not present on this system.
|
||||
*
|
||||
* \param[in] sid ID of the RoT Service to query.
|
||||
*
|
||||
* \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
|
||||
* caller is not permitted to access the service.
|
||||
* \retval > 0 The minor version of the implemented RoT
|
||||
* Service.
|
||||
*/
|
||||
uint32_t psa_version(uint32_t sid);
|
||||
|
||||
/**
|
||||
* \brief Connect to an RoT Service by its SID.
|
||||
*
|
||||
* \param[in] sid ID of the RoT Service to connect to.
|
||||
* \param[in] minor_version Requested version of the RoT Service.
|
||||
*
|
||||
* \retval > 0 A handle for the connection.
|
||||
* \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
|
||||
* connection.
|
||||
* \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the
|
||||
* connection at the moment.
|
||||
* \retval "Does not return" The RoT Service ID and version are not
|
||||
* supported, or the caller is not permitted to
|
||||
* access the service.
|
||||
*/
|
||||
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version);
|
||||
|
||||
/**
|
||||
* \brief Call an RoT Service on an established connection.
|
||||
*
|
||||
* \param[in] handle A handle to an established connection.
|
||||
* \param[in] in_vec Array of input \ref psa_invec structures.
|
||||
* \param[in] in_len Number of input \ref psa_invec structures.
|
||||
* \param[in/out] out_vec Array of output \ref psa_outvec structures.
|
||||
* \param[in] out_len Number of output \ref psa_outvec structures.
|
||||
*
|
||||
* \retval >=0 RoT Service-specific status value.
|
||||
* \retval <0 RoT Service-specific error code.
|
||||
* \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
|
||||
* Service. This indicates that either this or
|
||||
* a previous message was invalid.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg An invalid handle was passed.
|
||||
* \arg The connection is already handling a request.
|
||||
* \arg An invalid memory reference was provided.
|
||||
* \arg in_len + out_len > PSA_MAX_IOVEC.
|
||||
* \arg The message is unrecognized by the RoT
|
||||
* Service or incorrectly formatted.
|
||||
*/
|
||||
psa_status_t psa_call(psa_handle_t handle,
|
||||
const psa_invec *in_vec,
|
||||
size_t in_len,
|
||||
psa_outvec *out_vec,
|
||||
size_t out_len);
|
||||
|
||||
/**
|
||||
* \brief Close a connection to an RoT Service.
|
||||
*
|
||||
* \param[in] handle A handle to an established connection, or the
|
||||
* null handle.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg An invalid handle was provided that is not
|
||||
* the null handle.
|
||||
* \arg The connection is handling a request.
|
||||
*/
|
||||
void psa_close(psa_handle_t handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PSA_CLIENT_H__ */
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PSA_SERVICE_H__
|
||||
#define __PSA_SERVICE_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/********************** PSA Secure Partition Macros and Types ****************/
|
||||
|
||||
/* PSA wait timeouts */
|
||||
#define PSA_POLL (0x00000000u)
|
||||
#define PSA_BLOCK (0x80000000u)
|
||||
|
||||
/* A mask value that includes all Secure Partition signals */
|
||||
#define PSA_WAIT_ANY (~0u)
|
||||
|
||||
/* Doorbell signal */
|
||||
#define PSA_DOORBELL (0x00000008u)
|
||||
|
||||
/* PSA message types */
|
||||
#define PSA_IPC_CONNECT (1)
|
||||
#define PSA_IPC_CALL (2)
|
||||
#define PSA_IPC_DISCONNECT (3)
|
||||
|
||||
/* Maximum number of input and output vectors */
|
||||
#define PSA_MAX_IOVEC (4)
|
||||
|
||||
/* Return code from psa_get() */
|
||||
#define PSA_ERR_NOMSG (INT32_MIN + 3)
|
||||
|
||||
/* Store a set of one or more Secure Partition signals */
|
||||
typedef uint32_t psa_signal_t;
|
||||
|
||||
/**
|
||||
* Describe a message received by an RoT Service after calling \ref psa_get().
|
||||
*/
|
||||
typedef struct psa_msg_t {
|
||||
uint32_t type; /* One of the following values:
|
||||
* \ref PSA_IPC_CONNECT
|
||||
* \ref PSA_IPC_CALL
|
||||
* \ref PSA_IPC_DISCONNECT
|
||||
*/
|
||||
psa_handle_t handle; /* A reference generated by the SPM to the
|
||||
* message returned by psa_get().
|
||||
*/
|
||||
int32_t client_id; /* Partition ID of the sender of the message */
|
||||
void *rhandle; /* Be useful for binding a connection to some
|
||||
* application-specific data or function
|
||||
* pointer within the RoT Service
|
||||
* implementation.
|
||||
*/
|
||||
size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
|
||||
* vector in bytes.
|
||||
*/
|
||||
size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
|
||||
* vector in bytes.
|
||||
*/
|
||||
} psa_msg_t;
|
||||
|
||||
/************************* PSA Secure Partition API **************************/
|
||||
|
||||
/**
|
||||
* \brief Return the Secure Partition interrupt signals that have been asserted
|
||||
* from a subset of signals provided by the caller.
|
||||
*
|
||||
* \param[in] signal_mask A set of signals to query. Signals that are not
|
||||
* in this set will be ignored.
|
||||
* \param[in] timeout Specify either blocking \ref PSA_BLOCK or
|
||||
* polling \ref PSA_POLL operation.
|
||||
*
|
||||
* \retval >0 At least one signal is asserted.
|
||||
* \retval 0 No signals are asserted. This is only seen when
|
||||
* a polling timeout is used.
|
||||
*/
|
||||
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the message which corresponds to a given RoT Service signal
|
||||
* and remove the message from the RoT Service queue.
|
||||
*
|
||||
* \param[in] signal The signal value for an asserted RoT Service.
|
||||
* \param[out] msg Pointer to \ref psa_msg_t object for receiving
|
||||
* the message.
|
||||
*
|
||||
* \retval PSA_SUCCESS Success, *msg will contain the delivered
|
||||
* message.
|
||||
* \retval PSA_ERR_NOMSG Message could not be delivered.
|
||||
* \retval "Does not return" The call is invalid because one or more of the
|
||||
* following are true:
|
||||
* \arg signal has more than a single bit set.
|
||||
* \arg signal does not correspond to an RoT Service.
|
||||
* \arg The RoT Service signal is not currently
|
||||
* asserted.
|
||||
* \arg The msg pointer provided is not a valid memory
|
||||
* reference.
|
||||
*/
|
||||
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
|
||||
|
||||
/**
|
||||
* \brief Associate some RoT Service private data with a client connection.
|
||||
*
|
||||
* \param[in] msg_handle Handle for the client's message.
|
||||
* \param[in] rhandle Reverse handle allocated by the RoT Service.
|
||||
*
|
||||
* \retval void Success, rhandle will be provided with all
|
||||
* subsequent messages delivered on this
|
||||
* connection.
|
||||
* \retval "Does not return" msg_handle is invalid.
|
||||
*/
|
||||
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
|
||||
|
||||
/**
|
||||
* \brief Read a message parameter or part of a message parameter from a client
|
||||
* input vector.
|
||||
*
|
||||
* \param[in] msg_handle Handle for the client's message.
|
||||
* \param[in] invec_idx Index of the input vector to read from. Must be
|
||||
* less than \ref PSA_MAX_IOVEC.
|
||||
* \param[out] buffer Buffer in the Secure Partition to copy the
|
||||
* requested data to.
|
||||
* \param[in] num_bytes Maximum number of bytes to be read from the
|
||||
* client input vector.
|
||||
*
|
||||
* \retval >0 Number of bytes copied.
|
||||
* \retval 0 There was no remaining data in this input
|
||||
* vector.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg invec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
* \arg the memory reference for buffer is invalid or
|
||||
* not writable.
|
||||
*/
|
||||
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
|
||||
void *buffer, size_t num_bytes);
|
||||
|
||||
/**
|
||||
* \brief Skip over part of a client input vector.
|
||||
*
|
||||
* \param[in] msg_handle Handle for the client's message.
|
||||
* \param[in] invec_idx Index of input vector to skip from. Must be
|
||||
* less than \ref PSA_MAX_IOVEC.
|
||||
* \param[in] num_bytes Maximum number of bytes to skip in the client
|
||||
* input vector.
|
||||
*
|
||||
* \retval >0 Number of bytes skipped.
|
||||
* \retval 0 There was no remaining data in this input
|
||||
* vector.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg invec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
*/
|
||||
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
|
||||
|
||||
/**
|
||||
* \brief Write a message response to a client output vector.
|
||||
*
|
||||
* \param[in] msg_handle Handle for the client's message.
|
||||
* \param[out] outvec_idx Index of output vector in message to write to.
|
||||
* Must be less than \ref PSA_MAX_IOVEC.
|
||||
* \param[in] buffer Buffer with the data to write.
|
||||
* \param[in] num_bytes Number of bytes to write to the client output
|
||||
* vector.
|
||||
*
|
||||
* \retval void Success
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg msg_handle does not refer to a
|
||||
* \ref PSA_IPC_CALL message.
|
||||
* \arg outvec_idx is equal to or greater than
|
||||
* \ref PSA_MAX_IOVEC.
|
||||
* \arg The memory reference for buffer is invalid.
|
||||
* \arg The call attempts to write data past the end
|
||||
* of the client output vector.
|
||||
*/
|
||||
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
|
||||
const void *buffer, size_t num_bytes);
|
||||
|
||||
/**
|
||||
* \brief Complete handling of a specific message and unblock the client.
|
||||
*
|
||||
* \param[in] msg_handle Handle for the client's message.
|
||||
* \param[in] status Message result value to be reported to the
|
||||
* client.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg msg_handle is invalid.
|
||||
* \arg An invalid status code is specified for the
|
||||
* type of message.
|
||||
*/
|
||||
void psa_reply(psa_handle_t msg_handle, psa_status_t status);
|
||||
|
||||
/**
|
||||
* \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
|
||||
*
|
||||
* \param[in] partition_id Secure Partition ID of the target partition.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" partition_id does not correspond to a Secure
|
||||
* Partition.
|
||||
*/
|
||||
void psa_notify(int32_t partition_id);
|
||||
|
||||
/**
|
||||
* \brief Clear the PSA_DOORBELL signal.
|
||||
*
|
||||
* \param[in] void
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The Secure Partition's doorbell signal is not
|
||||
* currently asserted.
|
||||
*/
|
||||
void psa_clear(void);
|
||||
|
||||
/**
|
||||
* \brief Inform the SPM that an interrupt has been handled (end of interrupt).
|
||||
*
|
||||
* \param[in] irq_signal The interrupt signal that has been processed.
|
||||
*
|
||||
* \retval void Success.
|
||||
* \retval "Does not return" The call is invalid, one or more of the
|
||||
* following are true:
|
||||
* \arg irq_signal is not an interrupt signal.
|
||||
* \arg irq_signal indicates more than one signal.
|
||||
* \arg irq_signal is not currently asserted.
|
||||
*/
|
||||
void psa_eoi(psa_signal_t irq_signal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PSA_SERVICE_H__ */
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_API_H__
|
||||
#define __TFM_API_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "interface/include/psa_client.h"
|
||||
|
||||
#define TFM_INVALID_CLIENT_ID 0
|
||||
|
||||
/**
|
||||
* \brief Checks if the provided client ID is a secure client ID.
|
||||
*
|
||||
* \param[in] client_id Client ID to check
|
||||
*
|
||||
* \return Returns 1 if the client Id is secure. Otherwise, returns 0.
|
||||
*/
|
||||
#define TFM_CLIENT_ID_IS_S(client_id) ((client_id)>0)
|
||||
|
||||
/**
|
||||
* \brief Checks if the provided client ID is a non-secure client ID.
|
||||
*
|
||||
* \param[in] client_id Client ID to check
|
||||
*
|
||||
* \return Returns 1 if the client Id is non-secure. Otherwise, returns 0.
|
||||
*/
|
||||
#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0)
|
||||
|
||||
/* FixMe: sort out DEBUG compile option and limit return value options
|
||||
* on external interfaces */
|
||||
/* Note:
|
||||
* TFM will only return values recognized and parsed by TFM core.
|
||||
* Service return codes are not automatically passed on to REE.
|
||||
* Any non-zero return value is interpreted as an error that may trigger
|
||||
* TEE error handling flow.
|
||||
*/
|
||||
enum tfm_status_e
|
||||
{
|
||||
TFM_SUCCESS = 0,
|
||||
TFM_PARTITION_BUSY,
|
||||
TFM_ERROR_SECURE_DOMAIN_LOCKED,
|
||||
TFM_ERROR_INVALID_PARAMETER,
|
||||
TFM_ERROR_PARTITION_NON_REENTRANT,
|
||||
TFM_ERROR_NS_THREAD_MODE_CALL,
|
||||
TFM_ERROR_NOT_INITIALIZED,
|
||||
TFM_ERROR_NO_ACTIVE_PARTITION,
|
||||
TFM_ERROR_INVALID_EXC_MODE,
|
||||
TFM_SECURE_LOCK_FAILED,
|
||||
TFM_SECURE_UNLOCK_FAILED,
|
||||
TFM_ERROR_GENERIC = 0x1F,
|
||||
TFM_PARTITION_SPECIFIC_ERROR_MIN,
|
||||
};
|
||||
|
||||
//==================== Secure function declarations ==========================//
|
||||
|
||||
/**
|
||||
* \brief Assign client ID to the current TZ context
|
||||
*
|
||||
* \param[in] ns_client_id The client ID to be assigned to the current
|
||||
* context
|
||||
* \return TFM_SUCCESS if the client ID assigned successfully, an error code
|
||||
* according to \ref tfm_status_e in case of error.
|
||||
*
|
||||
* \note This function have to be called from handler mode.
|
||||
*/
|
||||
enum tfm_status_e tfm_register_client_id (int32_t ns_client_id);
|
||||
|
||||
/**
|
||||
* \brief Retrieve the version of the PSA Framework API that is implemented
|
||||
*
|
||||
* \return The version of the PSA Framework
|
||||
*/
|
||||
uint32_t tfm_psa_framework_version_veneer(void);
|
||||
|
||||
/**
|
||||
* \brief Return version of secure function provided by secure binary
|
||||
*
|
||||
* \param[in] sid ID of secure service
|
||||
*
|
||||
* \return Version number of secure function
|
||||
*/
|
||||
uint32_t tfm_psa_version_veneer(uint32_t sid);
|
||||
|
||||
/**
|
||||
* \brief Connect to secure function
|
||||
*
|
||||
* \param[in] sid ID of secure service
|
||||
* \param[in] minor_version Minor version of SF requested by client
|
||||
*
|
||||
* \return Returns handle to connection
|
||||
*/
|
||||
psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version);
|
||||
|
||||
/**
|
||||
* \brief Call a secure function referenced by a connection handle
|
||||
*
|
||||
* \param[in] handle Handle to connection
|
||||
* \param[in] in_vecs invec containing pointer/count of input vectors
|
||||
* \param[in] out_vecs outvec containing pointer/count of output vectors
|
||||
*
|
||||
* \return Returns \ref psa_status_t status code
|
||||
*/
|
||||
psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
|
||||
const psa_invec *in_vecs,
|
||||
psa_outvec *out_vecs);
|
||||
|
||||
/**
|
||||
* \brief Close connection to secure function referenced by a connection handle
|
||||
*
|
||||
* \param[in] handle Handle to connection
|
||||
*
|
||||
* \return Returns \ref psa_status_t status code
|
||||
*/
|
||||
psa_status_t tfm_psa_close_veneer(psa_handle_t handle);
|
||||
|
||||
//================ End Secure function declarations ==========================//
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_API_H__ */
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
#ifndef __TFM_NS_LOCK_H__
|
||||
#define __TFM_NS_LOCK_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int32_t (*veneer_fn) (uint32_t arg0, uint32_t arg1,
|
||||
uint32_t arg2, uint32_t arg3);
|
||||
|
||||
/**
|
||||
* \brief NS world, NS lock based dispatcher
|
||||
*
|
||||
* \details To be called from the wrapper API interface
|
||||
*/
|
||||
|
||||
uint32_t tfm_ns_lock_dispatch(veneer_fn fn,
|
||||
uint32_t arg0, uint32_t arg1,
|
||||
uint32_t arg2, uint32_t arg3);
|
||||
|
||||
/**
|
||||
* \brief NS world, Init NS lock
|
||||
*
|
||||
* \details Needs to be called during non-secure app init
|
||||
* to initialize the TFM NS lock object
|
||||
*/
|
||||
uint32_t tfm_ns_lock_init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_NS_LOCK_H__ */
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cmsis_compiler.h>
|
||||
|
||||
#ifndef __TFM_NS_SVC_H__
|
||||
#define __TFM_NS_SVC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Include all the SVC handler headers
|
||||
*/
|
||||
#include "tfm_nspm_svc_handler.h"
|
||||
|
||||
/**
|
||||
* \brief Macro to encode an svc instruction
|
||||
*
|
||||
*/
|
||||
#define SVC(code) __ASM("svc %0" : : "I" (code))
|
||||
|
||||
/**
|
||||
* \def LIST_SVC_NSPM
|
||||
*
|
||||
* \brief This is an X macro which lists
|
||||
* the SVC interface exposed by TF-M
|
||||
* for the NS OS.
|
||||
*
|
||||
*/
|
||||
#define LIST_SVC_NSPM \
|
||||
X(SVC_TFM_NSPM_REGISTER_CLIENT_ID, tfm_nspm_svc_register_client_id) \
|
||||
|
||||
/**
|
||||
* \brief Numbers associated to each SVC available
|
||||
*
|
||||
* \details Start from 1 as 0 is reserved by RTX
|
||||
*/
|
||||
enum tfm_svc_num {
|
||||
SVC_INVALID = 0,
|
||||
|
||||
#define X(SVC_ENUM, SVC_HANDLER) SVC_ENUM,
|
||||
|
||||
/* SVC API for Services */
|
||||
#ifdef TFM_NS_CLIENT_IDENTIFICATION
|
||||
LIST_SVC_NSPM
|
||||
#endif
|
||||
|
||||
#undef X
|
||||
|
||||
/* add all the new entries above this line */
|
||||
SVC_TFM_MAX,
|
||||
};
|
||||
|
||||
/* number of user SVC functions */
|
||||
#define USER_SVC_COUNT (SVC_TFM_MAX - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_NS_SVC_H__ */
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __TFM_NSPM_SVC_HANDLER_H__
|
||||
#define __TFM_NSPM_SVC_HANDLER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Reports the client ID of this task to TF-M (SVC function)
|
||||
*
|
||||
* \param [in] client_id Client ID to register.
|
||||
*
|
||||
* \return Returns 1 if the client ID was successfully reported 0 otherwise
|
||||
*/
|
||||
uint32_t tfm_nspm_svc_register_client_id(uint32_t client_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TFM_NSPM_SVC_HANDLER_H__ */
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
# TF-M integration to Mbed-OS
|
||||
This document is an initial draft for TF-M for Mbed-OS porting guide .
|
||||
|
||||
## Audience
|
||||
This guide is intended for developers wishing to port Mbed-OS with TF-M used as a secure kernel for ARMv8-M targets.
|
||||
|
||||
Prior knowledge with both TF-M & Mbed-OS concepts is assumed.
|
||||
|
||||
## Build system concepts:
|
||||
|
||||
Mbed-OS build system is based on [Mbed-CLI](https://github.com/ARMmbed/mbed-cli).
|
||||
Mbed-CLI build system performs lookup for source and header files within project directory and adds them all to a build. All folders will be scanned for sources except for:
|
||||
- folders starting with `TARGET_*`
|
||||
- folders starting with `COMPONENT_*`
|
||||
- folders starting with `FEATURE_*`
|
||||
- folders starting with `TESTS_*` (not true for `mbed test` builds)
|
||||
- files and folders listed in `.mbedignore`
|
||||
|
||||
The ignored folders listed above can be explicitly added to a compilation by adding following keys to a target description in `targets.json`:
|
||||
- adding `extra_labels_add`, `inherits` and `sub_target` for adding `TARGET_*`
|
||||
- adding `components_add` for adding `COMPONENT_*`
|
||||
- `features_add` for adding `FEATURE_*`
|
||||
|
||||
TF-M is built as bare-metal in a secure target, in order to build a secure target with TF-M as its' kernel need to add `--app-config <MBED-OS-ROOT>/tools/psa/tfm/mbed_app.json` to the build command of the secure target.
|
||||
|
||||
## Build hooks
|
||||
|
||||
Mbed-OS testing tools are designed to work with a single image (`.bin` or `.hex`).
|
||||
When building mbed-os for ARMv8-M targets two images are created. One for normal world(NW) and one for TrustZone(TZ).
|
||||
Mbed-OS build system provides `post_binary_hook` that allows executing arbitrary Python script for merging NW and TZ images. Typically `post_binary_hook` is added to NW target and assumes TZ target images as a prerequisite.
|
||||
|
||||
## Porting ARMv8-M targets
|
||||
|
||||
Typically firmware for ARMv8-M targets consist of 2 or more images: normal world and TrustZone image. More images can be present in case boot loaders are used.
|
||||
Two images must be built and linked separately. TrustZone image must be built first.
|
||||
|
||||
There may be code and/or header files sharing between the two targets.
|
||||
Nested folder layout typically provides more easy code reuse between two targets:
|
||||
Example:
|
||||
|
||||
```txt
|
||||
└── tragets
|
||||
└── TARGET_<VENDOR>
|
||||
└── TARGET_<BOARD>
|
||||
├── common_files <-- files shared between NW and TZ images
|
||||
├── TARGET_<BOARD>_NS
|
||||
│ └── normal_world_files <-- files only to be included for NW build
|
||||
└── TARGET_<BOARD>_S
|
||||
└── trustzone_files <-- files only to be included for TZ build
|
||||
```
|
||||
|
||||
The target should be represented in a following way in `target.json` (`MUSCA_A1` is taken for example and should be substituted):
|
||||
```json
|
||||
...
|
||||
"ARM_MUSCA_A1": {
|
||||
"public": false,
|
||||
"inherits": ["Target"],
|
||||
"supported_toolchains": ["ARMC6", "GCC_ARM"],
|
||||
"default_toolchain": "ARMC6",
|
||||
"extra_labels": ["ARM_SSG", "MUSCA_A1"],
|
||||
},
|
||||
"ARM_MUSCA_A1_NS": {
|
||||
"inherits": ["NSPE_Target", "ARM_MUSCA_A1"],
|
||||
"core": "Cortex-M33-NS",
|
||||
"device_has_add": ["INTERRUPTIN", "LPTICKER", "SERIAL", "SLEEP", "USTICKER"],
|
||||
"macros": [
|
||||
"MBED_TZ_DEFAULT_ACCESS=1",
|
||||
"MBED_FAULT_HANDLER_DISABLED",
|
||||
"TFM_PSA_API",
|
||||
"MBEDTLS_PSA_CRYPTO_C"
|
||||
],
|
||||
"extra_labels_add": ["MUSCA_A1_NS", "PSA", "TFM"],
|
||||
"post_binary_hook": {"function": "ArmMuscaA1Code.binary_hook"}
|
||||
},
|
||||
"ARM_MUSCA_A1_S": {
|
||||
"inherits": ["SPE_Target", "ARM_MUSCA_A1"],
|
||||
"core": "Cortex-M33",
|
||||
"device_has_add": ["FLASH"],
|
||||
"macros": [
|
||||
"MBED_FAULT_HANDLER_DISABLED",
|
||||
"MBED_MPU_CUSTOM",
|
||||
"BYPASS_NVSTORE_CHECK",
|
||||
"TFM_LVL=1",
|
||||
"TFM_PSA_API",
|
||||
"MBEDTLS_PSA_CRYPTO_SPM",
|
||||
"MBEDTLS_PSA_CRYPTO_C",
|
||||
"MBEDTLS_ENTROPY_NV_SEED",
|
||||
"MBEDTLS_PLATFORM_NV_SEED_READ_MACRO=mbed_default_seed_read",
|
||||
"MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO=mbed_default_seed_write"
|
||||
],
|
||||
"components_add": ["FLASHIAP"],
|
||||
"extra_labels_add": ["MUSCA_A1_S", "PSA", "TFM"]
|
||||
},
|
||||
```
|
||||
|
||||
Example details:
|
||||
- Secure target:
|
||||
- `"device_has_add": ["FLASH"]` and `"components_add": ["FLASHIAP"]` for enabling storage stack. Required by PSA Internal storage service.
|
||||
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
|
||||
- all the macros from the example above are required
|
||||
- must inherit from `SPE_Target`
|
||||
- Nonsecure target:
|
||||
- must inherit from `NSPE_Target`
|
||||
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
|
||||
- all the macros from the example above are required
|
||||
- `post_binary_hook` is used to combine secure and non-secure images
|
||||
|
||||
### HAL
|
||||
For porting Mbed-OS & TF-M both Mbed-OS and TF-M HAL layers should be created.
|
||||
|
||||
#### Mbed-OS HAL:
|
||||
Follow instructions for [Mbed-OS HAL porting](https://os.mbed.com/docs/mbed-os/v5.11/porting/porting-hal-modules.html)
|
||||
|
||||
#### TF-M:
|
||||
Mbed-OS contains customized TF-M version. TF-M services reference implementation was replaced by Mbed-OS version. Thus TF-M has different HAL layer comparing to vanilla [TF-M reference implementation](https://git.trustedfirmware.org/trusted-firmware-m.git/about/).
|
||||
|
||||
The porting layer consists of:
|
||||
- All functions listed in: `components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h`
|
||||
- Flash API `mbed-os/hal/flash_api.h` implementation is required for TZ image. It is used by PSA Internal trusted storage implementation.
|
||||
|
|
@ -62,6 +62,11 @@ uint32_t psa_security_lifecycle_state(void);
|
|||
psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state);
|
||||
|
||||
|
||||
/** \brief Resets the system
|
||||
*
|
||||
*/
|
||||
void psa_system_reset();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "psa_crypto_srv_ifs.h"
|
||||
|
||||
#include "psa/client.h"
|
||||
|
||||
#include "crypto.h"
|
||||
#include "crypto_platform_spe.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
// ---------------------------------- Includes ---------------------------------
|
||||
#include "psa/service.h"
|
||||
#include "psa/client.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "psa/client.h"
|
||||
#include "psa/service.h"
|
||||
#if defined(TARGET_TFM)
|
||||
#define SPM_PANIC(format, ...) \
|
||||
{ \
|
||||
while(1){}; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PSA_CRYPTO_SECURE 1
|
||||
#include "crypto_spe.h"
|
||||
#include "crypto_platform_spe.h"
|
||||
|
|
@ -446,7 +451,11 @@ static void psa_hash_operation(void)
|
|||
case PSA_HASH_CLONE_BEGIN: {
|
||||
size_t index = 0;
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
status = reserve_hash_clone(psa_identity(msg.handle), msg.rhandle, &index);
|
||||
#else
|
||||
status = reserve_hash_clone(msg.client_id, msg.rhandle, &index);
|
||||
#endif
|
||||
if (status == PSA_SUCCESS) {
|
||||
psa_write(msg.handle, 0, &index, sizeof(index));
|
||||
}
|
||||
|
|
@ -462,7 +471,11 @@ static void psa_hash_operation(void)
|
|||
SPM_PANIC("SPM read length mismatch");
|
||||
}
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
status = get_hash_clone(index, psa_identity(msg.handle), &hash_clone);
|
||||
#else
|
||||
status = get_hash_clone(index, msg.client_id, &hash_clone);
|
||||
#endif
|
||||
if (status == PSA_SUCCESS) {
|
||||
status = psa_hash_clone(hash_clone->source_operation, msg.rhandle);
|
||||
release_hash_clone(hash_clone);
|
||||
|
|
@ -1488,7 +1501,12 @@ void psa_crypto_generator_operations(void)
|
|||
void crypto_main(void *ptr)
|
||||
{
|
||||
while (1) {
|
||||
uint32_t signals = psa_wait_any(PSA_BLOCK);
|
||||
uint32_t signals = 0;
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
signals = psa_wait_any(PSA_BLOCK);
|
||||
#else
|
||||
signals = psa_wait(CRYPTO_SRV_WAIT_ANY_SID_MSK, PSA_BLOCK);
|
||||
#endif
|
||||
if (signals & PSA_CRYPTO_INIT) {
|
||||
psa_crypto_init_operation();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,3 +28,8 @@ psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state)
|
|||
{
|
||||
return psa_platfrom_lifecycle_change_request_impl(new_state);
|
||||
}
|
||||
|
||||
void psa_system_reset(void)
|
||||
{
|
||||
psa_system_reset_impl();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
#include "psa/lifecycle.h"
|
||||
#include "psa/internal_trusted_storage.h"
|
||||
#include "platform_srv_impl.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include "cmsis.h"
|
||||
|
||||
#ifndef MBED_CONF_LIFECYCLE_STATE
|
||||
#define MBED_CONF_LIFECYCLE_STATE PSA_LIFECYCLE_ASSEMBLY_AND_TEST
|
||||
|
|
@ -38,3 +40,9 @@ psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t state)
|
|||
}
|
||||
return PSA_LIFECYCLE_ERROR;
|
||||
}
|
||||
|
||||
MBED_WEAK void psa_system_reset_impl(void)
|
||||
{
|
||||
/* Reset the system */
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,5 +22,6 @@
|
|||
|
||||
psa_status_t psa_platfrom_lifecycle_get_impl(uint32_t *lc_state);
|
||||
psa_status_t psa_platfrom_lifecycle_change_request_impl(uint32_t lc_state);
|
||||
void psa_system_reset_impl(void);
|
||||
|
||||
#endif // __PLATFROM_SRV_IMPL_H__
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "psa_platform_ifs.h"
|
||||
#include "psa/lifecycle.h"
|
||||
#include "psa/client.h"
|
||||
#include "mbed_toolchain.h"
|
||||
|
||||
uint32_t psa_security_lifecycle_state(void)
|
||||
{
|
||||
|
|
@ -56,3 +57,12 @@ psa_status_t mbed_psa_reboot_and_request_new_security_state(uint32_t new_state)
|
|||
return status;
|
||||
}
|
||||
|
||||
MBED_NORETURN void psa_system_reset(void)
|
||||
{
|
||||
psa_handle_t conn = psa_connect(PSA_PLATFORM_LC_SET, 1);
|
||||
if (conn <= PSA_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
psa_call(conn, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,18 @@ spm_rot_service_t platform_rot_services[PLATFORM_ROT_SRV_COUNT] = {
|
|||
.tail = NULL
|
||||
}
|
||||
},
|
||||
{
|
||||
.sid = PSA_PLATFORM_SYSTEM_RESET,
|
||||
.mask = PSA_PLATFORM_SYSTEM_RESET_MSK,
|
||||
.partition = NULL,
|
||||
.min_version = 1,
|
||||
.min_version_policy = PSA_MINOR_VERSION_POLICY_RELAXED,
|
||||
.allow_nspe = true,
|
||||
.queue = {
|
||||
.head = NULL,
|
||||
.tail = NULL
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/* External SIDs used by PLATFORM */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@
|
|||
#include "psa/internal_trusted_storage.h"
|
||||
#include "psa/service.h"
|
||||
|
||||
#if defined(TARGET_TFM)
|
||||
#define SPM_PANIC(format, ...) \
|
||||
{ \
|
||||
while(1){}; \
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef psa_status_t (*SignalHandler)(psa_msg_t *);
|
||||
|
||||
static psa_status_t lifecycle_get(psa_msg_t *msg)
|
||||
|
|
@ -52,6 +59,12 @@ static psa_status_t lifecycle_change_request(psa_msg_t *msg)
|
|||
|
||||
}
|
||||
|
||||
static psa_status_t system_reset_request(psa_msg_t *msg)
|
||||
{
|
||||
(void)msg;
|
||||
psa_system_reset_impl();
|
||||
}
|
||||
|
||||
static void message_handler(psa_msg_t *msg, SignalHandler handler)
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
|
@ -77,7 +90,12 @@ void platform_partition_entry(void *ptr)
|
|||
uint32_t signals = 0;
|
||||
psa_msg_t msg = {0};
|
||||
while (1) {
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
signals = psa_wait_any(PSA_BLOCK);
|
||||
#else
|
||||
signals = psa_wait(PLATFORM_WAIT_ANY_SID_MSK, PSA_BLOCK);
|
||||
#endif
|
||||
|
||||
if ((signals & PSA_PLATFORM_LC_GET_MSK) != 0) {
|
||||
psa_get(PSA_PLATFORM_LC_GET_MSK, &msg);
|
||||
message_handler(&msg, lifecycle_get);
|
||||
|
|
@ -86,5 +104,9 @@ void platform_partition_entry(void *ptr)
|
|||
psa_get(PSA_PLATFORM_LC_SET_MSK, &msg);
|
||||
message_handler(&msg, lifecycle_change_request);
|
||||
}
|
||||
if ((signals & PSA_PLATFORM_SYSTEM_RESET_MSK) != 0) {
|
||||
psa_get(PSA_PLATFORM_SYSTEM_RESET_MSK, &msg);
|
||||
message_handler(&msg, system_reset_request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#define PLATFORM_ID 8
|
||||
|
||||
#define PLATFORM_ROT_SRV_COUNT (2UL)
|
||||
#define PLATFORM_ROT_SRV_COUNT (3UL)
|
||||
#define PLATFORM_EXT_ROT_SRV_COUNT (1UL)
|
||||
|
||||
/* PLATFORM event flags */
|
||||
|
|
@ -44,10 +44,13 @@
|
|||
#define PSA_PLATFORM_LC_GET_MSK (1UL << PSA_PLATFORM_LC_GET_MSK_POS)
|
||||
#define PSA_PLATFORM_LC_SET_MSK_POS (5UL)
|
||||
#define PSA_PLATFORM_LC_SET_MSK (1UL << PSA_PLATFORM_LC_SET_MSK_POS)
|
||||
#define PSA_PLATFORM_SYSTEM_RESET_MSK_POS (6UL)
|
||||
#define PSA_PLATFORM_SYSTEM_RESET_MSK (1UL << PSA_PLATFORM_SYSTEM_RESET_MSK_POS)
|
||||
|
||||
#define PLATFORM_WAIT_ANY_SID_MSK (\
|
||||
PSA_PLATFORM_LC_GET_MSK | \
|
||||
PSA_PLATFORM_LC_SET_MSK)
|
||||
PSA_PLATFORM_LC_SET_MSK | \
|
||||
PSA_PLATFORM_SYSTEM_RESET_MSK)
|
||||
|
||||
|
||||
#endif // PSA_PLATFORM_PARTITION_H
|
||||
|
|
|
|||
|
|
@ -21,6 +21,14 @@
|
|||
"non_secure_clients": true,
|
||||
"minor_version": 1,
|
||||
"minor_policy": "RELAXED"
|
||||
},
|
||||
{
|
||||
"name": "PSA_PLATFORM_SYSTEM_RESET",
|
||||
"identifier": "0x00011002",
|
||||
"signal": "PSA_PLATFORM_SYSTEM_RESET_MSK",
|
||||
"non_secure_clients": true,
|
||||
"minor_version": 1,
|
||||
"minor_policy": "RELAXED"
|
||||
}
|
||||
],
|
||||
"extern_sids": [
|
||||
|
|
|
|||
|
|
@ -28,5 +28,6 @@
|
|||
|
||||
#define PSA_PLATFORM_LC_GET 0x00011000
|
||||
#define PSA_PLATFORM_LC_SET 0x00011001
|
||||
#define PSA_PLATFORM_SYSTEM_RESET 0x00011002
|
||||
|
||||
#endif // PSA_PLATFORM_PARTITION_ROT_SERVICES_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
/* Copyright (c) 2018 ARM Limited
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "KVStore.h"
|
||||
#include "TDBStore.h"
|
||||
#include "psa/internal_trusted_storage.h"
|
||||
#include "pits_impl.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_toolchain.h"
|
||||
#include "FlashIAP.h"
|
||||
#include "FlashIAPBlockDevice.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
static KVStore *internal_store = NULL;
|
||||
static bool is_tfm_kv_initialized = false;
|
||||
|
||||
static inline uint32_t align_up(uint64_t val, uint64_t size)
|
||||
{
|
||||
return (((val - 1) / size) + 1) * size;
|
||||
}
|
||||
|
||||
static inline uint32_t align_down(uint64_t val, uint64_t size)
|
||||
{
|
||||
return (((val) / size)) * size;
|
||||
}
|
||||
|
||||
static BlockDevice *_get_blockdevice(bd_addr_t start_address, bd_size_t size)
|
||||
{
|
||||
int ret = MBED_SUCCESS;
|
||||
bd_addr_t flash_end_address;
|
||||
bd_addr_t flash_start_address;
|
||||
bd_addr_t aligned_start_address;
|
||||
bd_addr_t aligned_end_address;
|
||||
bd_addr_t end_address;
|
||||
FlashIAP flash;
|
||||
|
||||
ret = flash.init();
|
||||
if (ret != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Get flash parameters before starting
|
||||
flash_start_address = flash.get_flash_start();
|
||||
flash_end_address = flash_start_address + flash.get_flash_size();;
|
||||
|
||||
aligned_start_address = align_down(start_address, flash.get_sector_size(start_address));
|
||||
if (start_address != aligned_start_address) {
|
||||
flash.deinit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end_address = start_address + size;
|
||||
if (end_address > flash_end_address) {
|
||||
flash.deinit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aligned_end_address = align_up(end_address, flash.get_sector_size(end_address - 1));
|
||||
if (end_address != aligned_end_address) {
|
||||
flash.deinit();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FlashIAPBlockDevice bd(start_address, size);
|
||||
flash.deinit();
|
||||
return &bd;
|
||||
}
|
||||
|
||||
static int _calculate_blocksize_match_tdbstore(BlockDevice *bd)
|
||||
{
|
||||
bd_size_t size = bd->size();
|
||||
bd_size_t erase_size = bd->get_erase_size();
|
||||
bd_size_t number_of_sector = size / erase_size;
|
||||
|
||||
if (number_of_sector < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tfm_kv_init(void)
|
||||
{
|
||||
int ret = MBED_SUCCESS;
|
||||
bd_size_t internal_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE;
|
||||
bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS;
|
||||
|
||||
//Get internal memory FLASHIAP block device.
|
||||
BlockDevice *internal_bd = _get_blockdevice(internal_start_address, internal_size);
|
||||
if (internal_bd == NULL) {
|
||||
return -1; // TODO: Error code
|
||||
}
|
||||
|
||||
ret = internal_bd->init();
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Check that internal flash has 2 or more sectors
|
||||
if (_calculate_blocksize_match_tdbstore(internal_bd) != 0) {
|
||||
return -1; // TODO: Error code
|
||||
}
|
||||
|
||||
//Deinitialize internal block device and TDB will reinitialize and take control on it.
|
||||
ret = internal_bd->deinit();
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Create a TDBStore in the internal FLASHIAP block device.
|
||||
static TDBStore tdb_internal(internal_bd);
|
||||
internal_store = &tdb_internal;
|
||||
|
||||
ret = internal_store->init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Get default KVStore instance for internal flesh storage
|
||||
*
|
||||
* \return valid pointer to KVStore
|
||||
*/
|
||||
|
||||
KVStore *get_its_kvstore_instance(void)
|
||||
{
|
||||
return internal_store;
|
||||
}
|
||||
|
||||
int kv_init_storage_config()
|
||||
{
|
||||
int ret = MBED_SUCCESS;
|
||||
|
||||
if (!is_tfm_kv_initialized) {
|
||||
ret = tfm_kv_init();
|
||||
}
|
||||
|
||||
is_tfm_kv_initialized = (ret == MBED_SUCCESS) ? true : false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -16,21 +16,38 @@
|
|||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "KVMap.h"
|
||||
#include "KVStore.h"
|
||||
#include "TDBStore.h"
|
||||
#include "psa/internal_trusted_storage.h"
|
||||
#include "pits_impl.h"
|
||||
#include "pits_version_impl.h"
|
||||
#include "mbed_error.h"
|
||||
#include "mbed_assert.h"
|
||||
#include "mbed_toolchain.h"
|
||||
|
||||
#if defined(TARGET_TFM)
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
KVStore *get_its_kvstore_instance(void);
|
||||
|
||||
#else
|
||||
|
||||
#include "KVMap.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
/*
|
||||
* \brief Get default KVStore instance for internal flesh storage
|
||||
*
|
||||
* \return valid pointer to KVStore
|
||||
*/
|
||||
KVStore *get_its_kvstore_instance(void)
|
||||
{
|
||||
#endif
|
||||
KVMap &kv_map = KVMap::get_instance();
|
||||
return kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));
|
||||
}
|
||||
#endif // defined(TARGET_TFM)
|
||||
|
||||
// Maximum length of filename we use for kvstore API.
|
||||
// pid: 6; delimiter: 1; uid: 11; str terminator: 1
|
||||
|
|
@ -50,10 +67,16 @@ const uint8_t base64_coding_table[] = {
|
|||
|
||||
static KVStore *kvstore = NULL;
|
||||
|
||||
MBED_WEAK psa_its_status_t its_version_migrate(void *storage, const its_version_t *version)
|
||||
{
|
||||
(void)storage;
|
||||
(void)version;
|
||||
return PSA_ITS_SUCCESS;
|
||||
}
|
||||
|
||||
static void its_init(void)
|
||||
{
|
||||
KVMap &kv_map = KVMap::get_instance();
|
||||
kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));
|
||||
kvstore = get_its_kvstore_instance();
|
||||
if (!kvstore) {
|
||||
// Can only happen due to system misconfiguration.
|
||||
// Thus considered as unrecoverable error for runtime.
|
||||
|
|
@ -105,19 +128,6 @@ static void its_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
// used from test only
|
||||
void its_deinit(void)
|
||||
{
|
||||
kvstore = NULL;
|
||||
}
|
||||
|
||||
MBED_WEAK psa_its_status_t its_version_migrate(void *storage, const its_version_t *version)
|
||||
{
|
||||
(void)storage;
|
||||
(void)version;
|
||||
return PSA_ITS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Convert KVStore stauts codes to PSA internal storage status codes
|
||||
*
|
||||
|
|
@ -316,7 +326,3 @@ psa_its_status_t psa_its_reset_impl()
|
|||
int status = kvstore->reset();
|
||||
return convert_status(status);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_TFM) && defined(COMPONENT_SPE)
|
||||
extern int kv_init_storage_config();
|
||||
#endif
|
||||
#define PITS_DATA_PTR_AT_OFFSET(ptr, offset) ((void *)(((uintptr_t)ptr) + ((uintptr_t)offset)))
|
||||
#define STR_EXPAND(tok) #tok
|
||||
|
||||
|
|
@ -34,6 +37,8 @@ psa_its_status_t psa_its_get_info_impl(int32_t pid, psa_its_uid_t uid, struct ps
|
|||
psa_its_status_t psa_its_remove_impl(int32_t pid, psa_its_uid_t uid);
|
||||
psa_its_status_t psa_its_reset_impl();
|
||||
|
||||
psa_its_status_t psa_its_reset_impl(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
|
||||
/* Threads stacks */
|
||||
MBED_ALIGN(8) uint8_t its_thread_stack[1024] = {0};
|
||||
MBED_ALIGN(8) uint8_t its_thread_stack[2048] = {0};
|
||||
|
||||
/* Threads control blocks */
|
||||
osRtxThread_t its_thread_cb = {0};
|
||||
|
|
@ -45,7 +45,7 @@ osThreadAttr_t its_thread_attr = {
|
|||
.cb_mem = &its_thread_cb,
|
||||
.cb_size = sizeof(its_thread_cb),
|
||||
.stack_mem = its_thread_stack,
|
||||
.stack_size = 1024,
|
||||
.stack_size = 2048,
|
||||
.priority = osPriorityNormal,
|
||||
.tz_module = 0,
|
||||
.reserved = 0
|
||||
|
|
@ -124,7 +124,7 @@ static const osMutexAttr_t its_mutex_attr = {
|
|||
};
|
||||
|
||||
|
||||
extern void pits_entry(void *ptr);
|
||||
extern void its_entry(void *ptr);
|
||||
|
||||
void its_init(spm_partition_t *partition)
|
||||
{
|
||||
|
|
@ -142,7 +142,7 @@ void its_init(spm_partition_t *partition)
|
|||
}
|
||||
partition->rot_services = its_rot_services;
|
||||
|
||||
partition->thread_id = osThreadNew(pits_entry, NULL, &its_thread_attr);
|
||||
partition->thread_id = osThreadNew(its_entry, NULL, &its_thread_attr);
|
||||
if (NULL == partition->thread_id) {
|
||||
SPM_PANIC("Failed to create start main thread of partition its!\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,25 @@
|
|||
#include "psa_its_partition.h"
|
||||
#include "psa/internal_trusted_storage.h"
|
||||
#include "pits_impl.h"
|
||||
#include "kv_config.h"
|
||||
#include "mbed_error.h"
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
#include "kv_config.h"
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_TFM)
|
||||
#define SPM_PANIC(format, ...) \
|
||||
{ \
|
||||
while(1){}; \
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef psa_status_t (*SignalHandler)(psa_msg_t *);
|
||||
|
||||
static psa_status_t storage_set(psa_msg_t *msg)
|
||||
|
|
@ -59,9 +70,11 @@ static psa_status_t storage_set(psa_msg_t *msg)
|
|||
free(data);
|
||||
return PSA_ITS_ERROR_STORAGE_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
psa_its_status_t status = psa_its_set_impl(psa_identity(msg->handle), key, alloc_size, data, flags);
|
||||
|
||||
#else
|
||||
psa_its_status_t status = psa_its_set_impl(msg->client_id, key, alloc_size, data, flags);
|
||||
#endif
|
||||
memset(data, 0, alloc_size);
|
||||
free(data);
|
||||
return status;
|
||||
|
|
@ -89,7 +102,12 @@ static psa_status_t storage_get(psa_msg_t *msg)
|
|||
return PSA_ITS_ERROR_STORAGE_FAILURE;
|
||||
}
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
psa_its_status_t status = psa_its_get_impl(psa_identity(msg->handle), key, offset, msg->out_size[0], data);
|
||||
#else
|
||||
psa_its_status_t status = psa_its_get_impl(msg->client_id, key, offset, msg->out_size[0], data);
|
||||
#endif
|
||||
|
||||
if (status == PSA_ITS_SUCCESS) {
|
||||
psa_write(msg->handle, 0, data, msg->out_size[0]);
|
||||
}
|
||||
|
|
@ -112,7 +130,12 @@ static psa_status_t storage_info(psa_msg_t *msg)
|
|||
return PSA_DROP_CONNECTION;
|
||||
}
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
psa_its_status_t status = psa_its_get_info_impl(psa_identity(msg->handle), key, &info);
|
||||
#else
|
||||
psa_its_status_t status = psa_its_get_info_impl(msg->client_id, key, &info);
|
||||
#endif
|
||||
|
||||
if (status == PSA_ITS_SUCCESS) {
|
||||
psa_write(msg->handle, 0, &info, msg->out_size[0]);
|
||||
}
|
||||
|
|
@ -132,15 +155,20 @@ static psa_status_t storage_remove(psa_msg_t *msg)
|
|||
return PSA_DROP_CONNECTION;
|
||||
}
|
||||
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
return psa_its_remove_impl(psa_identity(msg->handle), key);
|
||||
#else
|
||||
return psa_its_remove_impl(msg->client_id, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
static psa_status_t storage_reset(psa_msg_t *msg)
|
||||
{
|
||||
(void)msg;
|
||||
return psa_its_reset_impl();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void message_handler(psa_msg_t *msg, SignalHandler handler)
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
|
|
@ -161,13 +189,17 @@ static void message_handler(psa_msg_t *msg, SignalHandler handler)
|
|||
psa_reply(msg->handle, status);
|
||||
}
|
||||
|
||||
void pits_entry(void *ptr)
|
||||
void its_entry(void *ptr)
|
||||
{
|
||||
uint32_t signals = 0;
|
||||
psa_msg_t msg = {0};
|
||||
|
||||
while (1) {
|
||||
#if defined(TARGET_MBED_SPM)
|
||||
signals = psa_wait_any(PSA_BLOCK);
|
||||
#else
|
||||
signals = psa_wait(ITS_WAIT_ANY_SID_MSK, PSA_BLOCK);
|
||||
#endif
|
||||
|
||||
// KVStore initiation:
|
||||
// - Must be done after the psa_wait_any() call since only now we know OS initialization is done
|
||||
|
|
@ -197,6 +229,7 @@ void pits_entry(void *ptr)
|
|||
psa_get(PSA_ITS_RESET_MSK, &msg);
|
||||
message_handler(&msg, storage_reset);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"type": "APPLICATION-ROT",
|
||||
"priority": "NORMAL",
|
||||
"id": "0x0000000A",
|
||||
"entry_point": "pits_entry",
|
||||
"stack_size": "0x400",
|
||||
"entry_point": "its_entry",
|
||||
"stack_size": "0x800",
|
||||
"heap_size": "0x400",
|
||||
"services": [{
|
||||
"name": "PSA_ITS_GET",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include "platform/platform.h"
|
||||
#include "platform/FilePath.h"
|
||||
|
|
@ -904,6 +905,9 @@ extern "C" long PREFIX(_flen)(FILEHANDLE fh)
|
|||
return size;
|
||||
}
|
||||
|
||||
// Do not compile this code for TFM secure target
|
||||
#if !defined(COMPONENT_SPE) || !defined(TARGET_TFM)
|
||||
|
||||
extern "C" char Image$$RW_IRAM1$$ZI$$Limit[];
|
||||
|
||||
extern "C" MBED_WEAK __value_in_regs struct __initial_stackheap _mbed_user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3)
|
||||
|
|
@ -924,6 +928,8 @@ extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uin
|
|||
return _mbed_user_setup_stackheap(R0, R1, R2, R3);
|
||||
}
|
||||
|
||||
#endif // !defined(COMPONENT_SPE) || !defined(TARGET_TFM)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -1205,7 +1211,7 @@ extern "C" WEAK void __cxa_pure_virtual(void)
|
|||
// SP. This make it compatible with RTX RTOS thread stacks.
|
||||
#if defined(TOOLCHAIN_GCC_ARM)
|
||||
|
||||
#if defined(TARGET_CORTEX_A)
|
||||
#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
|
||||
extern "C" uint32_t __HeapLimit;
|
||||
#endif
|
||||
|
||||
|
|
@ -1234,7 +1240,7 @@ extern "C" WEAK caddr_t _sbrk(int incr)
|
|||
unsigned char *prev_heap = heap;
|
||||
unsigned char *new_heap = heap + incr;
|
||||
|
||||
#if defined(TARGET_CORTEX_A)
|
||||
#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
|
||||
if (new_heap >= (unsigned char *)&__HeapLimit) { /* __HeapLimit is end of heap section */
|
||||
#else
|
||||
if (new_heap >= (unsigned char *)__get_MSP()) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
#include "spm_init.h"
|
||||
#include "spm_api.h"
|
||||
#endif
|
||||
#if defined(TARGET_TFM) && defined(COMPONENT_NSPE)
|
||||
#include "TARGET_TFM/interface/include/tfm_ns_lock.h"
|
||||
#endif
|
||||
|
||||
#if defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
|
||||
|
||||
|
|
@ -98,9 +101,12 @@ MBED_NORETURN void mbed_rtos_start()
|
|||
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Dispatcher thread not created", &psa_spm_dispatcher_th_attr);
|
||||
}
|
||||
#endif // defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
|
||||
|
||||
#endif // defined(TARGET_MBED_SPM)
|
||||
|
||||
#if defined(TARGET_TFM) && defined(COMPONENT_NSPE)
|
||||
tfm_ns_lock_init();
|
||||
#endif // defined(TARGET_TFM) && defined(COMPONENT_NSPE)
|
||||
|
||||
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
|
||||
osThreadId_t result = osThreadNew((osThreadFunc_t)mbed_start, NULL, &_main_thread_attr);
|
||||
if ((void *)result == NULL) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
{
|
||||
"files" : [
|
||||
{
|
||||
"src_file" : "interface/src/tfm_ns_lock_rtx.c",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/src/tfm_psa_ns_api.c",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/psa_client.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/psa_service.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/tfm_api.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/tfm_ns_lock.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/tfm_ns_svc.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "interface/include/tfm_nspm_svc_handler.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/include/tfm_plat_boot_seed.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_boot_seed.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/include/tfm_plat_defs.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_defs.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/include/tfm_plat_device_id.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_device_id.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/include/tfm_spm_hal.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/ext/driver/Driver_Common.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_Common.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/ext/driver/Driver_MPC.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_MPC.h"
|
||||
},
|
||||
{
|
||||
"src_file" : "platform/ext/driver/Driver_PPC.h",
|
||||
"dest_file" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_PPC.h"
|
||||
}
|
||||
],
|
||||
"folders" : [
|
||||
{
|
||||
"src_folder" : "secure_fw/core",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core"
|
||||
},
|
||||
{
|
||||
"src_folder" : "secure_fw/core/ipc",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc"
|
||||
},
|
||||
{
|
||||
"src_folder" : "secure_fw/core/ipc/include",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include"
|
||||
},
|
||||
{
|
||||
"src_folder" : "secure_fw/include",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include"
|
||||
},
|
||||
{
|
||||
"src_folder" : "secure_fw/spm",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm"
|
||||
},
|
||||
{
|
||||
"src_folder" : "bl2/include",
|
||||
"dest_folder" : "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include"
|
||||
}
|
||||
],
|
||||
"commit_sha" : [
|
||||
"11e5abc451acc7e7596e01b0f5605b4ad3e1965e",
|
||||
"9541a37d7c878d057a40734ab4174cb46d81a922",
|
||||
"e87efab83af6273a12b471ab574ddbf4359ff0de",
|
||||
"bc275ff42a5c6275efffce81c91cce37e3749a3f",
|
||||
"fb6b17dcdd59faa023e7940a6bb2f052956044c0",
|
||||
"38bd4a279d22ff083d37c7f6a034d4a589e3527e",
|
||||
"8c33f1e25ada6e3cbc15bd982825473ba9a57540",
|
||||
"1134fd4dbb4245d19c010861a9f0bec7210c9701"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright (c) 2017-2018 ARM Limited
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# http://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.
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
from os.path import join as path_join
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
|
||||
# Be sure that the tools directory is in the search path
|
||||
ROOT = os.path.abspath(path_join(os.path.dirname(__file__), os.pardir, os.pardir))
|
||||
sys.path.insert(0, ROOT)
|
||||
|
||||
from tools.psa.mbed_spm_tfm_common import Manifest, validate_partition_manifests, manifests_discovery
|
||||
|
||||
__version__ = '1.0'
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TEMPLATES_DIR = path_join(SCRIPT_DIR, 'mbed_spm', 'templates')
|
||||
MANIFEST_TEMPLATES = [filename for filename in
|
||||
[os.path.join(dp, f) for dp, dn, fn in
|
||||
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
|
||||
if '_NAME_' in filename]
|
||||
COMMON_TEMPLATES = [filename for filename in
|
||||
[os.path.join(dp, f) for dp, dn, fn in
|
||||
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
|
||||
if '_NAME_' not in filename]
|
||||
MANIFEST_FILE_PATTERN = '*_psa.json'
|
||||
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
|
||||
SPM_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA', 'TARGET_MBED_SPM')
|
||||
SPM_TESTS_ROOT = path_join(MBED_OS_ROOT, 'TESTS', 'psa')
|
||||
|
||||
|
||||
def generate_source_files(
|
||||
templates,
|
||||
render_args,
|
||||
output_folder,
|
||||
extra_filters=None
|
||||
):
|
||||
"""
|
||||
Generate SPM common C code from manifests using given templates
|
||||
|
||||
:param templates: Dictionary of template and their auto-generated products
|
||||
:param render_args: Dictionary of arguments that should be passed to render
|
||||
:param output_folder: Output directory for file generation
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: Path to generated folder containing common generated files
|
||||
"""
|
||||
|
||||
rendered_files = []
|
||||
templates_dirs = list(
|
||||
set([os.path.dirname(path) for path in templates])
|
||||
)
|
||||
template_files = {os.path.basename(t): t for t in templates}
|
||||
|
||||
# Load templates for the code generation.
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(templates_dirs),
|
||||
lstrip_blocks=True,
|
||||
trim_blocks=True,
|
||||
undefined=StrictUndefined
|
||||
)
|
||||
if extra_filters:
|
||||
env.filters.update(extra_filters)
|
||||
|
||||
for tf in template_files:
|
||||
template = env.get_template(tf)
|
||||
rendered_files.append(
|
||||
(templates[template_files[tf]], template.render(**render_args)))
|
||||
rendered_file_dir = os.path.dirname(templates[template_files[tf]])
|
||||
if not os.path.exists(rendered_file_dir):
|
||||
os.makedirs(rendered_file_dir)
|
||||
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
for fname, data in rendered_files:
|
||||
with open(fname, 'wt') as fh:
|
||||
fh.write(data)
|
||||
|
||||
return output_folder
|
||||
|
||||
|
||||
def generate_partitions_sources(manifest_files, extra_filters=None):
|
||||
"""
|
||||
Process all the given manifest files and generate C code from them
|
||||
|
||||
:param manifest_files: List of manifest files
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: List of paths to the generated files
|
||||
"""
|
||||
|
||||
# Construct a list of all the manifests and sids.
|
||||
manifests = []
|
||||
for manifest_file in manifest_files:
|
||||
manifest = Manifest.from_json(manifest_file)
|
||||
manifests.append(manifest)
|
||||
|
||||
generated_folders = set()
|
||||
for manifest in manifests:
|
||||
manifest_output_folder = manifest.autogen_folder
|
||||
|
||||
render_args = {
|
||||
'partition': manifest,
|
||||
'dependent_partitions': manifest.find_dependencies(manifests),
|
||||
'script_ver': __version__
|
||||
}
|
||||
manifest_output_folder = generate_source_files(
|
||||
manifest.templates_to_files(MANIFEST_TEMPLATES,
|
||||
TEMPLATES_DIR,
|
||||
manifest_output_folder),
|
||||
render_args,
|
||||
manifest_output_folder,
|
||||
extra_filters=extra_filters
|
||||
)
|
||||
generated_folders.add(manifest_output_folder)
|
||||
|
||||
return list(generated_folders)
|
||||
|
||||
|
||||
def generate_psa_setup(manifest_files, output_dir, weak_setup,
|
||||
extra_filters=None):
|
||||
"""
|
||||
Process all the given manifest files and generate C setup code from them
|
||||
:param manifest_files: List of manifest files
|
||||
:param output_dir: Output directory for the generated files
|
||||
:param weak_setup: Is the functions/data in the setup file weak
|
||||
(can be overridden by another setup file)
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: path to the setup generated files
|
||||
"""
|
||||
autogen_folder = output_dir
|
||||
templates_dict = {
|
||||
t: path_join(autogen_folder,
|
||||
os.path.relpath(os.path.splitext(t)[0], TEMPLATES_DIR))
|
||||
for t in COMMON_TEMPLATES
|
||||
}
|
||||
|
||||
complete_source_list = list(templates_dict.values())
|
||||
|
||||
# Construct lists of all the manifests and mmio_regions.
|
||||
region_list = []
|
||||
manifests = []
|
||||
for manifest_file in manifest_files:
|
||||
manifest_obj = Manifest.from_json(manifest_file)
|
||||
manifests.append(manifest_obj)
|
||||
for region in manifest_obj.mmio_regions:
|
||||
region_list.append(region)
|
||||
complete_source_list.extend(
|
||||
list(manifest_obj.templates_to_files(
|
||||
MANIFEST_TEMPLATES,
|
||||
TEMPLATES_DIR,
|
||||
manifest_obj.autogen_folder).values())
|
||||
)
|
||||
|
||||
# Validate the correctness of the manifest collection.
|
||||
validate_partition_manifests(manifests)
|
||||
|
||||
render_args = {
|
||||
'partitions': manifests,
|
||||
'regions': region_list,
|
||||
'region_pair_list': list(itertools.combinations(region_list, 2)),
|
||||
'weak': weak_setup,
|
||||
'script_ver': __version__
|
||||
}
|
||||
|
||||
return generate_source_files(
|
||||
templates_dict,
|
||||
render_args,
|
||||
autogen_folder,
|
||||
extra_filters=extra_filters
|
||||
)
|
||||
|
||||
|
||||
def generate_psa_code():
|
||||
# Find all manifest files in the mbed-os tree
|
||||
manifest_files = manifests_discovery(MBED_OS_ROOT)
|
||||
|
||||
# Generate partition code for each manifest file
|
||||
generate_partitions_sources(manifest_files)
|
||||
|
||||
test_manifest_files = sorted(
|
||||
[path for path in manifest_files if 'TESTS' in path])
|
||||
system_manifest_files = sorted(
|
||||
list(set(manifest_files) - set(test_manifest_files)))
|
||||
|
||||
# Generate default system psa setup file (only system partitions)
|
||||
generate_psa_setup(system_manifest_files, SPM_CORE_ROOT, weak_setup=True)
|
||||
|
||||
tests_dir_content = [path_join(SPM_TESTS_ROOT, f) for f in
|
||||
os.listdir(SPM_TESTS_ROOT)]
|
||||
spm_tests = [path for path in tests_dir_content if os.path.isdir(path)]
|
||||
|
||||
# Build a dictionary for test partition in the form of:
|
||||
# { test_root: manifest_list }
|
||||
# For each test generate specific psa setup file (system + test partitions)
|
||||
tests_dict = {test_root: [] for test_root in spm_tests}
|
||||
for test_root in spm_tests:
|
||||
tests_dict[test_root] = [manifest_path for manifest_path in
|
||||
test_manifest_files if
|
||||
test_root in manifest_path]
|
||||
|
||||
if not tests_dict[test_root]:
|
||||
continue
|
||||
tests_dict[test_root] += system_manifest_files
|
||||
generate_psa_setup(sorted(tests_dict[test_root]), test_root,
|
||||
weak_setup=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
generate_psa_code()
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright (c) 2017-2018 ARM Limited
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# http://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.
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from os.path import join as path_join
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
|
||||
# Be sure that the tools directory is in the search path
|
||||
ROOT = os.path.abspath(path_join(os.path.dirname(__file__), os.pardir, os.pardir))
|
||||
sys.path.insert(0, ROOT)
|
||||
|
||||
from tools.psa.mbed_spm_tfm_common import Manifest, validate_partition_manifests
|
||||
|
||||
__version__ = '1.0'
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
|
||||
TEMPLATES_LIST_FILE = path_join(SCRIPT_DIR, 'tfm', 'tfm_generated_file_list.json')
|
||||
SERVICES_DIR = os.path.join(MBED_OS_ROOT, "components", "TARGET_PSA", "services")
|
||||
|
||||
SERVICES_MANIFESTS = [
|
||||
path_join(SERVICES_DIR, 'psa_prot_internal_storage', 'pits_psa.json'),
|
||||
path_join(SERVICES_DIR, 'platform', 'platform_psa.json'),
|
||||
path_join(SERVICES_DIR, 'crypto', 'crypto_partition_psa.json')
|
||||
]
|
||||
|
||||
|
||||
def generate_partition_source_files(manifest_files, extra_filters=None):
|
||||
"""
|
||||
Process all the given manifest files and generate C code from them.
|
||||
|
||||
:param manifest_files: List of manifest files
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: path to the setup generated files
|
||||
"""
|
||||
|
||||
# Construct lists of all the manifests and mmio_regions.
|
||||
region_list = []
|
||||
manifests = []
|
||||
for manifest_file in manifest_files:
|
||||
manifest_obj = Manifest.from_json(manifest_file, psa_type='TFM')
|
||||
manifests.append(manifest_obj)
|
||||
for region in manifest_obj.mmio_regions:
|
||||
region_list.append(region)
|
||||
|
||||
# Validate the correctness of the manifest collection.
|
||||
validate_partition_manifests(manifests)
|
||||
|
||||
render_args = {
|
||||
'partitions': manifests,
|
||||
}
|
||||
|
||||
# Load templates for the code generation.
|
||||
with open(TEMPLATES_LIST_FILE, 'r') as fh:
|
||||
templates_data = json.load(fh)
|
||||
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(MBED_OS_ROOT),
|
||||
lstrip_blocks=True,
|
||||
trim_blocks=True,
|
||||
undefined=StrictUndefined
|
||||
)
|
||||
|
||||
if extra_filters:
|
||||
env.filters.update(extra_filters)
|
||||
|
||||
# Generate code for each template
|
||||
for tpl in templates_data:
|
||||
template = env.get_template(tpl['template'])
|
||||
data = template.render(**render_args)
|
||||
output_path = os.path.join(MBED_OS_ROOT, tpl['output'])
|
||||
output_folder = os.path.dirname(output_path)
|
||||
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
with open(output_path, 'wt') as fh:
|
||||
fh.write(data)
|
||||
|
||||
|
||||
def generate_tfm_code():
|
||||
generate_partition_source_files(SERVICES_MANIFESTS)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
generate_tfm_code()
|
||||
|
|
@ -15,31 +15,15 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import fnmatch
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
from os.path import join as path_join
|
||||
import json
|
||||
from jsonschema import validate
|
||||
import fnmatch
|
||||
from six import integer_types, string_types
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader, StrictUndefined
|
||||
from jsonschema import validate
|
||||
|
||||
__version__ = '1.0'
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TEMPLATES_DIR = path_join(SCRIPT_DIR, 'templates')
|
||||
MANIFEST_TEMPLATES = [filename for filename in
|
||||
[os.path.join(dp, f) for dp, dn, fn in
|
||||
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
|
||||
if '_NAME_' in filename]
|
||||
COMMON_TEMPLATES = [filename for filename in
|
||||
[os.path.join(dp, f) for dp, dn, fn in
|
||||
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
|
||||
if '_NAME_' not in filename]
|
||||
MANIFEST_FILE_PATTERN = '*_psa.json'
|
||||
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
|
||||
SPM_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA', 'TARGET_MBED_SPM')
|
||||
SPM_TESTS_ROOT = path_join(MBED_OS_ROOT, 'TESTS', 'psa')
|
||||
|
||||
|
||||
def assert_int(num):
|
||||
|
|
@ -195,6 +179,7 @@ class Manifest(object):
|
|||
def __init__(
|
||||
self,
|
||||
manifest_file,
|
||||
psa_type,
|
||||
name,
|
||||
partition_id,
|
||||
partition_type,
|
||||
|
|
@ -212,6 +197,7 @@ class Manifest(object):
|
|||
Manifest C'tor (Aligned with json schema)
|
||||
|
||||
:param manifest_file: Path to json manifest
|
||||
:param psa_type: PSA implementation type (TFM/MBED_SPM)
|
||||
:param name: Partition unique name
|
||||
:param partition_id: Partition identifier
|
||||
:param partition_type: Whether the partition is unprivileged or part
|
||||
|
|
@ -250,12 +236,17 @@ class Manifest(object):
|
|||
assert isinstance(entry_point, string_types)
|
||||
assert partition_type in self.PARTITION_TYPES
|
||||
assert partition_id > 0
|
||||
assert psa_type in ['TFM', 'MBED_SPM']
|
||||
|
||||
self.file = manifest_file
|
||||
self.name = name
|
||||
self.psa_type = psa_type
|
||||
self.id = partition_id
|
||||
self.type = partition_type
|
||||
self.priority = self.PRIORITY[priority]
|
||||
if psa_type == 'TFM':
|
||||
self.priority = priority
|
||||
else:
|
||||
self.priority = self.PRIORITY[priority]
|
||||
self.heap_size = heap_size
|
||||
self.stack_size = stack_size
|
||||
self.entry_point = entry_point
|
||||
|
|
@ -312,12 +303,13 @@ class Manifest(object):
|
|||
)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, manifest_file, skip_src=False):
|
||||
def from_json(cls, manifest_file, skip_src=False, psa_type='MBED_SPM'):
|
||||
"""
|
||||
Load a partition manifest file
|
||||
|
||||
:param manifest_file: Manifest file path
|
||||
:param skip_src: Ignore the `source_files` entry
|
||||
:param psa_type: PSA implementation type (TFM/MBED_SPM)
|
||||
:return: Manifest object
|
||||
"""
|
||||
|
||||
|
|
@ -356,6 +348,7 @@ class Manifest(object):
|
|||
|
||||
return Manifest(
|
||||
manifest_file=manifest_file,
|
||||
psa_type=psa_type,
|
||||
name=manifest['name'],
|
||||
partition_id=assert_int(manifest['id']),
|
||||
partition_type=manifest['type'],
|
||||
|
|
@ -398,6 +391,7 @@ class Manifest(object):
|
|||
Translates a list of partition templates to file names
|
||||
|
||||
:param templates: List of partition templates
|
||||
:param templates_base: Base directory of the templates
|
||||
:param output_dir: Output directory (Default is autogen folder property)
|
||||
:return: Dictionary of template to output file translation
|
||||
"""
|
||||
|
|
@ -600,150 +594,6 @@ def validate_partition_manifests(manifests):
|
|||
)
|
||||
|
||||
|
||||
def generate_source_files(
|
||||
templates,
|
||||
render_args,
|
||||
output_folder,
|
||||
extra_filters=None
|
||||
):
|
||||
"""
|
||||
Generate SPM common C code from manifests using given templates
|
||||
|
||||
:param templates: Dictionary of template and their auto-generated products
|
||||
:param render_args: Dictionary of arguments that should be passed to render
|
||||
:param output_folder: Output directory for file generation
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: Path to generated folder containing common generated files
|
||||
"""
|
||||
|
||||
rendered_files = []
|
||||
templates_dirs = list(
|
||||
set([os.path.dirname(path) for path in templates])
|
||||
)
|
||||
template_files = {os.path.basename(t): t for t in templates}
|
||||
|
||||
# Load templates for the code generation.
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(templates_dirs),
|
||||
lstrip_blocks=True,
|
||||
trim_blocks=True,
|
||||
undefined=StrictUndefined
|
||||
)
|
||||
if extra_filters:
|
||||
env.filters.update(extra_filters)
|
||||
|
||||
for tf in template_files:
|
||||
template = env.get_template(tf)
|
||||
rendered_files.append(
|
||||
(templates[template_files[tf]], template.render(**render_args)))
|
||||
rendered_file_dir = os.path.dirname(templates[template_files[tf]])
|
||||
if not os.path.exists(rendered_file_dir):
|
||||
os.makedirs(rendered_file_dir)
|
||||
|
||||
if not os.path.exists(output_folder):
|
||||
os.makedirs(output_folder)
|
||||
|
||||
for fname, data in rendered_files:
|
||||
with open(fname, 'wt') as fh:
|
||||
fh.write(data)
|
||||
|
||||
return output_folder
|
||||
|
||||
|
||||
def generate_partitions_sources(manifest_files, extra_filters=None):
|
||||
"""
|
||||
Process all the given manifest files and generate C code from them
|
||||
|
||||
:param manifest_files: List of manifest files
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: List of paths to the generated files
|
||||
"""
|
||||
|
||||
# Construct a list of all the manifests and sids.
|
||||
manifests = []
|
||||
for manifest_file in manifest_files:
|
||||
manifest = Manifest.from_json(manifest_file)
|
||||
manifests.append(manifest)
|
||||
|
||||
generated_folders = set()
|
||||
for manifest in manifests:
|
||||
manifest_output_folder = manifest.autogen_folder
|
||||
|
||||
render_args = {
|
||||
'partition': manifest,
|
||||
'dependent_partitions': manifest.find_dependencies(manifests),
|
||||
'script_ver': __version__
|
||||
}
|
||||
manifest_output_folder = generate_source_files(
|
||||
manifest.templates_to_files(MANIFEST_TEMPLATES,
|
||||
TEMPLATES_DIR,
|
||||
manifest_output_folder),
|
||||
render_args,
|
||||
manifest_output_folder,
|
||||
extra_filters=extra_filters
|
||||
)
|
||||
generated_folders.add(manifest_output_folder)
|
||||
|
||||
return list(generated_folders)
|
||||
|
||||
|
||||
def generate_psa_setup(manifest_files, output_dir, weak_setup,
|
||||
extra_filters=None):
|
||||
"""
|
||||
Process all the given manifest files and generate C setup code from them
|
||||
:param manifest_files: List of manifest files
|
||||
:param output_dir: Output directory for the generated files
|
||||
:param weak_setup: Is the functions/data in the setup file weak
|
||||
(can be overridden by another setup file)
|
||||
:param extra_filters: Dictionary of extra filters to use in the rendering
|
||||
process
|
||||
:return: path to the setup generated files
|
||||
"""
|
||||
autogen_folder = output_dir
|
||||
templates_dict = {
|
||||
t: path_join(autogen_folder,
|
||||
os.path.relpath(os.path.splitext(t)[0], TEMPLATES_DIR))
|
||||
for t in COMMON_TEMPLATES
|
||||
}
|
||||
|
||||
complete_source_list = list(templates_dict.values())
|
||||
|
||||
# Construct lists of all the manifests and mmio_regions.
|
||||
region_list = []
|
||||
manifests = []
|
||||
for manifest_file in manifest_files:
|
||||
manifest_obj = Manifest.from_json(manifest_file)
|
||||
manifests.append(manifest_obj)
|
||||
for region in manifest_obj.mmio_regions:
|
||||
region_list.append(region)
|
||||
complete_source_list.extend(
|
||||
list(manifest_obj.templates_to_files(
|
||||
MANIFEST_TEMPLATES,
|
||||
TEMPLATES_DIR,
|
||||
manifest_obj.autogen_folder).values())
|
||||
)
|
||||
|
||||
# Validate the correctness of the manifest collection.
|
||||
validate_partition_manifests(manifests)
|
||||
|
||||
render_args = {
|
||||
'partitions': manifests,
|
||||
'regions': region_list,
|
||||
'region_pair_list': list(itertools.combinations(region_list, 2)),
|
||||
'weak': weak_setup,
|
||||
'script_ver': __version__
|
||||
}
|
||||
|
||||
return generate_source_files(
|
||||
templates_dict,
|
||||
render_args,
|
||||
autogen_folder,
|
||||
extra_filters=extra_filters
|
||||
)
|
||||
|
||||
|
||||
def manifests_discovery(root_dir):
|
||||
manifest_files = set()
|
||||
|
||||
|
|
@ -754,42 +604,3 @@ def manifests_discovery(root_dir):
|
|||
manifest_files.update(to_add)
|
||||
|
||||
return list(manifest_files)
|
||||
|
||||
|
||||
def generate_psa_code():
|
||||
# Find all manifest files in the mbed-os tree
|
||||
manifest_files = manifests_discovery(MBED_OS_ROOT)
|
||||
|
||||
# Generate partition code for each manifest file
|
||||
generate_partitions_sources(manifest_files)
|
||||
|
||||
test_manifest_files = sorted(
|
||||
[path for path in manifest_files if 'TESTS' in path])
|
||||
system_manifest_files = sorted(
|
||||
list(set(manifest_files) - set(test_manifest_files)))
|
||||
|
||||
# Generate default system psa setup file (only system partitions)
|
||||
generate_psa_setup(system_manifest_files, SPM_CORE_ROOT, weak_setup=True)
|
||||
|
||||
tests_dir_content = [path_join(SPM_TESTS_ROOT, f) for f in
|
||||
os.listdir(SPM_TESTS_ROOT)]
|
||||
spm_tests = [path for path in tests_dir_content if os.path.isdir(path)]
|
||||
|
||||
# Build a dictionary for test partition in the form of:
|
||||
# { test_root: manifest_list }
|
||||
# For each test generate specific psa setup file (system + test partitions)
|
||||
tests_dict = {test_root: [] for test_root in spm_tests}
|
||||
for test_root in spm_tests:
|
||||
tests_dict[test_root] = [manifest_path for manifest_path in
|
||||
test_manifest_files if
|
||||
test_root in manifest_path]
|
||||
|
||||
if not tests_dict[test_root]:
|
||||
continue
|
||||
tests_dict[test_root] += system_manifest_files
|
||||
generate_psa_setup(sorted(tests_dict[test_root]), test_root,
|
||||
weak_setup=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
generate_psa_code()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue