diff --git a/.astyleignore b/.astyleignore index 7efdc16bbd8..121b6f78cee 100644 --- a/.astyleignore +++ b/.astyleignore @@ -22,4 +22,5 @@ TESTS/mbed_hal/trng/pithy targets components/802.15.4_RF components/wifi +components/TARGET_PSA/TARGET_TFM tools diff --git a/.travis.yml b/.travis.yml index 6c2caa9a6c4..a40619f9993 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/LICENSE b/LICENSE index 45222606360..8e7c48b3951 100644 --- a/LICENSE +++ b/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 diff --git a/TESTS/psa/spm_client/COMPONENT_NSPE/client_ipc_tests.cpp b/TESTS/psa/spm_client/COMPONENT_NSPE/client_ipc_tests.cpp index b726ac0614d..55ed4751629 100644 --- a/TESTS/psa/spm_client/COMPONENT_NSPE/client_ipc_tests.cpp +++ b/TESTS/psa/spm_client/COMPONENT_NSPE/client_ipc_tests.cpp @@ -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" diff --git a/TESTS/psa/spm_server/COMPONENT_NSPE/main.cpp b/TESTS/psa/spm_server/COMPONENT_NSPE/main.cpp index 57010262a32..242b6529fd7 100644 --- a/TESTS/psa/spm_server/COMPONENT_NSPE/main.cpp +++ b/TESTS/psa/spm_server/COMPONENT_NSPE/main.cpp @@ -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" diff --git a/TESTS/psa/spm_smoke/COMPONENT_NSPE/main.cpp b/TESTS/psa/spm_smoke/COMPONENT_NSPE/main.cpp index 6af907fa33c..ac14680d378 100644 --- a/TESTS/psa/spm_smoke/COMPONENT_NSPE/main.cpp +++ b/TESTS/psa/spm_smoke/COMPONENT_NSPE/main.cpp @@ -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" diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c new file mode 100644 index 00000000000..76b284effff --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include + +#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; +} + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c new file mode 100644 index 00000000000..159eef90888 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_psa_ns_api.c @@ -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); +} + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_defs.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_defs.inc new file mode 100644 index 00000000000..34af1e427d9 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_defs.inc @@ -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__ */ \ No newline at end of file diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_list.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_list.inc new file mode 100644 index 00000000000..f07bf053f4d --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_list.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__ */ \ No newline at end of file diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_service_list.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_service_list.inc new file mode 100644 index 00000000000..75db66b70dc --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_service_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__ */ \ No newline at end of file diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_spm_signal_defs.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_spm_signal_defs.h new file mode 100644 index 00000000000..837669f4193 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_spm_signal_defs.h @@ -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 \ No newline at end of file diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/boot_record.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/boot_record.h new file mode 100644 index 00000000000..ab71a486290 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/boot_record.h @@ -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 +#include +#include + +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/tfm_boot_status.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/tfm_boot_status.h new file mode 100644 index 00000000000..30a7b1c2ccc --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/tfm_boot_status.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 +#include + + +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/mbed_lib.json b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/mbed_lib.json new file mode 100644 index 00000000000..5553b738352 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/mbed_lib.json @@ -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 + } + } +} + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_Common.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_Common.h new file mode 100644 index 00000000000..cdf44b3325c --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_Common.h @@ -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 +#include +#include + +#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 */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_MPC.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_MPC.h new file mode 100644 index 00000000000..9ed84ba7457 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_MPC.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 */ + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_PPC.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_PPC.h new file mode 100644 index 00000000000..e689b2ebde7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/ext/driver/Driver_PPC.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__ */ + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_boot_seed.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_boot_seed.h new file mode 100644 index 00000000000..11b79f0ebb1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_boot_seed.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 +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_defs.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_defs.h new file mode 100644 index 00000000000..f0b4297a247 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_defs.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 +#include + +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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_device_id.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_device_id.h new file mode 100644 index 00000000000..eb7d1baa503 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_plat_device_id.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 +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h new file mode 100644 index 00000000000..509f153d650 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.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 +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_arch_v8m.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_arch_v8m.h new file mode 100644 index 00000000000..96914c07469 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_arch_v8m.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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_internal_defines.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_internal_defines.h new file mode 100644 index 00000000000..a5382c57805 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_internal_defines.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_list.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_list.h new file mode 100644 index 00000000000..976450362e7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_list.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_message_queue.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_message_queue.h new file mode 100644 index 00000000000..31bcda94823 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_message_queue.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_pools.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_pools.h new file mode 100644 index 00000000000..1072f78f0f5 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_pools.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm.h new file mode 100644 index 00000000000..0fd3a8f8004 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm.h @@ -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 +#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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_svcalls.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_svcalls.h new file mode 100644 index 00000000000..c64ce74889b --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_svcalls.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_thread.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_thread.h new file mode 100644 index 00000000000..8a6d86364d5 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_thread.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_utils.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_utils.h new file mode 100644 index 00000000000..17f94c065bc --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_utils.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_wait.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_wait.h new file mode 100644 index 00000000000..2bed0aec3d2 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_wait.h @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_client.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_client.c new file mode 100644 index 00000000000..f8fe605f02b --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_client.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#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)); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_service.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_service.c new file mode 100644 index 00000000000..487197168ed --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/psa_service.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#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)); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_arch_v8m.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_arch_v8m.c new file mode 100644 index 00000000000..5c50636896e --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_arch_v8m.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include + +#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 ."); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_message_queue.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_message_queue.c new file mode 100644 index 00000000000..83ebf50edb8 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_message_queue.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_pools.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_pools.c new file mode 100644 index 00000000000..a5e7b2a65be --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_pools.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#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); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_spm.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_spm.c new file mode 100644 index 00000000000..1e929b30fd7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_spm.c @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#include +#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(); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_svcalls.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_svcalls.c new file mode 100644 index 00000000000..bdea0de8523 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_svcalls.c @@ -0,0 +1,976 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_thread.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_thread.c new file mode 100644 index 00000000000..39f42ee2347 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_thread.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#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); + } +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_utils.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_utils.c new file mode 100644 index 00000000000..1586633a742 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_utils.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_wait.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_wait.c new file mode 100644 index 00000000000..814ec89469c --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/tfm_wait.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/secure_utilities.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/secure_utilities.h new file mode 100644 index 00000000000..d35cdc7de27 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/secure_utilities.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_boot_data.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_boot_data.c new file mode 100644 index 00000000000..cad2b70b898 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_boot_data.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.c new file mode 100644 index 00000000000..db5921061e6 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#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(); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.h new file mode 100644 index 00000000000..a30a0fa1364 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_core.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_handler.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_handler.c new file mode 100644 index 00000000000..58e012322d1 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_handler.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + +#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 +#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) { + ; + } +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_internal.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_internal.h new file mode 100644 index 00000000000..18a56ecdacd --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_internal.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.c new file mode 100644 index 00000000000..8912b0422ef --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#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 diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.h new file mode 100644 index 00000000000..b485462519f --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_nspm.h @@ -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 + +/** + * \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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_platform_core_api.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_platform_core_api.h new file mode 100644 index 00000000000..7092e0c1bcc --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_platform_core_api.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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_psa_api_client.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_psa_api_client.c new file mode 100644 index 00000000000..36f2c163581 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_psa_api_client.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.c new file mode 100644 index 00000000000..e0663b4adb2 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.h new file mode 100644 index 00000000000..2f253e1ae67 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_spm_services.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_spm_services.c new file mode 100644 index 00000000000..9052ef7369f --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_spm_services.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include + +#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)); +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_svc.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_svc.h new file mode 100644 index 00000000000..44ad9ff73db --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_svc.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/tfm_spm_services_api.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/tfm_spm_services_api.h new file mode 100644 index 00000000000..be08ed278c7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/tfm_spm_services_api.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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.c new file mode 100644 index 00000000000..6331c30c49b --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.c @@ -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 +#include +#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; +} diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.h new file mode 100644 index 00000000000..c3f7414d4aa --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_api.h @@ -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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db.h new file mode 100644 index 00000000000..60b5fbd4569 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db.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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db_setup.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db_setup.h new file mode 100644 index 00000000000..a15e7b7cb14 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_db_setup.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 +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_partition_defs.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_partition_defs.h new file mode 100644 index 00000000000..0533881f872 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/spm_partition_defs.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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/LICENSE b/components/TARGET_PSA/TARGET_TFM/LICENSE new file mode 100644 index 00000000000..96810fdc927 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/LICENSE @@ -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 diff --git a/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause b/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause new file mode 100644 index 00000000000..476769c1fbc --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/LICENSE-BSD-3-Clause @@ -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. diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h new file mode 100644 index 00000000000..70534741a8a --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h @@ -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 +#include + +/*********************** 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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h new file mode 100644 index 00000000000..753fab76c55 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.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 + +/********************** 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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h new file mode 100644 index 00000000000..79a94cbdd06 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.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 +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.h new file mode 100644 index 00000000000..0c73a60a68b --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_lock.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 + +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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h new file mode 100644 index 00000000000..0399af9f0c0 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_ns_svc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.h new file mode 100644 index 00000000000..73f75a95e13 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_nspm_svc_handler.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 + +#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__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/tf-m-integration.md b/components/TARGET_PSA/TARGET_TFM/tf-m-integration.md new file mode 100644 index 00000000000..f38b6bce25d --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/tf-m-integration.md @@ -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 /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_ + └── TARGET_ + ├── common_files <-- files shared between NW and TZ images + ├── TARGET__NS + │   └── normal_world_files <-- files only to be included for NW build + └── TARGET__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. \ No newline at end of file diff --git a/components/TARGET_PSA/inc/psa/lifecycle.h b/components/TARGET_PSA/inc/psa/lifecycle.h index ab939abf98a..4f269fd386b 100644 --- a/components/TARGET_PSA/inc/psa/lifecycle.h +++ b/components/TARGET_PSA/inc/psa/lifecycle.h @@ -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 diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c index a0cc6b9b395..a11c6c01097 100644 --- a/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c +++ b/components/TARGET_PSA/services/crypto/COMPONENT_PSA_SRV_IPC/psa_crypto_spm.c @@ -24,9 +24,7 @@ #include #include #include "psa_crypto_srv_ifs.h" - #include "psa/client.h" - #include "crypto.h" #include "crypto_platform_spe.h" diff --git a/components/TARGET_PSA/services/crypto/COMPONENT_SPE/psa_crypto_partition.c b/components/TARGET_PSA/services/crypto/COMPONENT_SPE/psa_crypto_partition.c index 6651e2bc829..8b6dd75b038 100644 --- a/components/TARGET_PSA/services/crypto/COMPONENT_SPE/psa_crypto_partition.c +++ b/components/TARGET_PSA/services/crypto/COMPONENT_SPE/psa_crypto_partition.c @@ -1,10 +1,15 @@ // ---------------------------------- Includes --------------------------------- -#include "psa/service.h" -#include "psa/client.h" -#include -#include +#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(); } diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c index 36a66250ddc..269a5a7aae5 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c +++ b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_EMUL/platform_emul.c @@ -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(); +} diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c index f9c5c613b14..9951df50ba1 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c +++ b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.c @@ -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(); +} diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h index b2d3ae82547..6e44291fc0b 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h +++ b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IMPL/platform_srv_impl.h @@ -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__ diff --git a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c index c61eebe656e..8f36dfb9978 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c +++ b/components/TARGET_PSA/services/platform/COMPONENT_PSA_SRV_IPC/platform_ipc.c @@ -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); +} diff --git a/components/TARGET_PSA/services/platform/COMPONENT_SPE/TARGET_MBED_SPM/psa_platform_partition.c b/components/TARGET_PSA/services/platform/COMPONENT_SPE/TARGET_MBED_SPM/psa_platform_partition.c index 7d761e88765..72986f21620 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_SPE/TARGET_MBED_SPM/psa_platform_partition.c +++ b/components/TARGET_PSA/services/platform/COMPONENT_SPE/TARGET_MBED_SPM/psa_platform_partition.c @@ -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 */ diff --git a/components/TARGET_PSA/services/platform/COMPONENT_SPE/platform_partition.c b/components/TARGET_PSA/services/platform/COMPONENT_SPE/platform_partition.c index 355440bbaaf..6dc0cf6e695 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_SPE/platform_partition.c +++ b/components/TARGET_PSA/services/platform/COMPONENT_SPE/platform_partition.c @@ -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); + } } } diff --git a/components/TARGET_PSA/services/platform/COMPONENT_SPE/psa_platform_partition.h b/components/TARGET_PSA/services/platform/COMPONENT_SPE/psa_platform_partition.h index ef2f266d4a5..02445b8aefb 100644 --- a/components/TARGET_PSA/services/platform/COMPONENT_SPE/psa_platform_partition.h +++ b/components/TARGET_PSA/services/platform/COMPONENT_SPE/psa_platform_partition.h @@ -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 diff --git a/components/TARGET_PSA/services/platform/platform_psa.json b/components/TARGET_PSA/services/platform/platform_psa.json index a05f8697034..b519504cc5d 100644 --- a/components/TARGET_PSA/services/platform/platform_psa.json +++ b/components/TARGET_PSA/services/platform/platform_psa.json @@ -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": [ diff --git a/components/TARGET_PSA/services/platform/psa_platform_ifs.h b/components/TARGET_PSA/services/platform/psa_platform_ifs.h index db7c6677e6d..6aac5584fc4 100644 --- a/components/TARGET_PSA/services/platform/psa_platform_ifs.h +++ b/components/TARGET_PSA/services/platform/psa_platform_ifs.h @@ -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 diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp new file mode 100644 index 00000000000..a86866aa5c7 --- /dev/null +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/TARGET_TFM/its_tfm_impl.cpp @@ -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 +#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; +} + + diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp index 95a85aec588..925f7efd90c 100644 --- a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.cpp @@ -16,21 +16,38 @@ */ #include -#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 diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.h b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.h index fac053468d8..b426e68a5aa 100644 --- a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.h +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_PSA_SRV_IMPL/pits_impl.h @@ -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 diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/TARGET_MBED_SPM/psa_its_partition.c b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/TARGET_MBED_SPM/psa_its_partition.c index 96900732bcc..c4122edd6bb 100644 --- a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/TARGET_MBED_SPM/psa_its_partition.c +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/TARGET_MBED_SPM/psa_its_partition.c @@ -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"); } diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/its_partition.c b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/its_partition.c index fc203c6eaad..dfc5ad648b1 100644 --- a/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/its_partition.c +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/COMPONENT_SPE/its_partition.c @@ -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); } + } } diff --git a/components/TARGET_PSA/services/psa_prot_internal_storage/pits_psa.json b/components/TARGET_PSA/services/psa_prot_internal_storage/pits_psa.json index 24cc6ed66f2..2296e0dccdd 100644 --- a/components/TARGET_PSA/services/psa_prot_internal_storage/pits_psa.json +++ b/components/TARGET_PSA/services/psa_prot_internal_storage/pits_psa.json @@ -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", diff --git a/platform/mbed_retarget.cpp b/platform/mbed_retarget.cpp index d2de95bc7e1..d2d39bbd7b7 100644 --- a/platform/mbed_retarget.cpp +++ b/platform/mbed_retarget.cpp @@ -14,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include #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()) { diff --git a/rtos/TARGET_CORTEX/mbed_rtos_rtx.c b/rtos/TARGET_CORTEX/mbed_rtos_rtx.c index 9172dfe62c7..d36ceffa147 100644 --- a/rtos/TARGET_CORTEX/mbed_rtos_rtx.c +++ b/rtos/TARGET_CORTEX/mbed_rtos_rtx.c @@ -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) { diff --git a/tools/importer/tfm_importer.json b/tools/importer/tfm_importer.json new file mode 100644 index 00000000000..e9624f1b25a --- /dev/null +++ b/tools/importer/tfm_importer.json @@ -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" + ] +} + diff --git a/tools/psa/__init__.py b/tools/psa/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tools/psa/generate_mbed_spm_partition_code.py b/tools/psa/generate_mbed_spm_partition_code.py new file mode 100644 index 00000000000..1281fb85e94 --- /dev/null +++ b/tools/psa/generate_mbed_spm_partition_code.py @@ -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() diff --git a/tools/psa/generate_tfm_partition_code.py b/tools/psa/generate_tfm_partition_code.py new file mode 100644 index 00000000000..947c3b8d61f --- /dev/null +++ b/tools/psa/generate_tfm_partition_code.py @@ -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() diff --git a/tools/spm/templates/COMPONENT_SPE/TARGET_MBED_SPM/psa_NAME_partition.c.tpl b/tools/psa/mbed_spm/templates/COMPONENT_SPE/TARGET_MBED_SPM/psa_NAME_partition.c.tpl similarity index 100% rename from tools/spm/templates/COMPONENT_SPE/TARGET_MBED_SPM/psa_NAME_partition.c.tpl rename to tools/psa/mbed_spm/templates/COMPONENT_SPE/TARGET_MBED_SPM/psa_NAME_partition.c.tpl diff --git a/tools/spm/templates/COMPONENT_SPE/psa_NAME_partition.h.tpl b/tools/psa/mbed_spm/templates/COMPONENT_SPE/psa_NAME_partition.h.tpl similarity index 100% rename from tools/spm/templates/COMPONENT_SPE/psa_NAME_partition.h.tpl rename to tools/psa/mbed_spm/templates/COMPONENT_SPE/psa_NAME_partition.h.tpl diff --git a/tools/spm/templates/COMPONENT_SPE/psa_setup.c.tpl b/tools/psa/mbed_spm/templates/COMPONENT_SPE/psa_setup.c.tpl similarity index 100% rename from tools/spm/templates/COMPONENT_SPE/psa_setup.c.tpl rename to tools/psa/mbed_spm/templates/COMPONENT_SPE/psa_setup.c.tpl diff --git a/tools/spm/templates/psa_NAME_ifs.h.tpl b/tools/psa/mbed_spm/templates/psa_NAME_ifs.h.tpl similarity index 100% rename from tools/spm/templates/psa_NAME_ifs.h.tpl rename to tools/psa/mbed_spm/templates/psa_NAME_ifs.h.tpl diff --git a/tools/spm/generate_partition_code.py b/tools/psa/mbed_spm_tfm_common.py similarity index 74% rename from tools/spm/generate_partition_code.py rename to tools/psa/mbed_spm_tfm_common.py index 85271e19bee..35207c8acd2 100644 --- a/tools/spm/generate_partition_code.py +++ b/tools/psa/mbed_spm_tfm_common.py @@ -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 -from six import integer_types, string_types - -from jinja2 import Environment, FileSystemLoader, StrictUndefined +import json from jsonschema import validate +import fnmatch +from six import integer_types, string_types -__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 @@ def __init__( 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 @@ def __init__( 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 @@ def __eq__(self, other): ) @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 @@ def from_json(cls, manifest_file, skip_src=False): 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 @@ def templates_to_files(self, templates, templates_base, output_dir): 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() diff --git a/tools/spm/partition_description_schema.json b/tools/psa/partition_description_schema.json similarity index 100% rename from tools/spm/partition_description_schema.json rename to tools/psa/partition_description_schema.json diff --git a/tools/psa/tfm/mbed_app.json b/tools/psa/tfm/mbed_app.json new file mode 100644 index 00000000000..8594d501062 --- /dev/null +++ b/tools/psa/tfm/mbed_app.json @@ -0,0 +1,5 @@ +{ + "name": "tfm_build", + "requires" : ["psa-services", "tfm"], + "artifact_name": "tfm" +} diff --git a/tools/psa/tfm/templates/tfm_partition_defs.inc.tpl b/tools/psa/tfm/templates/tfm_partition_defs.inc.tpl new file mode 100644 index 00000000000..c72345dfaa2 --- /dev/null +++ b/tools/psa/tfm/templates/tfm_partition_defs.inc.tpl @@ -0,0 +1,32 @@ +/* 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__ + +{% for partition in partitions %} +{% set partition_loop = loop %} +#ifdef TFM_PSA_API +#define {{partition.name|upper}}_ID (TFM_SP_BASE + {{ partition_loop.index0 }}) +#endif + +{% endfor %} +#define TFM_MAX_USER_PARTITIONS ({{partitions|count}}) + +#endif /* __TFM_PARTITION_DEFS_INC__ */ diff --git a/tools/psa/tfm/templates/tfm_partition_list.inc.tpl b/tools/psa/tfm/templates/tfm_partition_list.inc.tpl new file mode 100644 index 00000000000..ce3d39fa0ec --- /dev/null +++ b/tools/psa/tfm/templates/tfm_partition_list.inc.tpl @@ -0,0 +1,23 @@ +/* + * 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__ + +{% for partition in partitions %} +#ifdef TFM_PSA_API +/******** {{partition.name|upper}} ********/ +PARTITION_DECLARE({{partition.name|upper}}, 0 + | SPM_PART_FLAG_IPC + , "{{partition.type}}", {{partition.id}}, {{partition.priority}}, {{partition.stack_size}}); +PARTITION_ADD_INIT_FUNC({{partition.name|upper}}, {{partition.entry_point}}); +#endif /* TFM_PSA_API */ + +{% endfor %} +#endif /* __TFM_PARTITION_LIST_INC__ */ diff --git a/tools/psa/tfm/templates/tfm_service_list.inc.tpl b/tools/psa/tfm/templates/tfm_service_list.inc.tpl new file mode 100644 index 00000000000..cef215943e8 --- /dev/null +++ b/tools/psa/tfm/templates/tfm_service_list.inc.tpl @@ -0,0 +1,22 @@ +/* + * 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__ + +{% for partition in partitions %} +#ifdef TFM_PSA_API +/******** {{partition.name|upper}} ********/ +{% for rot_srv in partition.rot_services %} +{"{{rot_srv.name|upper}}", {{partition.name|upper}}_ID, {{rot_srv.signal|upper}}, {{rot_srv.id}}, {% if rot_srv.nspe_callable %}true{% else %}false{% endif %}, {{rot_srv.minor_version}}, TFM_VERSION_POLICY_{{rot_srv.minor_policy|upper}}}, +{% endfor %} +#endif /* TFM_PSA_API */ + +{% endfor %} +#endif /* __TFM_SERVICE_LIST_INC__ */ diff --git a/tools/psa/tfm/templates/tfm_spm_signal_defs.h.tpl b/tools/psa/tfm/templates/tfm_spm_signal_defs.h.tpl new file mode 100644 index 00000000000..c554a026f13 --- /dev/null +++ b/tools/psa/tfm/templates/tfm_spm_signal_defs.h.tpl @@ -0,0 +1,18 @@ +/* + * 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__ + +{% for partition in partitions %} +{% for rot_srv in partition.rot_services %} +#define {{rot_srv.signal|upper}}_POS ({{loop.index + 3}}UL) +#define {{rot_srv.signal|upper}} (1UL << {{rot_srv.signal|upper}}_POS) +{% endfor %} + +{% endfor %} + +#endif diff --git a/tools/psa/tfm/tfm_generated_file_list.json b/tools/psa/tfm/tfm_generated_file_list.json new file mode 100644 index 00000000000..ddecfcd997c --- /dev/null +++ b/tools/psa/tfm/tfm_generated_file_list.json @@ -0,0 +1,22 @@ +[ + { + "name": "Secure Partition ID definitions", + "template": "tools/psa/tfm/templates/tfm_partition_defs.inc.tpl", + "output": "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_defs.inc" + }, + { + "name": "Secure Partition declarations", + "template": "tools/psa/tfm/templates/tfm_partition_list.inc.tpl", + "output": "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_partition_list.inc" + }, + { + "name": "Secure Service list", + "template": "tools/psa/tfm/templates/tfm_service_list.inc.tpl", + "output": "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_service_list.inc" + }, + { + "name": "Secure Service siganls list", + "template": "tools/psa/tfm/templates/tfm_spm_signal_defs.h.tpl", + "output": "components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/autogen/tfm_spm_signal_defs.h" + } +] diff --git a/tools/spm/__init__.py b/tools/spm/__init__.py deleted file mode 100644 index 5305b8db929..00000000000 --- a/tools/spm/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# 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. - -from .generate_partition_code import \ - generate_partitions_sources, generate_psa_setup - -__all__ = [ - 'generate_partitions_sources', - 'generate_psa_setup', -] diff --git a/tools/test/spm/test_generate_partition_code.py b/tools/test/spm/test_generate_partition_code.py index 13abd5e2956..b37570733ff 100644 --- a/tools/test/spm/test_generate_partition_code.py +++ b/tools/test/spm/test_generate_partition_code.py @@ -24,10 +24,11 @@ from jinja2.defaults import DEFAULT_FILTERS from .test_data import * -from tools.spm.generate_partition_code import * +from tools.psa.mbed_spm_tfm_common import * +from tools.psa.generate_mbed_spm_partition_code import * # Imported again as a module for monkey-patching -import tools.spm.generate_partition_code as generate_partition_code +import tools.psa.generate_mbed_spm_partition_code as generate_partition_code SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))