diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c index 76b284effff..feece0be330 100644 --- a/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c +++ b/components/TARGET_PSA/TARGET_TFM/COMPONENT_NSPE/interface/src/tfm_ns_lock_rtx.c @@ -1,16 +1,14 @@ /* - * Copyright (c) 2017-2018, Arm Limited. All rights reserved. + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include - #include "cmsis.h" #include "rtx_os.h" #include "cmsis_os2.h" - #include "tfm_api.h" #include "tfm_ns_lock.h" 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 deleted file mode 100644 index ab71a486290..00000000000 --- a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/boot_record.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef __BOOT_RECORD_H__ -#define __BOOT_RECORD_H__ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/*! - * \enum shared_data_err_t - * - * \brief Return values for adding data entry to shared memory area - */ -enum shared_memory_err_t { - SHARED_MEMORY_OK = 0, - SHARED_MEMORY_OVERFLOW = 1, - SHARED_MEMORY_OVERWRITE = 2, - - /* This is used to force the maximum size */ - TLV_TYPE_MAX = INT_MAX -}; - -/*! - * \brief Add a data item to the shared data area between bootloader and - * runtime SW - * - * \param[in] major_type TLV major type, identify consumer - * \param[in] minor_type TLV minor type, identify TLV type - * \param[in] size length of added data - * \param[in] data pointer to data - * - * \return Returns error code as specified in \ref shared_memory_err_t - */ -enum shared_memory_err_t -boot_add_data_to_shared_area(uint8_t major_type, - uint8_t minor_type, - size_t size, - const uint8_t *data); - -#ifdef __cplusplus -} -#endif - -#endif /* __BOOT_RECORD_H__ */ diff --git a/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/tfm_boot_status.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/bl2/include/tfm_boot_status.h index 30a7b1c2ccc..dbcc6ced470 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 - -/* PSA Root of Trust */ -#define TLV_MINOR_IAS_PRoT_SHA256 0x00 -#define TLV_MINOR_IAS_PRoT_SW_VERSION 0x01 -#define TLV_MINOR_IAS_PRoT_EPOCH 0x02 - -/* Application Root of Trust */ -#define TLV_MINOR_IAS_ARoT_SHA256 0x03 -#define TLV_MINOR_IAS_ARoT_SW_VERSION 0x04 -#define TLV_MINOR_IAS_ARoT_EPOCH 0x05 - -/* Non-secure processing environment: single non-secure image */ -#define TLV_MINOR_IAS_NSPE_SHA256 0x06 -#define TLV_MINOR_IAS_NSPE_SW_VERSION 0x07 -#define TLV_MINOR_IAS_NSPE_EPOCH 0x08 - -/* ARoT + PRoT: single secure image */ -#define TLV_MINOR_IAS_S_SHA256 0x09 -#define TLV_MINOR_IAS_S_SW_VERSION 0x0a -#define TLV_MINOR_IAS_S_EPOCH 0x0b +/* Major numbers (4 bit) to identify + * the consumer of shared data in runtime SW + */ +#define TLV_MAJOR_CORE 0x0 +#define TLV_MAJOR_IAS 0x1 -/* 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 +/** + * 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 | + * |---------------------------------------| + */ +/* 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 + +/* 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 + +/* 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 + +/* 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/dir_core.dox b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/dir_core.dox new file mode 100644 index 00000000000..a8da84823bb --- /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/include/tfm_message_queue.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_message_queue.h index 31bcda94823..44f5af44bf5 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 @@ -16,7 +16,7 @@ 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 0fd3a8f8004..b089d008e99 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 @@ -59,7 +59,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_svcalls.h b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/ipc/include/tfm_svcalls.h index fdbc4a9ce4a..97c506be14a 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 2bed0aec3d2..0bb6ea38e90 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. - * - * Parameters : - * pevt - pointer of event context - * - * Notes : - * Thread is blocked if event is not signaled. - */ -void tfm_event_wait(struct tfm_event_ctx *pevt); - -/* - * Signal an event. - * - * Parameters : - * pevt - pointer of event context - * - * Notes : - * Waiting thread on this event will be running. - */ -void tfm_event_signal(struct tfm_event_ctx *pevt); - -/* - * Peek an event status. - * - * Parameters : - * pevt - pointer of event context + * Wait on an event object. * - * Return : - * Status of event. + * Parameters: + * pevnt - The pointer of event object allocated by the caller * - * Notes : - * This function is used for getting event status without blocking thread. + * Notes: + * Block caller thread by calling this function. */ -uint32_t tfm_event_peek(struct tfm_event_ctx *pevt); +void tfm_event_wait(struct tfm_event_t *pevnt); /* - * Set event owner return value. + * Wake up an event object. * * Parameters : - * pevt - pointer of event context - * retval - return value of blocked owner thread + * pevnt - The pointer of event object allocated by the caller + * retval - Value to be returned to owner * - * Notes : - * Thread return value is set while thread is to be running. + * Notes: + * Wake up the blocked thread and set parameter 'retval' as the return value. */ -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 5c50636896e..bbf597a56e1 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 a5e7b2a65be..83342b88bb6 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 9fd056e19a7..d80c18348ca 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. @@ -348,7 +349,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 +406,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; } @@ -598,7 +595,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 a3fab65feaf..5483ba3d430 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 359aa71db83..cd01259e6e0 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 814ec89469c..44c801c43a5 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 d35cdc7de27..8c96de8f3dc 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) @@ -106,27 +106,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 cad2b70b898..9d659600d47 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_handler.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_handler.c index be77fcd3df9..f104a1bf226 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 00000000000..150e3cc977b --- /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_secure_api.c b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/core/tfm_secure_api.c index e0663b4adb2..0b11881bb77 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,7 +8,7 @@ #include #include #include -#include "cmsis.h" +#include #include "tfm_secure_api.h" #include "tfm_nspm.h" #include "secure_utilities.h" @@ -22,12 +22,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 +41,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 +74,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 +111,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 +360,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 +417,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 +470,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 +538,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 +620,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 +642,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 +737,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 +760,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 +768,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 +783,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 +1048,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 +1060,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 +1085,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 2f253e1ae67..8ab85facdb6 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 9052ef7369f..2714851424b 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 00000000000..10d074ff22b --- /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/dir_spm.dox b/components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/secure_fw/spm/dir_spm.dox new file mode 100644 index 00000000000..92c8a272e7e --- /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 ee2ff584f84..ff994d8babe 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" @@ -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 c3f7414d4aa..89d4564e16f 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 * @@ -193,26 +216,27 @@ 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 + * \brief Save stack pointer and link register for partition in database * * \param[in] partition_idx Partition index * \param[in] stack_ptr Stack pointer to be stored + * \param[in] lr Link register to be stored * * \note This function doesn't check if partition_idx is valid. */ -void tfm_spm_partition_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 Save stack pointer and link register for partition in database + * \brief Get the id of the partition for its index from the db * - * \param[in] partition_idx Partition index - * \param[in] stack_ptr Stack pointer to be stored - * \param[in] lr Link register to be stored + * \param[in] partition_idx Partition index + * + * \return Partition ID for that partition * * \note This function doesn't check if partition_idx is valid. */ -void tfm_spm_partition_store_context(uint32_t partition_idx, - uint32_t stack_ptr, uint32_t lr); +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 60b5fbd4569..8247424eda2 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" 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 a15e7b7cb14..7ffc651f89d 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,8 +66,13 @@ 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 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 70534741a8a..71adb802e39 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 753fab76c55..6453aede8ba 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 79a94cbdd06..d6ce6893a07 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 { diff --git a/tools/importer/tfm_importer.json b/tools/importer/tfm_importer.json index 04ef5666de9..4b8d92dd3e1 100644 --- a/tools/importer/tfm_importer.json +++ b/tools/importer/tfm_importer.json @@ -64,14 +64,12 @@ } ], "commit_sha" : [ - "71cd34df3265d98da5c9b34e4e18ef039d7bef5c", - "87f22efcb5ed28fc4dbe6c940057bc6ace3ec00a", - "03dbd4bb28113c6ffc05e6884b6b38f52163cb4b", - "ea8bff57b14dad0b8d7e09c698ed1a08c532f04b", - "8a087a6504a0e2d7e3e48adc6301f16e44ea5957", - "749faa6534be5b3067be4c1bcca12681f9587c0e", - "7a2c7d7df4d12776689b10e5fa77963f8473193f", - "134a169e35154e1faaba9876da1e49972b5312eb" + "185d2865da45cc2c6ac3acb755b90c196934d7d5", + "e89c1a68ce8f690ce0d6029cd9196b03906060de", + "3fbc73e046e59e45b58ea2935c5d2fe5e89e67d8", + "f0e4583b72c887c87bd06797d1dc815f4f9e3300", + "ad8ddd8e6e4f8cb378e16617931cfd80515fb51f", + "3badc126cf4c3b6ff224d57cb469f9be546b30e2", + "5a9dff2e04c3471caafb94962fe6fc1357305c1a" ] } -