From abd60fc341cd2662ce44ccefd3b0ef1c44ee0c3d Mon Sep 17 00:00:00 2001 From: Oren Cohen Date: Sun, 31 Mar 2019 13:59:24 +0300 Subject: [PATCH] [trusted-firmware-m]: Updated to 0101fd37 # Conflicts: # components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c --- .../COMPONENT_SPE/bl2/include/boot_record.h | 31 +- .../bl2/include/tfm_boot_status.h | 189 ++++++-- .../secure_fw/core/CMakeLists.inc | 71 +++ .../COMPONENT_SPE/secure_fw/core/dir_core.dox | 16 + .../secure_fw/core/ipc/CMakeLists.inc | 74 ++++ .../core/ipc/include/tfm_message_queue.h | 4 +- .../secure_fw/core/ipc/include/tfm_spm.h | 6 +- .../core/ipc/include/tfm_spm_signal_defs.h | 14 + .../secure_fw/core/ipc/include/tfm_svcalls.h | 7 +- .../secure_fw/core/ipc/include/tfm_wait.h | 77 +--- .../secure_fw/core/ipc/tfm_arch_v8m.c | 34 +- .../secure_fw/core/ipc/tfm_pools.c | 2 +- .../secure_fw/core/ipc/tfm_spm.c | 56 +-- .../secure_fw/core/ipc/tfm_svcalls.c | 45 +- .../secure_fw/core/ipc/tfm_thread.c | 2 +- .../secure_fw/core/ipc/tfm_wait.c | 52 +-- .../secure_fw/core/secure_utilities.h | 29 +- .../secure_fw/core/tfm_boot_data.c | 37 +- .../COMPONENT_SPE/secure_fw/core/tfm_core.c | 2 + .../secure_fw/core/tfm_handler.c | 4 +- .../secure_fw/core/tfm_memory_utils.h | 45 ++ .../secure_fw/core/tfm_psa_api_client.c | 5 +- .../secure_fw/core/tfm_secure_api.c | 410 +++++++++++++++++- .../secure_fw/core/tfm_secure_api.h | 20 +- .../secure_fw/core/tfm_spm_services.c | 5 +- .../secure_fw/include/dir_include.dox | 17 + .../secure_fw/spm/CMakeLists.inc | 61 +++ .../COMPONENT_SPE/secure_fw/spm/dir_spm.dox | 16 + .../COMPONENT_SPE/secure_fw/spm/spm_api.c | 43 +- .../COMPONENT_SPE/secure_fw/spm/spm_api.h | 108 +++-- .../COMPONENT_SPE/secure_fw/spm/spm_db.h | 12 +- .../secure_fw/spm/spm_db_setup.h | 19 +- .../secure_fw/spm/spm_partition_defs.h | 2 +- .../TARGET_TFM/interface/include/psa_client.h | 2 +- .../interface/include/psa_service.h | 2 - .../TARGET_TFM/interface/include/tfm_api.h | 13 +- 36 files changed, 1185 insertions(+), 347 deletions(-) create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/CMakeLists.inc create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/dir_core.dox create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/CMakeLists.inc create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm_signal_defs.h create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_memory_utils.h create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/dir_include.dox create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/CMakeLists.inc create mode 100644 components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/dir_spm.dox 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 index ab71a48629..217a20684c 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -11,6 +11,8 @@ #include #include #include +#include "../ext/mcuboot/bootutil/include/bootutil/image.h" +#include "../ext/mcuboot/include/flash_map/flash_map.h" #ifdef __cplusplus extern "C" { @@ -30,6 +32,16 @@ enum shared_memory_err_t { TLV_TYPE_MAX = INT_MAX }; +/*! + * \enum boot_status_err_t + * + * \brief Return values for saving boot status information to shared memory are + */ +enum boot_status_err_t { + BOOT_STATUS_OK, + BOOT_STATUS_ERROR, +}; + /*! * \brief Add a data item to the shared data area between bootloader and * runtime SW @@ -43,10 +55,25 @@ enum shared_memory_err_t { */ enum shared_memory_err_t boot_add_data_to_shared_area(uint8_t major_type, - uint8_t minor_type, + uint16_t minor_type, size_t size, const uint8_t *data); +/*! + * \brief Add an image's all boot status information to the shared data area + * between bootloader and runtime SW + * + * \param[in] sw_module Identifier of the SW component + * \param[in] hdr Pointer to the image header stored in RAM + * \param[in] fap Pointer to the flash area where image is stored + * + * \return Returns error code as specified in \ref boot_status_err_t + */ +enum boot_status_err_t +boot_save_boot_status(uint8_t sw_module, + const struct image_header *hdr, + const struct flash_area *fap); + #ifdef __cplusplus } #endif 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 index 30a7b1c2cc..dbcc6ced47 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -16,43 +16,165 @@ 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 +/* Major numbers (4 bit) 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 +/** + * The shared data between boot loader and runtime SW is TLV encoded. The + * shared data is stored in a well known location in secure memory and this is + * a contract between boot loader and runtime SW. + * + * The structure of shared data must be the following: + * - At the beginning there must be a header: struct shared_data_tlv_header + * This contains a magic number and a size field which covers the entire + * size of the shared data area including this header. + * - After the header there come the entries which are composed from an entry + * header structure: struct shared_data_tlv_entry and the data. In the entry + * header is a type field (tly_type) which identify the consumer of the + * entry in the runtime SW and specify the subtype of that data item. There + * is a size field (tlv_len) which covers the size of the entry header and + * the data. After this structure comes the actual data. + * - Arbitrary number and size of data entry can be in the shared memory area. + * + * This table gives of overview about the tlv_type field in the entry header. + * The tlv_type always composed from a major and minor number. Major number + * identifies the addressee in runtime SW, who should process the data entry. + * Minor number used to encode more info about the data entry. The actual + * definition of minor number could change per major number. In case of boot + * status data, which is going to be processed by initial attestation service + * the minor number is split further to two part: sw_module and claim. The + * sw_module identifies the SW component in the system which the data item + * belongs to and the claim part identifies the exact type of the data. + * + * |---------------------------------------| + * | tlv_type (16) | + * |---------------------------------------| + * | tlv_major(4)| tlv_minor(12) | + * |---------------------------------------| + * | MAJOR_IAS | sw_module(6) | claim(6) | + * |---------------------------------------| + * | MAJOR_CORE | TBD | + * |---------------------------------------| + */ -/* 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 +/* Initial attestation: SW components / SW modules + * This list is intended to be adjusted per device. It contains more SW + * components than currently available in TF-M project. It serves as an example, + * what kind of SW components might be available. + */ +#define SW_GENERAL 0x00 +#define SW_BL2 0x01 +#define SW_PROT 0x02 +#define SW_AROT 0x03 +#define SW_SPE 0x04 +#define SW_NSPE 0x05 +#define SW_S_NS 0x06 +#define SW_MAX 0x07 -/* 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 +/* Initial attestation: Claim per SW components / SW modules */ +/* Bits: 0-2 */ +#define SW_VERSION 0x00 +#define SW_SIGNER_ID 0x01 +#define SW_EPOCH 0x02 +#define SW_TYPE 0x03 +/* Bits: 3-5 */ +#define SW_MEASURE_VALUE 0x08 +#define SW_MEASURE_TYPE 0x09 -/* 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 +/* Initial attestation: General claim does not belong any particular SW + * component. But they might be part of the boot status. + */ +#define BOOT_SEED 0x00 +#define HW_VERSION 0x01 +#define SECURITY_LIFECYCLE 0x02 -/* 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 +/* Minor numbers (12 bit) to identify attestation service related data */ +#define TLV_MINOR_IAS_BOOT_SEED ((SW_GENERAL << 6) | BOOT_SEED) +#define TLV_MINOR_IAS_HW_VERSION ((SW_GENERAL << 6) | HW_VERSION) +#define TLV_MINOR_IAS_SLC ((SW_GENERAL << 6) | SECURITY_LIFECYCLE) +/* Bootloader - It can be more stage */ +#define TLV_MINOR_IAS_BL2_MEASURE_VALUE ((SW_BL2 << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_BL2_MEASURE_TYPE ((SW_BL2 << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_BL2_VERSION ((SW_BL2 << 6) | SW_VERSION) +#define TLV_MINOR_IAS_BL2_SIGNER_ID ((SW_BL2 << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_BL2_EPOCH ((SW_BL2 << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_BL2_TYPE ((SW_BL2 << 6) | SW_TYPE) + +/* PROT: PSA Root of Trust */ +#define TLV_MINOR_IAS_PROT_MEASURE_VALUE ((SW_PROT << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_PROT_MEASURE_TYPE ((SW_PROT << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_PROT_VERSION ((SW_PROT << 6) | SW_VERSION) +#define TLV_MINOR_IAS_PROT_SIGNER_ID ((SW_PROT << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_PROT_EPOCH ((SW_PROT << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_PROT_TYPE ((SW_PROT << 6) | SW_TYPE) + +/* AROT: Application Root of Trust */ +#define TLV_MINOR_IAS_AROT_MEASURE_VALUE ((SW_AROT << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_AROT_MEASURE_TYPE ((SW_AROT << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_AROT_VERSION ((SW_AROT << 6) | SW_VERSION) +#define TLV_MINOR_IAS_AROT_SIGNER_ID ((SW_AROT << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_AROT_EPOCH ((SW_AROT << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_AROT_TYPE ((SW_AROT << 6) | SW_TYPE) + +/* Non-secure processing environment - single non-secure image */ +#define TLV_MINOR_IAS_NSPE_MEASURE_VALUE ((SW_NSPE << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_NSPE_MEASURE_TYPE ((SW_NSPE << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_NSPE_VERSION ((SW_NSPE << 6) | SW_VERSION) +#define TLV_MINOR_IAS_NSPE_SIGNER_ID ((SW_NSPE << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_NSPE_EPOCH ((SW_NSPE << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_NSPE_TYPE ((SW_NSPE << 6) | SW_TYPE) + +/* Secure processing environment (ARoT + PRoT) - single secure image */ +#define TLV_MINOR_IAS_SPE_MEASURE_VALUE ((SW_SPE << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_SPE_MEASURE_TYPE ((SW_SPE << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_SPE_VERSION ((SW_SPE << 6) | SW_VERSION) +#define TLV_MINOR_IAS_SPE_SIGNER_ID ((SW_SPE << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_SPE_EPOCH ((SW_SPE << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_SPE_TYPE ((SW_SPE << 6) | SW_TYPE) + +/* SPE + NSPE - combined secure and non-secure image */ +#define TLV_MINOR_IAS_S_NS_MEASURE_VALUE ((SW_S_NS << 6) | SW_MEASURE_VALUE) +#define TLV_MINOR_IAS_S_NS_MEASURE_TYPE ((SW_S_NS << 6) | SW_MEASURE_TYPE) +#define TLV_MINOR_IAS_S_NS_VERSION ((SW_S_NS << 6) | SW_VERSION) +#define TLV_MINOR_IAS_S_NS_SIGNER_ID ((SW_S_NS << 6) | SW_SIGNER_ID) +#define TLV_MINOR_IAS_S_NS_EPOCH ((SW_S_NS << 6) | SW_EPOCH) +#define TLV_MINOR_IAS_S_NS_TYPE ((SW_S_NS << 6) | SW_TYPE) + +/* General macros to handle TLV type */ +#define MAJOR_MASK 0xF /* 4 bit */ +#define MAJOR_POS 12 /* 12 bit */ +#define MINOR_MASK 0xFFF /* 12 bit */ + +#define SET_TLV_TYPE(major, minor) \ + ((((major) & MAJOR_MASK) << MAJOR_POS) | ((minor) & MINOR_MASK)) +#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS) +#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK) + +/* Initial attestation specific macros */ +#define MODULE_POS 6 /* 6 bit */ +#define CLAIM_MASK 0x3F /* 6 bit */ +#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */ + +#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS) +#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK) +#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim)) + +#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \ + MEASUREMENT_CLAIM_POS) + +/* Magic value which marks the beginning of shared data area in memory */ #define SHARED_DATA_TLV_INFO_MAGIC 0x2016 /** * Shared data TLV header. All fields in little endian. * - * --------------------------- - * | tlv_magic | tlv_tot_len | - * --------------------------- + * ----------------------------------- + * | tlv_magic(16) | tlv_tot_len(16) | + * ----------------------------------- */ struct shared_data_tlv_header { uint16_t tlv_magic; @@ -64,15 +186,14 @@ 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 | - * --------------------------------------------- + * ------------------------------- + * | tlv_type(16) | tlv_len(16) | + * ------------------------------- + * | Raw data | + * ------------------------------- */ struct shared_data_tlv_entry { - uint8_t tlv_major_type; - uint8_t tlv_minor_type; + uint16_t tlv_type; uint16_t tlv_len; /* size of single TLV entry (including this header). */ }; diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/CMakeLists.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/CMakeLists.inc new file mode 100644 index 0000000000..0b290d5b01 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/CMakeLists.inc @@ -0,0 +1,71 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2017-2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +#Definitions to compile the "core" module. +#This file assumes it will be included from a project specific cmakefile, and +#will not create a library or executable. +#Inputs: +# TFM_ROOT_DIR - directory where secure FW sourec is located. +# +#Outputs: +# Will modify include directories to make the source compile. +# ALL_SRC_C: C source files to be compiled will be added to this list. +# This shall be added to your add_executable or add_library command. +# ALL_SRC_CXX: C++ source files to be compiled will be added to this list. +# This shall be added to your add_executable or add_library command. +# ALL_SRC_ASM: assembly source files to be compiled will be added to this +# list. This shall be added to your add_executable or add_library +# command. +# Include directories will be modified by using the include_directories() +# commands as needed. + +#Get the current directory where this file is located. +set(SS_CORE_DIR ${CMAKE_CURRENT_LIST_DIR}) +if(NOT DEFINED TFM_ROOT_DIR) + message(FATAL_ERROR + "Please set TFM_ROOT_DIR before including this file.") +endif() + +set (SS_CORE_C_SRC + "${SS_CORE_DIR}/tfm_core.c" + "${SS_CORE_DIR}/tfm_handler.c" + "${SS_CORE_DIR}/tfm_secure_api.c" + "${SS_CORE_DIR}/tfm_spm_services.c" + "${SS_CORE_DIR}/tfm_nspm.c" + "${SS_CORE_DIR}/tfm_boot_data.c" + ) + +#Append all our source files to global lists. +list(APPEND ALL_SRC_C ${SS_CORE_C_SRC}) +unset(SS_CORE_C_SRC) + +#Setting include directories +embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/spm ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core ABSOLUTE) + +set(BUILD_CMSIS_CORE Off) +set(BUILD_RETARGET Off) +set(BUILD_NATIVE_DRIVERS Off) +set(BUILD_STARTUP Off) +set(BUILD_TARGET_CFG Off) +set(BUILD_TARGET_HARDWARE_KEYS Off) +set(BUILD_TARGET_NV_COUNTERS Off) +set(BUILD_CMSIS_DRIVERS Off) +set(BUILD_TIME Off) +set(BUILD_UART_STDOUT Off) +set(BUILD_FLASH Off) +set(BUILD_BOOT_SEED Off) +set(BUILD_DEVICE_ID Off) +if(NOT DEFINED PLATFORM_CMAKE_FILE) + message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.") +elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE}) + message (FATAL_ERROR "Platform specific CMake \"${PLATFORM_CMAKE_FILE}\" file does not exist. Please fix value of PLATFORM_CMAKE_FILE.") +else() + include(${PLATFORM_CMAKE_FILE}) +endif() diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/dir_core.dox b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/dir_core.dox new file mode 100644 index 0000000000..a8da84823b --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/dir_core.dox @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +//This file holds description for the current directory. This documentation +//will be included in the Doxygen output. + +/*! +\dir +\brief Source code for the TF-M core. +\details This directory holds the source code of the "TF-M core" module. + +*/ \ No newline at end of file diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/CMakeLists.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/CMakeLists.inc new file mode 100644 index 0000000000..59c074e60f --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/CMakeLists.inc @@ -0,0 +1,74 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +#Definitions to compile the "ipc" module. +#This file assumes it will be included from a project specific cmakefile, and +#will not create a library or executable. +#Inputs: +# TFM_ROOT_DIR - directory where secure FW sourec is located. +# +#Outputs: +# Will modify include directories to make the source compile. +# ALL_SRC_C: C source files to be compiled will be added to this list. +# This shall be added to your add_executable or add_library command. +# ALL_SRC_CXX: C++ source files to be compiled will be added to this list. +# This shall be added to your add_executable or add_library command. +# ALL_SRC_ASM: assembly source files to be compiled will be added to this +# list. This shall be added to your add_executable or add_library +# command. +# Include directories will be modified by using the include_directories() +# commands as needed. + +#Get the current directory where this file is located. +set(SS_IPC_DIR ${CMAKE_CURRENT_LIST_DIR}) +if(NOT DEFINED TFM_ROOT_DIR) + message(FATAL_ERROR + "Please set TFM_ROOT_DIR before including this file.") +endif() + +if (NOT DEFINED TFM_PSA_API) + message(FATAL_ERROR "Incomplete build configuration: TFM_PSA_API is undefined. ") +elseif (TFM_PSA_API) + set (SS_IPC_C_SRC "${SS_IPC_DIR}/tfm_svcalls.c" + "${SS_IPC_DIR}/psa_service.c" + "${SS_IPC_DIR}/psa_client.c" + "${SS_IPC_DIR}/tfm_arch_v8m.c" + "${SS_IPC_DIR}/tfm_thread.c" + "${SS_IPC_DIR}/tfm_wait.c" + "${SS_IPC_DIR}/tfm_utils.c" + "${SS_IPC_DIR}/tfm_message_queue.c" + "${SS_IPC_DIR}/tfm_pools.c" + "${SS_IPC_DIR}/tfm_spm.c" + "${SS_IPC_DIR}/../tfm_core.c" + "${SS_IPC_DIR}/../tfm_secure_api.c" + "${SS_IPC_DIR}/../tfm_spm_services.c" + "${SS_IPC_DIR}/../tfm_handler.c" + "${SS_IPC_DIR}/../tfm_psa_api_client.c" + "${SS_IPC_DIR}/../tfm_nspm.c" + "${SS_IPC_DIR}/../tfm_boot_data.c" + ) +endif() + +#Append all our source files to global lists. +list(APPEND ALL_SRC_C ${SS_IPC_C_SRC}) +unset(SS_IPC_C_SRC) + +#Setting include directories +embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/spm ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core/ipc ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core/ipc/include ABSOLUTE) + +if(NOT DEFINED PLATFORM_CMAKE_FILE) + message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.") +elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE}) + message (FATAL_ERROR "Platform specific CMake \"${PLATFORM_CMAKE_FILE}\" file does not exist. Please fix value of PLATFORM_CMAKE_FILE.") +else() + include(${PLATFORM_CMAKE_FILE}) +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 index 31bcda9482..a00c179893 100644 --- 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 @@ -7,16 +7,14 @@ #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 */ + struct tfm_event_t ack_evnt; /* 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]; 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 index 0fd3a8f800..d197ae9a8c 100644 --- 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 @@ -10,15 +10,11 @@ #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 { @@ -59,7 +55,7 @@ struct tfm_spm_service_t { 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 */ + struct tfm_event_t signal_evnt; /* 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 */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm_signal_defs.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm_signal_defs.h new file mode 100644 index 0000000000..924de1f74a --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_spm_signal_defs.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ +#ifndef __TFM_SPM_SIGNAL_DEFS_H__ +#define __TFM_SPM_SIGNAL_DEFS_H__ + +#include "test/test_services/tfm_ipc_service/tfm_ipc_service_partition.h" +#include "test/test_services/tfm_core_test/tfm_ss_core_test_signal.h" +#include "test/test_services/tfm_core_test_2/tfm_ss_core_test_2_signal.h" + +#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 index fdbc4a9ce4..97c506be14 100644 --- 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 @@ -58,7 +58,7 @@ psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller); * 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. - * \param[in] lr Link register to be stored + * \param[in] lr EXC_RETURN value of the SVC. * * \retval >=0 RoT Service-specific status value. * \retval <0 RoT Service-specific error code. @@ -74,7 +74,8 @@ psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller); * \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, uint32_t lr); +psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller, + uint32_t lr); /** * \brief SVC handler for \ref psa_close. @@ -97,7 +98,7 @@ void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller); * * \param[in] svc_num SVC number * \param[in] ctx Argument context - * \param[in] lr Link register to be stored + * \param[in] lr EXC_RETURN value of the SVC. * * \returns Return values from those who has, * or PSA_SUCCESS. 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 index 2bed0aec3d..0bb6ea38e9 100644 --- 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 @@ -9,78 +9,47 @@ #include "cmsis_compiler.h" -#define EVENT_MAGIC 0x65766e74 -#define EVENT_STAT_WAITED 0x0 -#define EVENT_STAT_SIGNALED 0x1 +/* The magic number has two purposes: corruption detection and debug */ +#define TFM_EVENT_MAGIC 0x65766e74 -struct tfm_event_ctx { - uint32_t magic; /* 'evnt' */ - struct tfm_thrd_ctx *owner; /* waiting thread */ - uint32_t status; /* status */ - uint32_t retval; /* return value */ +struct tfm_event_t { + uint32_t magic; /* 'evnt' */ + struct tfm_thrd_ctx *owner; /* Event blocked thread */ }; /* - * Initialize an event context. + * Initialize an event object. * - * Parameters : - * pevt - pointer of event context caller provided - * stat - initial status (EVENT_STAT_WAITED or EVENT_STAT_SIGNALED) + * Parameters: + * pevnt - The pointer of event object allocated by the caller */ -void __STATIC_INLINE tfm_event_init(struct tfm_event_ctx *pevt, uint32_t stat) +void __STATIC_INLINE tfm_event_init(struct tfm_event_t *pevnt) { - pevt->magic = EVENT_MAGIC; - pevt->status = stat; - pevt->owner = NULL; - pevt->retval = 0; + pevnt->magic = TFM_EVENT_MAGIC; + pevnt->owner = NULL; } /* - * Wait on an event. + * Wait on an event object. * - * Parameters : - * pevt - pointer of event context + * Parameters: + * pevnt - The pointer of event object allocated by the caller * - * Notes : - * Thread is blocked if event is not signaled. + * Notes: + * Block caller thread by calling this function. */ -void tfm_event_wait(struct tfm_event_ctx *pevt); +void tfm_event_wait(struct tfm_event_t *pevnt); /* - * Signal an event. + * Wake up an event object. * * Parameters : - * pevt - pointer of event context + * pevnt - The pointer of event object allocated by the caller + * retval - Value to be returned to owner * - * Notes : - * Waiting thread on this event will be running. + * Notes: + * Wake up the blocked thread and set parameter 'retval' as the return value. */ -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); +void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval); #endif 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 index 5c50636896..bbf597a56e 100644 --- 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 @@ -11,9 +11,9 @@ #include "cmsis.h" #include "psa_client.h" #include "psa_service.h" -#include "secure_utilities.h" #include "tfm_utils.h" #include "tfm_thread.h" +#include "tfm_memory_utils.h" /* This file contains the ARCH code for ARM V8M */ @@ -91,6 +91,7 @@ void tfm_initialize_context(struct tfm_state_context *ctx, * thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes * aligned. */ +#if defined(__ARM_ARCH_8M_MAIN__) __attribute__((naked)) void PendSV_Handler(void) { __ASM( @@ -107,6 +108,37 @@ __attribute__((naked)) void PendSV_Handler(void) "bx lr \n" ); } +#elif defined(__ARM_ARCH_8M_BASE__) +__attribute__((naked)) void PendSV_Handler(void) +{ + __ASM( + "mrs r0, psp \n" + "mrs r1, psplim \n" + "push {r0, r1, r2, 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 r0, sp \n" + "bl tfm_pendsv_do_schedule \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 {r0-r3} \n" + "mov lr, r3 \n" + "msr psp, r0 \n" + "msr psplim, r1 \n" + "bx lr \n" + ); +} +#else +#error "Unsupported ARM Architecture." +#endif /* Reserved for future usage */ __attribute__((naked)) void MemManage_Handler(void) 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 index a5e7b2a65b..83342b88bb 100644 --- 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 @@ -17,7 +17,7 @@ #include "tfm_utils.h" #include "tfm_list.h" #include "tfm_pools.h" -#include "secure_utilities.h" +#include "tfm_memory_utils.h" int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz, size_t chunksz, size_t num) 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 index 9fd056e19a..dfc8c94c9d 100644 --- 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 @@ -25,6 +25,7 @@ #include "tfm_thread.h" #include "region_defs.h" #include "tfm_nspm.h" +#include "tfm_memory_utils.h" /* * IPC partitions. @@ -45,7 +46,7 @@ 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" + #include "secure_fw/services/tfm_service_list.inc" }; /********************** SPM functions for handler mode ***********************/ @@ -108,8 +109,6 @@ int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service, /* 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; @@ -272,7 +271,7 @@ int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service, switch (service->service_db->minor_policy) { case TFM_VERSION_POLICY_RELAXED: - if (minor_version > service->service_db->minor_version) { + if (minor_version < service->service_db->minor_version) { return IPC_ERROR_VERSION; } break; @@ -348,7 +347,7 @@ struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service, /* 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); + tfm_event_init(&msg->ack_evnt); msg->magic = TFM_MSG_MAGIC; msg->service = service; msg->handle = handle; @@ -405,15 +404,11 @@ int32_t tfm_spm_send_event(struct tfm_spm_service_t *service, /* 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); + tfm_event_wake(&service->partition->signal_evnt, + (service->partition->signals & + service->partition->signal_mask)); - /* Wake waiting thread up */ - tfm_event_signal(&service->partition->signal_event); - - tfm_event_wait(&msg->ack_mtx); + tfm_event_wait(&msg->ack_evnt); return IPC_SUCCESS; } @@ -435,19 +430,15 @@ 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) +static uint32_t tfm_spm_partition_get_stack_base_ext(uint32_t partition_idx) { - return g_spm_partition_db.partitions[partition_idx].stack_size; + return (uint32_t)&(g_spm_partition_db.partitions[partition_idx]. + stack[TFM_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); + return (uint32_t)&g_spm_partition_db.partitions[partition_idx].stack; } static tfm_thrd_func_t @@ -466,8 +457,6 @@ static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx) /* 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, $$ZI$$Base); REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$ZI$$Limit); REGION_DECLARE_EXT(Image$$, ER_TFM_DATA, $$RW$$Base); @@ -523,19 +512,7 @@ int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller) 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, $$RW$$Base); limit = (uintptr_t)®ION_NAME(Image$$, ER_TFM_DATA, $$RW$$Limit); if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) { @@ -560,12 +537,6 @@ int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller) if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) { return IPC_SUCCESS; } - - base = (uintptr_t)S_CODE_START; - limit = (uintptr_t)(S_CODE_START + S_CODE_SIZE); - if (memory_check_range(buffer, len, base, limit) == IPC_SUCCESS) { - return IPC_SUCCESS; - } } return IPC_ERROR_MEMORY_CHECK; @@ -598,7 +569,8 @@ void tfm_spm_init(void) } 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_event_init(&g_spm_ipc_partition[i].signal_evnt); tfm_list_init(&g_spm_ipc_partition[i].service_list); pth = tfm_spm_partition_get_thread_info_ext(i); 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 index a3fab65fea..5483ba3d43 100644 --- 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 @@ -18,9 +18,9 @@ #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" +#include "tfm_memory_utils.h" #define PSA_TIMEOUT_MASK PSA_BLOCK @@ -124,17 +124,25 @@ psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller, uint32_t lr) in_num = (size_t)args[2]; outptr = (psa_outvec *)args[3]; /* - * 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 be args[26]. + * 5th parameter is pushed at stack top before SVC, then PE hardware + * stacks the execution context. The size of the context depends on + * various settings: + * - if FP is not used, 5th parameter is at 8th position counting + * from SP; + * - if FP is used and FPCCR_S.TS is 0, 5th parameter is at 26th + * position counting from SP; + * - if FP is used and FPCCR_S.TS is 1, 5th parameter is at 42th + * position counting from SP. */ - if (lr & EXC_RETURN_FPU_FRAME_BASIC) { + if (lr & EXC_RETURN_FPU_FRAME_BASIC) { out_num = (size_t)args[8]; - } - else { +#if defined (__FPU_USED) && (__FPU_USED == 1U) + } else if (FPU->FPCCR & FPU_FPCCR_TS_Msk) { + out_num = (size_t)args[42]; +#endif + } else { out_num = (size_t)args[26]; - } + } } else { /* * FixMe: From non-secure caller, vec and len are composed into a new @@ -307,8 +315,8 @@ static psa_signal_t tfm_svcall_psa_wait(uint32_t *args) * 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); + if (timeout == PSA_BLOCK && (partition->signals & signal_mask) == 0) { + tfm_event_wait(&partition->signal_evnt); } return partition->signals & signal_mask; @@ -683,7 +691,7 @@ static void update_caller_outvec_len(struct tfm_msg_body_t *msg) * 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); + TFM_ASSERT(msg->ack_evnt.owner->status == THRD_STAT_BLOCK); while (msg->msg.out_size[i] != 0) { TFM_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base); @@ -800,11 +808,7 @@ static void tfm_svcall_psa_reply(uint32_t *args) 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); + tfm_event_wake(&msg->ack_evnt, ret); /* Message should not be unsed anymore */ tfm_spm_free_msg(msg); @@ -852,11 +856,8 @@ static void tfm_svcall_psa_notify(uint32_t *args) * 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); + tfm_event_wake(&partition->signal_evnt, + partition->signals & partition->signal_mask); } /** 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 index 359aa71db8..cd01259e6e 100644 --- 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 @@ -9,7 +9,7 @@ #include "tfm_arch_v8m.h" #include "tfm_thread.h" #include "tfm_utils.h" -#include "secure_utilities.h" +#include "tfm_memory_utils.h" /* Force ZERO in case ZI(bss) clear is missing */ static struct tfm_thrd_ctx *p_thrd_head = NULL; 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 index 814ec89469..44c801c43a 100644 --- 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 @@ -4,59 +4,27 @@ * 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) +void tfm_event_wait(struct tfm_event_t *pevnt) { - struct tfm_thrd_ctx *curr_thrd = tfm_thrd_curr_thread(); + TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC); - 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; + pevnt->owner = tfm_thrd_curr_thread(); + tfm_thrd_set_status(pevnt->owner, THRD_STAT_BLOCK); + tfm_thrd_activate_schedule(); } -/* Peek the status to see if caller would block. */ -uint32_t tfm_event_peek(struct tfm_event_ctx *pevt) +void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval) { - TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC); + TFM_ASSERT(pevnt && pevnt->magic == TFM_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; + if (pevnt->owner && pevnt->owner->status == THRD_STAT_BLOCK) { + tfm_thrd_set_status(pevnt->owner, THRD_STAT_RUNNING); + tfm_thrd_set_retval(pevnt->owner, retval); 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 index d35cdc7de2..99962d37f3 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -8,9 +8,9 @@ #ifndef __SECURE_UTILITIES_H__ #define __SECURE_UTILITIES_H__ +#include #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) @@ -25,8 +25,6 @@ #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 */ @@ -106,27 +104,4 @@ __STATIC_INLINE void __set_CONTROL_SPSEL(int32_t SPSEL) __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 index cad2b70b89..9d659600d4 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -7,7 +7,7 @@ #include #include "bl2/include/tfm_boot_status.h" -#include "secure_utilities.h" +#include "tfm_memory_utils.h" #include "tfm_internal.h" #include "tfm_api.h" #include "flash_layout.h" @@ -57,13 +57,13 @@ void tfm_core_validate_boot_data(void) 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]; + uint8_t *buf_start = (uint8_t *)args[1]; uint16_t buf_size = (uint16_t)args[2]; - uint8_t *buf_start = ptr; + uint8_t *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; + struct shared_data_tlv_entry tlv_entry; uintptr_t tlv_end, offset; uint32_t res; @@ -71,9 +71,9 @@ void tfm_core_get_boot_data_handler(uint32_t args[]) * by the partition */ res = tfm_core_check_buffer_access(running_partition_idx, - (void*)buf_start, + (void *)buf_start, buf_size, - 2); + 2); /* Check 4 bytes alignment */ if (!res) { /* Not in accessible range, return error */ args[0] = TFM_ERROR_INVALID_PARAMETER; @@ -97,26 +97,31 @@ void tfm_core_get_boot_data_handler(uint32_t args[]) args[0] = TFM_ERROR_INVALID_PARAMETER; return; } else { - tfm_memcpy(ptr, tlv_header, SHARED_DATA_HEADER_SIZE); - ptr += SHARED_DATA_HEADER_SIZE; + tlv_header = (struct shared_data_tlv_header *)buf_start; + tlv_header->tlv_magic = SHARED_DATA_TLV_INFO_MAGIC; + tlv_header->tlv_tot_len = SHARED_DATA_HEADER_SIZE; + ptr = (uint8_t *)tlv_header + 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) { + for (; offset < tlv_end; offset += tlv_entry.tlv_len) { + /* Create local copy to avoid unaligned access */ + tfm_memcpy(&tlv_entry, + (const void *)offset, + SHARED_DATA_ENTRY_HEADER_SIZE); + if (GET_MAJOR(tlv_entry.tlv_type) == tlv_major) { /* Check buffer overflow */ - if ((ptr - buf_start + tlv_entry->tlv_len) > buf_size) { + 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); + tfm_memcpy(ptr, (const void *)offset, tlv_entry.tlv_len); - ptr += tlv_entry->tlv_len; - tlv_header->tlv_tot_len += tlv_entry->tlv_len; + ptr += tlv_entry.tlv_len; + tlv_header->tlv_tot_len += tlv_entry.tlv_len; } } args[0] = TFM_SUCCESS; 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 index db5921061e..7cf65082a9 100644 --- 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 @@ -11,6 +11,7 @@ #include "tfm_internal.h" #include "tfm_api.h" #include "platform/include/tfm_spm_hal.h" +#include "uart_stdout.h" #include "secure_utilities.h" #include "secure_fw/spm/spm_api.h" #include "secure_fw/include/tfm_spm_services_api.h" @@ -87,6 +88,7 @@ int32_t tfm_core_init(void) __enable_irq(); + stdio_init(); LOG_MSG("Secure image initializing!"); #ifdef TFM_CORE_DEBUG 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 index be77fcd3df..f104a1bf22 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -8,7 +8,6 @@ #include #include -#include "cmsis.h" #include "secure_utilities.h" #include "arm_acle.h" #include "tfm_svc.h" @@ -16,6 +15,7 @@ #include "region_defs.h" #include "tfm_api.h" #include "tfm_internal.h" +#include "tfm_memory_utils.h" #ifdef TFM_PSA_API #include #include "tfm_svcalls.h" diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_memory_utils.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_memory_utils.h new file mode 100644 index 0000000000..150e3cc977 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_memory_utils.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_MEMORY_UTILS_H__ +#define __TFM_MEMORY_UTILS_H__ + +#include +#include "cmsis_compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 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, size_t num) +{ + return (memcpy(dest, src, num)); +} + +__attribute__ ((always_inline)) __STATIC_INLINE +int 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)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_MEMORY_UTILS_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 index 36f2c16358..4b35c58e7f 100644 --- 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 @@ -48,8 +48,7 @@ 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; + struct tfm_sfn_req_s desc, *desc_ptr = &desc; int32_t res; desc.sfn = fn; @@ -99,7 +98,7 @@ psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version) __tfm_secure_gateway_attributes__ psa_status_t tfm_psa_call_veneer(psa_handle_t handle, const psa_invec *in_vecs, - psa_outvec *out_vecs) + const psa_invec *out_vecs) { TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_call, handle, in_vecs, out_vecs, 0); 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 index e0663b4adb..0d0f8ff570 100644 --- 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 @@ -8,10 +8,11 @@ #include #include #include -#include "cmsis.h" +#include #include "tfm_secure_api.h" #include "tfm_nspm.h" #include "secure_utilities.h" +#include "uart_stdout.h" #include "secure_fw/spm/spm_api.h" #include "region_defs.h" #include "tfm_api.h" @@ -22,12 +23,15 @@ #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_UNPRIV_SCRATCH, $$ZI$$Base); +REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit); + +#if TFM_LVL == 1 REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base); REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit); #endif @@ -38,6 +42,15 @@ REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit); int32_t tfm_secure_lock; static int32_t tfm_secure_api_initializing = 1; +static int32_t is_iovec_api_call(void) +{ + uint32_t current_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(current_partition_idx); + return curr_part_data->iovec_api; +} + static int32_t *prepare_partition_ctx( struct tfm_exc_stack_t *svc_ctx, struct tfm_sfn_req_s *desc_ptr, @@ -62,6 +75,30 @@ static int32_t *prepare_partition_ctx( return dst; } +static int32_t *prepare_partition_iovec_ctx( + struct tfm_exc_stack_t *svc_ctx, + struct tfm_sfn_req_s *desc_ptr, + struct iovec_args_t *iovec_args, + 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 */ + *(--dst) = iovec_args->out_len; + *(--dst) = (uint32_t)iovec_args->out_vec; + *(--dst) = iovec_args->in_len; + *(--dst) = (uint32_t)iovec_args->in_vec; + + return dst; +} + static void restore_caller_ctx( struct tfm_exc_stack_t *svc_ctx, struct tfm_exc_stack_t *target_ctx) @@ -75,6 +112,241 @@ static void restore_caller_ctx( return; } +/** + * \brief Check whether a memory range is inside a memory region. + * + * \param[in] p The start address of the range to check + * \param[in] s The size of the range to check + * \param[in] region_start The start address of the region, which should + * contain the range + * \param[in] region_len The size of the region, which should contain the + * range + * + * \return 1 if the region contains the range, 0 otherwise. + */ +static int32_t check_address_range(const void *p, size_t s, + uintptr_t region_start, uint32_t region_len) +{ + int32_t range_in_region = 0; + + /* Check for overflow in the range parameters */ + if ((uintptr_t)p > UINTPTR_MAX-s) { + return 0; + } + + /* We trust the region parameters, and don't check for overflow */ + + /* Calculate the result */ + range_in_region = ((uintptr_t)p >= region_start) && + ((uintptr_t)p+s <= region_start+region_len); + + return range_in_region; +} + +/** + * \brief Check whether the current partition has access to a memory range + * + * This function assumes, that the current MPU configuration is set for the + * partition to be checked. The flags should contain information of the + * execution mode of the partition code (priv/unpriv), and access type + * (read/write) as specified in "ARMv8-M Security Extensions: Requirements on + * Development Tools" chapter "Address range check intrinsic" + * + * \param[in] p The start address of the range to check + * \param[in] s The size of the range to check + * \param[in] flags The flags to pass to the cmse_check_address_range func + * + * \return 1 if the partition has access to the memory range, 0 otherwise. + */ +static int32_t has_access_to_region(const void *p, size_t s, uint32_t flags) +{ + int32_t range_access_allowed_by_mpu; + + uint32_t scratch_base = + (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base); + uint32_t scratch_limit = + (uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit); + + /* Use the TT instruction to check access to the partition's regions*/ + range_access_allowed_by_mpu = + cmse_check_address_range((void *)p, s, flags) != NULL; + + if (range_access_allowed_by_mpu) { + return 1; + } + + /* If the check for the current MPU settings fails, check for the share + * region, only if the partition is secure + */ + if ((flags & CMSE_NONSECURE) == 0) { + if (check_address_range(p, s, scratch_base, + scratch_limit+1-scratch_base)) { + return 1; + } + } + + /* If all else fails, check whether the region is in the non-secure + * memory + */ + return + check_address_range(p, s, NS_CODE_START, NS_CODE_LIMIT+1-NS_CODE_START) || + check_address_range(p, s, NS_DATA_START, NS_DATA_LIMIT+1-NS_DATA_START); +} + +/** + * \brief Check whether the current partition has read access to a memory range + * + * This function assumes, that the current MPU configuration is set for the + * partition to be checked. + * + * \param[in] p The start address of the range to check + * \param[in] s The size of the range to check + * \param[in] ns_caller Whether the current partition is a non-secure one + * + * \return 1 if the partition has access to the memory range, 0 otherwise. + */ +static int32_t has_read_access_to_region(const void *p, size_t s, + int32_t ns_caller) +{ + uint32_t flags = CMSE_MPU_UNPRIV|CMSE_MPU_READ; + + if (ns_caller) { + flags |= CMSE_NONSECURE; + } + + return has_access_to_region(p, s, flags); +} + +/** + * \brief Check whether the current partition has write access to a memory range + * + * This function assumes, that the current MPU configuration is set for the + * partition to be checked. + * + * \param[in] p The start address of the range to check + * \param[in] s The size of the range to check + * \param[in] ns_caller Whether the current partition is a non-secure one + * + * \return 1 if the partition has access to the memory range, 0 otherwise. + */ +static int32_t has_write_access_to_region(void *p, size_t s, int32_t ns_caller) +{ + uint32_t flags = CMSE_MPU_UNPRIV|CMSE_MPU_READWRITE; + + if (ns_caller) { + flags |= CMSE_NONSECURE; + } + + return has_access_to_region(p, s, flags); +} + +/** \brief Check whether the iovec parameters are valid, and the memory ranges + * are in the posession of the calling partition + * + * \param[in] desc_ptr The secure function request descriptor + * + * \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code + * otherwise as in /ref tfm_status_e + */ +static int32_t tfm_core_check_sfn_parameters(struct tfm_sfn_req_s *desc_ptr) +{ + struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0]; + size_t in_len = desc_ptr->args[1]; + struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2]; + size_t out_len = desc_ptr->args[3]; + + uint32_t i; + + /* The number of vectors are within range. Extra checks to avoid overflow */ + if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) || + (in_len + out_len > PSA_MAX_IOVEC)) { + return TFM_ERROR_INVALID_PARAMETER; + } + + /* Check whether the caller partition has at write access to the iovec + * structures themselves. Use the TT instruction for this. + */ + if (in_len > 0) { + if ((in_vec == NULL) || + (has_write_access_to_region(in_vec, sizeof(psa_invec)*in_len, + desc_ptr->ns_caller) != 1)) { + return TFM_ERROR_INVALID_PARAMETER; + } + } else { + if (in_vec != NULL) { + return TFM_ERROR_INVALID_PARAMETER; + } + } + if (out_len > 0) { + if ((out_vec == NULL) || + (has_write_access_to_region(out_vec, sizeof(psa_outvec)*out_len, + desc_ptr->ns_caller) != 1)) { + return TFM_ERROR_INVALID_PARAMETER; + } + } else { + if (out_vec != NULL) { + return TFM_ERROR_INVALID_PARAMETER; + } + } + + /* Check whether the caller partition has access to the data inside the + * iovecs + */ + for (i = 0; i < in_len; ++i) { + if (in_vec[i].len > 0) { + if ((in_vec[i].base == NULL) || + (has_read_access_to_region(in_vec[i].base, in_vec[i].len, + desc_ptr->ns_caller) != 1)) { + return TFM_ERROR_INVALID_PARAMETER; + } + } + } + for (i = 0; i < out_len; ++i) { + if (out_vec[i].len > 0) { + if ((out_vec[i].base == NULL) || + (has_write_access_to_region(out_vec[i].base, out_vec[i].len, + desc_ptr->ns_caller) != 1)) { + return TFM_ERROR_INVALID_PARAMETER; + } + } + } + + return TFM_SUCCESS; +} + +static void tfm_copy_iovec_parameters(struct iovec_args_t *target, + const struct iovec_args_t *source) +{ + int i; + + target->in_len = source->in_len; + for (i = 0; i < source->in_len; ++i) { + target->in_vec[i].base = source->in_vec[i].base; + target->in_vec[i].len = source->in_vec[i].len; + } + target->out_len = source->out_len; + for (i = 0; i < source->out_len; ++i) { + target->out_vec[i].base = source->out_vec[i].base; + target->out_vec[i].len = source->out_vec[i].len; + } +} + +static void tfm_clear_iovec_parameters(struct iovec_args_t *args) +{ + int i; + + args->in_len = 0; + for (i = 0; i < PSA_MAX_IOVEC; ++i) { + args->in_vec[i].base = NULL; + args->in_vec[i].len = 0; + } + args->out_len = 0; + for (i = 0; i < PSA_MAX_IOVEC; ++i) { + args->out_vec[i].base = NULL; + args->out_vec[i].len = 0; + } +} + static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr, uint32_t excReturn) { @@ -89,6 +361,7 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr, struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp; uint32_t caller_partition_id; int32_t client_id; + struct iovec_args_t *iovec_args; caller_flags = tfm_spm_partition_get_flags(caller_partition_idx); @@ -145,8 +418,13 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr, #if TFM_LVL == 1 /* Prepare switch to shared secure partition stack */ + /* In case the call is coming from the non-secure world, we save the iovecs + * on the stop of the stack. So the memory area, that can actually be used + * as stack by the partitions starts at a lower address + */ partition_psp = - (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit); + (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- + sizeof(struct iovec_args_t); partition_psplim = (uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base); #else @@ -193,16 +471,53 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr, * 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); + if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { + /* Save the iovecs on the common stack. The vectors had been sanity + * checked already, and since then the interrupts have been kept + * disabled. So we can be sure that the vectors haven't been + * tampered with since the check. + */ + iovec_args = (struct iovec_args_t *) + ((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- + sizeof(struct iovec_args_t)); + tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args); + tfm_copy_iovec_parameters(iovec_args, + &(curr_part_data->iovec_args)); + + /* Prepare the partition context, update stack ptr */ + psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr, + iovec_args, + (int32_t *)partition_psp); + } 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); } #else - /* Prepare the partition context, update stack ptr */ - psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr, - (int32_t *)partition_psp); + if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { + /* Save the iovecs on the stack of the partition. The vectors had been + * sanity checked already, and since then the interrupts have been kept + * disabled. So we can be sure that the vectors haven't been tampered + * with since the check. + */ + iovec_args = + (struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) - + sizeof(struct iovec_args_t)); + tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args); + tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args)); + + /* Prepare the partition context, update stack ptr */ + psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr, + iovec_args, + (int32_t *)partition_psp); + } 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 @@ -224,7 +539,9 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn) uint32_t return_partition_idx; uint32_t return_partition_flags; uint32_t psp = __get_PSP(); + int i; struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp; + struct iovec_args_t *iovec_args; if (current_partition_idx == SPM_INVALID_PARTITION_IDX) { return TFM_SECURE_UNLOCK_FAILED; @@ -304,6 +621,18 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn) uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base; __set_PSPLIM(psp_stack_bottom); + /* FIXME: The condition should be removed once all the secure service + * calls are done via the iovec veneers */ + if (curr_part_data->iovec_api) { + iovec_args = (struct iovec_args_t *) + ((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)- + sizeof(struct iovec_args_t)); + + for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) { + curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len; + } + tfm_clear_iovec_parameters(iovec_args); + } } #else /* Restore caller context */ @@ -314,7 +643,20 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn) __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)); + current_partition_idx, psp + sizeof(struct tfm_exc_stack_t)); + + /* FIXME: The condition should be removed once all the secure service + * calls are done via the iovec veneers */ + if (curr_part_data->iovec_api) { + iovec_args = (struct iovec_args_t *) + (tfm_spm_partition_get_stack_top(current_partition_idx) - + sizeof(struct iovec_args_t)); + + for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) { + curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len; + } + tfm_clear_iovec_parameters(iovec_args); + } #endif tfm_spm_partition_cleanup_context(current_partition_idx); @@ -396,12 +738,22 @@ int32_t tfm_core_sfn_request_handler( res = tfm_check_sfn_req_integrity(desc_ptr); if (res != TFM_SUCCESS) { ERROR_MSG("Invalid service request!"); - return TFM_ERROR_STATUS(res); + tfm_secure_api_error_handler(); } __disable_irq(); + desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx(); + if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { + res = tfm_core_check_sfn_parameters(desc_ptr); + if (res != TFM_SUCCESS) { + /* The sanity check of iovecs failed. */ + __enable_irq(); + tfm_secure_api_error_handler(); + } + } + res = tfm_core_check_sfn_req_rules(desc_ptr); if (res != TFM_SUCCESS) { /* FixMe: error compartmentalization TBD */ @@ -409,7 +761,7 @@ int32_t tfm_core_sfn_request_handler( desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED); __enable_irq(); ERROR_MSG("Unauthorized service request!"); - return TFM_ERROR_STATUS(res); + tfm_secure_api_error_handler(); } res = tfm_start_partition(desc_ptr, excReturn); @@ -417,7 +769,7 @@ int32_t tfm_core_sfn_request_handler( /* FixMe: consider possible fault scenarios */ __enable_irq(); ERROR_MSG("Failed to process service request!"); - return TFM_ERROR_STATUS(res); + tfm_secure_api_error_handler(); } __enable_irq(); @@ -432,6 +784,14 @@ int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr) int32_t *args; int32_t retVal; + if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) { + res = tfm_core_check_sfn_parameters(desc_ptr); + if (res != TFM_SUCCESS) { + /* The sanity check of iovecs failed. */ + return res; + } + } + /* No excReturn value is needed as no exception handling is used */ res = tfm_core_sfn_request_handler(desc_ptr, 0); @@ -689,6 +1049,8 @@ void tfm_core_memory_permission_check_handler(uint32_t *svc_args) uint32_t tfm_core_partition_request_svc_handler( struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn) { + struct tfm_sfn_req_s *desc_ptr; + if (!(excReturn & EXC_RETURN_STACK_PROCESS)) { /* Service request SVC called with MSP active. * Either invalid configuration for Thread mode or SVC called @@ -699,7 +1061,7 @@ uint32_t tfm_core_partition_request_svc_handler( tfm_secure_api_error_handler(); } - struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0; + 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(); @@ -724,17 +1086,19 @@ uint32_t tfm_core_partition_return_handler(uint32_t lr) /* 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 */ + if (!is_iovec_api_call()) { + 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!"); + 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(); + /* 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); 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 index 2f253e1ae6..8ab85facdb 100644 --- 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 @@ -29,6 +29,9 @@ #define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY) #endif +#define TFM_SFN_API_LEGACY 0 +#define TFM_SFN_API_IOVEC 1 + #ifndef TFM_LVL #error TFM_LVL is not defined! #endif @@ -42,6 +45,7 @@ struct tfm_sfn_req_s { sfn_t sfn; int32_t *args; uint32_t caller_part_idx; + int32_t iovec_api; int32_t ns_caller : 1; }; @@ -73,8 +77,9 @@ 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_memory_permission_check(const 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); @@ -83,12 +88,16 @@ 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_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \ + return tfm_core_partition_request(id, fn, TFM_SFN_API_IOVEC, \ + (int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d) + #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) + return tfm_core_partition_request(id, fn, TFM_SFN_API_LEGACY, \ + (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 tfm_core_partition_request(uint32_t id, void *fn, int32_t iovec_api, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4) { int32_t args[4] = {arg1, arg2, arg3, arg4}; @@ -98,6 +107,7 @@ int32_t tfm_core_partition_request(uint32_t id, void *fn, desc.sfn = fn; desc.args = args; desc.ns_caller = cmse_nonsecure_caller(); + desc.iovec_api = iovec_api; if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) { /* FixMe: Error severity TBD */ return TFM_ERROR_GENERIC; 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 index 9052ef7369..2714851424 100644 --- 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 @@ -100,8 +100,9 @@ __attribute__((naked)) int32_t tfm_core_sfn_request( #endif __attribute__((naked)) -int32_t tfm_core_memory_permission_check( - void *ptr, uint32_t len, int32_t access) +int32_t tfm_core_memory_permission_check(const void *ptr, + uint32_t len, + int32_t access) { __ASM( "SVC %0\n" diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/dir_include.dox b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/dir_include.dox new file mode 100644 index 0000000000..10d074ff22 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/include/dir_include.dox @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +//This file holds description for the current directory. This documentation +//will be included in the Doxygen output. + +/*! +\dir +\brief Include files for the TF-M. +\details This directory currently only holds the include file for the SPM +module. + +*/ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/CMakeLists.inc b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/CMakeLists.inc new file mode 100644 index 0000000000..d1e57d888f --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/CMakeLists.inc @@ -0,0 +1,61 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2017-2018, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- + +#Definitions to compile the "spm" module. +#This file assumes it will be included from a project specific cmakefile, and +#will not create a library or executable. +#Inputs: +# TFM_ROOT_DIR - root directory of the TF-M repository. +# +#Outputs: +# Will modify include directories to make the source compile. +# ALL_SRC_C: C source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command. +# ALL_SRC_CXX: C++ source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command. +# ALL_SRC_ASM: assembly source files to be compiled will be added to this list. This shall be added to your add_executable or add_library command. +# Include directories will be modified by using the include_directories() commands as needed. + +#Get the current directory where this file is located. +set(SS_SPM_DIR ${CMAKE_CURRENT_LIST_DIR}) +if(NOT DEFINED TFM_ROOT_DIR) + message(FATAL_ERROR "Please set TFM_ROOT_DIR before including this file.") +endif() + +set (SS_SPM_C_SRC "${SS_SPM_DIR}/spm_api.c") + + +#Append all our source files to global lists. +list(APPEND ALL_SRC_C ${SS_SPM_C_SRC}) +unset(SS_SPM_C_SRC) + +#Setting include directories +embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/spm ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR}/secure_fw/core ABSOLUTE) +embedded_include_directories(PATH ${TFM_ROOT_DIR} ABSOLUTE) + +set(BUILD_CMSIS_CORE Off) +set(BUILD_RETARGET Off) +set(BUILD_NATIVE_DRIVERS Off) +set(BUILD_STARTUP Off) +set(BUILD_TARGET_CFG Off) +set(BUILD_TARGET_HARDWARE_KEYS Off) +set(BUILD_TARGET_NV_COUNTERS Off) +set(BUILD_CMSIS_DRIVERS Off) +set(BUILD_TIME Off) +set(BUILD_UART_STDOUT Off) +set(BUILD_FLASH Off) +set(BUILD_BOOT_SEED Off) +set(BUILD_DEVICE_ID Off) +if(NOT DEFINED PLATFORM_CMAKE_FILE) + message (FATAL_ERROR "Platform specific CMake is not defined. Please set PLATFORM_CMAKE_FILE.") +elseif(NOT EXISTS ${PLATFORM_CMAKE_FILE}) + message (FATAL_ERROR "Platform specific CMake \"${PLATFORM_CMAKE_FILE}\" file does not exist. Please fix value of PLATFORM_CMAKE_FILE.") +else() + include(${PLATFORM_CMAKE_FILE}) +endif() + diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/dir_spm.dox b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/dir_spm.dox new file mode 100644 index 0000000000..92c8a272e7 --- /dev/null +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/dir_spm.dox @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +//This file holds description for the current directory. This documentation +//will be included in the Doxygen output. + +/*! +\dir +\brief Source code for the Secure Partition Manager. +\details This directory holds the source code of the "TF-M SPM" module. + +*/ \ No newline at end of file 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 index ee2ff584f8..e08230abd8 100644 --- 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 @@ -11,13 +11,12 @@ #include #include "spm_api.h" #include "platform/include/tfm_spm_hal.h" -#include "secure_utilities.h" +#include "tfm_memory_utils.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" @@ -123,7 +122,7 @@ enum spm_err_t tfm_spm_db_init(void) ++g_spm_partition_db.partition_count; /* Add user-defined secure partitions */ - #include "tfm_partition_list.inc" + #include "secure_fw/services/tfm_partition_list.inc" g_spm_partition_db.is_init = 1; @@ -156,6 +155,7 @@ enum spm_err_t tfm_spm_partition_init(void) desc.args = args; desc.ns_caller = 0; + desc.iovec_api = TFM_SFN_API_IOVEC; desc.sfn = (sfn_t)part->static_data.partition_init; desc.sp_id = part->static_data.partition_id; res = tfm_core_sfn_request(&desc); @@ -314,6 +314,29 @@ enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx, return ret; } +void tfm_spm_partition_set_iovec(uint32_t partition_idx, int32_t *args) +{ + struct spm_partition_runtime_data_t *runtime_data = + &g_spm_partition_db.partitions[partition_idx].runtime_data; + int32_t i; + + runtime_data->iovec_args.in_len = args[1]; + for (i = 0; i < runtime_data->iovec_args.in_len; ++i) { + runtime_data->iovec_args.in_vec[i].base = + ((psa_invec *)args[0])[i].base; + runtime_data->iovec_args.in_vec[i].len = ((psa_invec *)args[0])[i].len; + } + runtime_data->iovec_args.out_len = args[3]; + for (i = 0; i < runtime_data->iovec_args.out_len; ++i) { + runtime_data->iovec_args.out_vec[i].base = + ((psa_outvec *)args[2])[i].base; + runtime_data->iovec_args.out_vec[i].len = + ((psa_outvec *)args[2])[i].len; + } + runtime_data->orig_outvec = (psa_outvec *)args[2]; + runtime_data->iovec_api = 1; +} + uint32_t tfm_spm_partition_get_running_partition_idx(void) { return g_spm_partition_db.running_partition_idx; @@ -323,6 +346,20 @@ void tfm_spm_partition_cleanup_context(uint32_t partition_idx) { struct spm_partition_desc_t *partition = &(g_spm_partition_db.partitions[partition_idx]); + int32_t i; + partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX; partition->runtime_data.share = 0; + partition->runtime_data.iovec_args.in_len = 0; + for (i = 0; i < PSA_MAX_IOVEC; ++i) { + partition->runtime_data.iovec_args.in_vec[i].base = 0; + partition->runtime_data.iovec_args.in_vec[i].len = 0; + } + partition->runtime_data.iovec_args.out_len = 0; + for (i = 0; i < PSA_MAX_IOVEC; ++i) { + partition->runtime_data.iovec_args.out_vec[i].base = 0; + partition->runtime_data.iovec_args.out_vec[i].len = 0; + } + partition->runtime_data.orig_outvec = 0; + partition->runtime_data.iovec_api = 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 index c3f7414d4a..89d4564e16 100644 --- 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 @@ -9,6 +9,7 @@ #define __SPM_API_H__ /* This file contains the apis exported by the SPM to tfm core */ +#include "tfm_api.h" #include "spm_partition_defs.h" #include "secure_fw/core/tfm_secure_api.h" @@ -37,6 +38,20 @@ enum spm_part_flag_mask_t { SPM_PART_FLAG_IPC = 0x04 }; +/** + * \brief Holds the iovec parameters that are passed to a service + * + * \note The size of the structure is (and have to be) multiple of 8 bytes + */ +struct iovec_args_t { + psa_invec in_vec[PSA_MAX_IOVEC]; /*!< Array of psa_invec objects */ + size_t in_len; /*!< Number psa_invec objects in in_vec + */ + psa_outvec out_vec[PSA_MAX_IOVEC]; /*!< Array of psa_outvec objects */ + size_t out_len; /*!< Number psa_outvec objects in out_vec + */ +}; + /** * \brief Runtime context information of a partition */ @@ -47,6 +62,13 @@ struct spm_partition_runtime_data_t { uint32_t share; uint32_t stack_ptr; uint32_t lr; + int32_t iovec_api; /*!< Whether the function in the partition + * had been called using the iovec API. + * FIXME: Remove the field once this is the + * only option + */ + struct iovec_args_t iovec_args; + psa_outvec *orig_outvec; }; @@ -60,6 +82,7 @@ struct spm_partition_runtime_data_t { */ uint32_t get_partition_idx(uint32_t partition_id); +#if TFM_LVL != 1 /** * \brief Configure isolated sandbox for a partition * @@ -104,28 +127,6 @@ uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx); */ 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 * @@ -172,6 +173,28 @@ uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx); */ uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx); +/** + * \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_idx, uint32_t stack_ptr); +#endif + +/** + * \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 current runtime data of a partition * @@ -192,16 +215,6 @@ const struct spm_partition_runtime_data_t * */ 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 * @@ -214,6 +227,17 @@ void tfm_spm_partition_set_stack(uint32_t partition_id, uint32_t stack_ptr); void tfm_spm_partition_store_context(uint32_t partition_idx, uint32_t stack_ptr, uint32_t lr); +/** + * \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 Set the current state of a partition * @@ -221,7 +245,7 @@ void tfm_spm_partition_store_context(uint32_t partition_idx, * \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. + * \note The 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); @@ -261,6 +285,24 @@ void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx, enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx, uint32_t share); +/** + * \brief Set the iovec parameters for the partition + * + * \param[in] partition_idx Partition index + * \param[in] args The arguments of the secure function + * + * args is expected to be of type int32_t[4] where: + * args[0] is in_vec + * args[1] is in_len + * args[2] is out_vec + * args[3] is out_len + * + * \note This function doesn't check if partition_idx is valid. + * \note This function assumes that the iovecs that are passed in args are + * valid, and does no sanity check on them at all. + */ +void tfm_spm_partition_set_iovec(uint32_t partition_idx, int32_t *args); + /** * \brief Initialize partition database * 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 index 60b5fbd456..6b28f94159 100644 --- 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 @@ -8,6 +8,7 @@ #ifndef __SPM_DB_H__ #define __SPM_DB_H__ + #ifdef TFM_PSA_API #include "tfm_thread.h" #endif @@ -15,9 +16,7 @@ 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); +typedef psa_status_t(*sp_init_function)(void); #define TFM_PARTITION_TYPE_APP "APPLICATION-ROT" #define TFM_PARTITION_TYPE_PSA "PSA-ROT" @@ -66,10 +65,11 @@ struct spm_partition_desc_t { #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. + * FixMe: Hard code stack is not aligned with the definition in the + * manifest. It will use the partition stacks in the linker scripts/sct + * files include Level 1 to 3. */ - uint32_t stack_limit; - uint32_t stack_size; + uint8_t stack[TFM_STACK_SIZE] __attribute__((aligned(8))); #endif }; 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 index a15e7b7cb1..d79fed9ce6 100644 --- 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 @@ -17,10 +17,10 @@ * 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 + * \param[in] partition_idx The index of the partition * - * \return \ref INVALID_PARTITION_IDX if the provided ID is invalid. The index - * of the partition otherwise. + * \return \ref INVALID_PARTITION_IDX if the provided index is invalid. The + * index of the partition otherwise. */ uint32_t get_partition_idx(uint32_t partition_id); @@ -66,12 +66,17 @@ struct spm_partition_db_t { #define PARTITION_INIT_RUNTIME_DATA(data, partition) \ do { \ data.partition_state = SPM_PARTITION_STATE_UNINIT; \ + /* The top of the stack is reserved for the iovec */ \ + /* parameters of the service called. That's why in */ \ + /* data.stack_ptr we extract sizeof(struct iovec_args_t) */ \ + /* from the limit. */ \ data.stack_ptr = \ - PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \ + PART_REGION_ADDR(partition, _STACK$$ZI$$Limit - \ + sizeof(struct iovec_args_t)); \ } while (0) #endif -#define PARTITION_DECLARE(partition, flag, type, id, priority, part_stack_size) \ +#define PARTITION_DECLARE(partition, flag, type, id, priority) \ do { \ REGION_DECLARE(Image$$, partition, $$Base); \ REGION_DECLARE(Image$$, partition, $$Limit); \ @@ -97,12 +102,8 @@ struct spm_partition_db_t { 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); \ 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 index 0533881f87..85ab1eca6e 100644 --- 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 @@ -29,7 +29,7 @@ */ #define TFM_SP_CORE_ID (1) -#include "tfm_partition_defs.inc" +#include "secure_fw/services/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 diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h index 70534741a8..71adb802e3 100644 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_client.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited. All rights reserved. + * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h index 753fab76c5..6453aede8b 100644 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/psa_service.h @@ -223,8 +223,6 @@ 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. diff --git a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h index 79a94cbdd0..2ba93c0916 100644 --- a/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h +++ b/components/TARGET_PSA/TARGET_TFM/interface/include/tfm_api.h @@ -13,7 +13,7 @@ extern "C" { #endif #include -#include "interface/include/psa_client.h" +#include "psa_client.h" #define TFM_INVALID_CLIENT_ID 0 @@ -35,13 +35,18 @@ extern "C" { */ #define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0) +/* Maximum number of input and output vectors */ +#define PSA_MAX_IOVEC (4) + /* FixMe: sort out DEBUG compile option and limit return value options * on external interfaces */ -/* Note: +/* For secure functions using prorietary signatures * 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. + * For secure functions using the veneers in secure_fw/ns_callable/tfm_veneers.c + * (iovec API) this limitation does not apply. */ enum tfm_status_e { @@ -105,13 +110,13 @@ psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version); * * \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 + * \param[in] out_vecs invec 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); + const psa_invec *out_vecs); /** * \brief Close connection to secure function referenced by a connection handle