Remove imported TF-M SPM related files

These changes are the first step towards switching to TF-M SPM and
services which will be running on the secure side and mbed-os
will be running on the non-secure side.

Signed-off-by: Devaraj Ranganna <devaraj.ranganna@arm.com>
pull/12402/head
Devaraj Ranganna 2019-10-01 13:53:25 +01:00 committed by Jaeden Amero
parent 5624ad123a
commit da5b641ed7
59 changed files with 0 additions and 7950 deletions

View File

@ -1,91 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "cmsis.h"
#include "rtx_os.h"
#include "cmsis_os2.h"
#include "tfm_api.h"
#include "tfm_ns_lock.h"
/**
* \brief struct ns_lock_state type
*/
struct ns_lock_state
{
bool init;
osMutexId_t id;
};
/**
* \brief ns_lock status
*/
static struct ns_lock_state ns_lock = {.init=false, .id=NULL};
/**
* \brief Mutex properties, NS lock
*/
static osRtxMutex_t ns_lock_cb = { 0 };
static const osMutexAttr_t ns_lock_attrib = {
.name = "ns_lock",
.attr_bits = osMutexPrioInherit,
.cb_mem = &ns_lock_cb,
.cb_size = sizeof(ns_lock_cb)
};
/**
* \brief NS world, NS lock based dispatcher
*/
__attribute__((weak))
uint32_t tfm_ns_lock_dispatch(veneer_fn fn,
uint32_t arg0, uint32_t arg1,
uint32_t arg2, uint32_t arg3)
{
uint32_t result;
/* Check the NS lock has been initialized */
if (ns_lock.init == false) {
return TFM_ERROR_GENERIC;
}
/* TFM request protected by NS lock */
if (osMutexAcquire(ns_lock.id,osWaitForever) != osOK) {
return TFM_ERROR_GENERIC;
}
result = fn(arg0, arg1, arg2, arg3);
if (osMutexRelease(ns_lock.id) != osOK) {
return TFM_ERROR_GENERIC;
}
return result;
}
/**
* \brief NS world, Init NS lock
*/
__attribute__((weak))
enum tfm_status_e tfm_ns_lock_init()
{
if (ns_lock.init == false) {
ns_lock.id = osMutexNew(&ns_lock_attrib);
ns_lock.init = true;
return TFM_SUCCESS;
}
else {
return TFM_ERROR_GENERIC;
}
}
bool tfm_ns_lock_get_init_state()
{
return ns_lock.init;
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "interface/include/psa_client.h"
#include "tfm_ns_lock.h"
#include "tfm_api.h"
/**** API functions ****/
uint32_t psa_framework_version(void)
{
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_framework_version_veneer,
0,
0,
0,
0);
}
uint32_t psa_version(uint32_t sid)
{
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_version_veneer,
sid,
0,
0,
0);
}
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
{
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_connect_veneer,
sid,
minor_version,
0,
0);
}
psa_status_t psa_call(psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len)
{
/* FixMe: sanity check can be added to offload some NS thread checks from
* TFM secure API
*/
/* Due to v8M restrictions, TF-M NS API needs to add another layer of
* serialization in order for NS to pass arguments to S
*/
psa_invec in_vecs, out_vecs;
in_vecs.base = in_vec;
in_vecs.len = in_len;
out_vecs.base = out_vec;
out_vecs.len = out_len;
return tfm_ns_lock_dispatch((veneer_fn)tfm_psa_call_veneer,
(uint32_t)handle,
(uint32_t)&in_vecs,
(uint32_t)&out_vecs,
0);
}
void psa_close(psa_handle_t handle)
{
tfm_ns_lock_dispatch((veneer_fn)tfm_psa_close_veneer,
(uint32_t)handle,
0,
0,
0);
}

View File

@ -1,217 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_BOOT_STATUS_H__
#define __TFM_BOOT_STATUS_H__
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Major numbers (4 bit) to identify
* the consumer of shared data in runtime SW
*/
#define TLV_MAJOR_CORE 0x0
#define TLV_MAJOR_IAS 0x1
/**
* 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(16) | tlv_tot_len(16) |
* -----------------------------------
*/
struct shared_data_tlv_header {
uint16_t tlv_magic;
uint16_t tlv_tot_len; /* size of whole TLV area (including this header) */
};
#define SHARED_DATA_HEADER_SIZE sizeof(struct shared_data_tlv_header)
/**
* Shared data TLV entry header format. All fields in little endian.
*
* -------------------------------
* | tlv_type(16) | tlv_len(16) |
* -------------------------------
* | Raw data |
* -------------------------------
*/
struct shared_data_tlv_entry {
uint16_t tlv_type;
uint16_t tlv_len; /* size of single TLV entry (including this header). */
};
/**
* \struct tfm_boot_data
*
* \brief Store the data for the runtime SW
*/
struct tfm_boot_data {
struct shared_data_tlv_header header;
uint8_t data[];
};
#define SHARED_DATA_ENTRY_HEADER_SIZE sizeof(struct shared_data_tlv_entry)
#define SHARED_DATA_ENTRY_SIZE(size) (size + SHARED_DATA_ENTRY_HEADER_SIZE)
#ifdef __cplusplus
}
#endif
#endif /* __TFM_BOOT_STATUS_H__ */

View File

@ -1,11 +0,0 @@
{
"name": "tfm-s",
"macros": ["MBED_FAULT_HANDLER_DISABLED"],
"config": {
"max_ns_thread_count": {
"help": "maximum allowed number of non-secure threads",
"macro_name": "TFM_MAX_NS_THREAD_COUNT",
"value": 10
}
}
}

View File

@ -1,190 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_HAL_H__
#define __TFM_SPM_HAL_H__
#include <stdint.h>
#include "tfm_secure_api.h"
#include "spm_api.h"
/**
* \brief Holds peripheral specific data fields required to manage the
* peripherals isolation
*
* This structure has to be defined in the platform directory, and may have
* different definition for each platform. The structure should contain fields
* that describe the peripheral for the functions that are prototyped in this
* file and are responsible for configuring the isolation of the peripherals.
*
* Pointers to structures of this type are managed by the SPM, and passed to the
* necessary function on isolation request. The pointers are also defined by the
* platform in the header file tfm_peripherals_def.h. For details on this, see
* the documentation of that file.
*/
struct tfm_spm_partition_platform_data_t;
#if defined (TFM_PSA_API) || (TFM_LVL != 1)
/**
* \brief Holds SPM db fields that define the memory regions used by a
* partition.
*/
struct tfm_spm_partition_memory_data_t
{
uint32_t code_start; /*!< Start of the code memory of this partition. */
uint32_t code_limit; /*!< Address of the byte beyond the end of the code
* memory of this partition.
*/
uint32_t ro_start; /*!< Start of the read only memory of this
* partition.
*/
uint32_t ro_limit; /*!< Address of the byte beyond the end of the read
* only memory of this partition.
*/
uint32_t rw_start; /*!< Start of the data region of this partition. */
uint32_t rw_limit; /*!< Address of the byte beyond the end of the data
* region of this partition.
*/
uint32_t zi_start; /*!< Start of the zero initialised data region of
* this partition.
*/
uint32_t zi_limit; /*!< Address of the byte beyond the end of the zero
* initialised region of this partition.
*/
uint32_t stack_bottom; /*!< The bottom of the stack for the partition. */
uint32_t stack_top; /*!< The top of the stack for the partition. */
};
#endif
/**
* \brief This function initialises the HW used for isolation, and sets the
* default configuration for them.
*
* This function is called during TF-M core early startup, before DB init
*/
void tfm_spm_hal_init_isolation_hw(void);
/**
* \brief This function initialises the HW used for isolation, and sets the
* default configuration for them.
* This function is called during TF-M core early startup, after DB init
*/
void tfm_spm_hal_setup_isolation_hw(void);
/**
* \brief Configure peripherals for a partition based on the platfotm data from
* the DB
*
* This function is called during partition initialisation (before calling the
* init function for the partition)
*
* \param[in] platform_data The platform fields of the partition DB record to
* be used for configuration. Can be NULL.
*/
void tfm_spm_hal_configure_default_isolation(
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Configures the system debug properties.
* The default configuration of this function should disable secure debug
* when either DAUTH_NONE or DAUTH_NS_ONLY define is set. It is up to the
* platform owner to decide if secure debug can be turned on in their
* system, if DAUTH_FULL define is present.
* The DAUTH_CHIP_DEFAULT define should not be considered a safe default
* option unless explicitly noted by the chip vendor.
* The implementation has to expect that one of those defines is going to
* be set. Otherwise, a compile error needs to be triggered.
*/
void tfm_spm_hal_init_debug(void);
/**
* \brief Enables the fault handlers
*/
void enable_fault_handlers(void);
/**
* \brief Configures the system reset request properties
*/
void system_reset_cfg(void);
/**
* \brief Configures all external interrupts to target the
* NS state, apart for the ones associated to secure
* peripherals (plus MPC and PPC)
*/
void nvic_interrupt_target_state_cfg(void);
/**
* \brief This function enable the interrupts associated
* to the secure peripherals (plus the isolation boundary violation
* interrupts)
*/
void nvic_interrupt_enable(void);
/**
* \brief Get the VTOR value of non-secure image
*
* \return Returns the address where the vector table of the non-secure image
* is located
*/
uint32_t tfm_spm_hal_get_ns_VTOR(void);
/**
* \brief Get the initial address of non-secure image main stack
*
* \return Returns the initial non-secure MSP
*/
uint32_t tfm_spm_hal_get_ns_MSP(void);
/**
* \brief Get the entry point of the non-secure image
*
* \return Returns the address of the non-secure image entry point
*/
uint32_t tfm_spm_hal_get_ns_entry_point(void);
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
/**
* \brief Configure the sandbox for a partition.
*
* \param[in] memory_data The memory ranges from the partition DB for this
* partition
* \param[in] platform_data The platform fields of the partition DB record
* for this partition. Can be NULL.
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_partition_sandbox_config(
const struct tfm_spm_partition_memory_data_t *memory_data,
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Deconfigure the sandbox for a partition.
*
* \param[in] memory_data The memory ranges from the partition DB for this
* partition
* \param[in] platform_data The platform fields of the partition DB record
* for this partition. Can be NULL.
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_partition_sandbox_deconfig(
const struct tfm_spm_partition_memory_data_t *memory_data,
const struct tfm_spm_partition_platform_data_t *platform_data);
/**
* \brief Set the share region mode
*
* \param[in] share The mode to set
*
* \return Returns the result operation as per \ref spm_err_t
*/
enum spm_err_t tfm_spm_hal_set_share_region(
enum tfm_buffer_share_region_e share);
#endif
#endif /* __TFM_SPM_HAL_H__ */

View File

@ -1,16 +0,0 @@
/*
* 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.
*/

View File

@ -1,66 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_ARCH_V8M_H__
#define __TFM_ARCH_V8M_H__
#include "cmsis.h"
#define XPSR_T32 0x01000000
#define LR_UNPRIVILEGED 0xfffffffd
/* This header file collects the ARCH related operations. */
struct tfm_state_context_base {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t ra_lr;
uint32_t ra;
uint32_t xpsr;
};
struct tfm_state_context_ext {
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t sp;
uint32_t sp_limit;
uint32_t dummy;
uint32_t lr;
};
struct tfm_state_context {
struct tfm_state_context_ext ctxb;
};
#define TFM_STATE_1ST_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
#define TFM_STATE_2ND_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r1)
#define TFM_STATE_3RD_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r2)
#define TFM_STATE_4TH_ARG(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r3)
#define TFM_STATE_RET_VAL(ctx) \
(((struct tfm_state_context_base *)(ctx)->ctxb.sp)->r0)
__STATIC_INLINE void tfm_trigger_pendsv(void)
{
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
void tfm_initialize_context(struct tfm_state_context *ctx,
uint32_t r0, uint32_t ra,
uint32_t sp, uint32_t sp_limit);
#endif

View File

@ -1,18 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_INTERNAL_DEFINES_H__
#define __TFM_INTERNAL_DEFINES_H__
/* IPC internal return status */
#define IPC_SUCCESS 0
#define IPC_ERROR_BAD_PARAMETERS (INT32_MIN)
#define IPC_ERROR_SHORT_BUFFER (INT32_MIN + 1)
#define IPC_ERROR_VERSION (INT32_MIN + 2)
#define IPC_ERROR_MEMORY_CHECK (INT32_MIN + 3)
#define IPC_ERROR_GENERIC (INT32_MIN + 0x1F)
#endif

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_LIST_H__
#define __TFM_LIST_H__
/* List structure */
struct tfm_list_node_t {
struct tfm_list_node_t *prev;
struct tfm_list_node_t *next;
};
/**
* \brief Initialize list head.
*
* \param[in] head List head need to be initialized.
*/
__STATIC_INLINE void tfm_list_init(struct tfm_list_node_t *head)
{
head->next = head;
head->prev = head;
}
/**
* \brief Add one node to list tail.
*
* \param[in] head List head initialized by \ref tfm_list_init.
* \param[in] node List node want to be added.
*/
__STATIC_INLINE void
tfm_list_add_tail(struct tfm_list_node_t *head, struct tfm_list_node_t *node)
{
head->prev->next = node;
node->prev = head->prev;
head->prev = node;
node->next = head;
}
/**
* \brief Check if a list is empty.
*
* \param[in] head List head initialized by \ref tfm_list_init.
*
* \returns returns 1 for empty, or 0 for not.
*/
__STATIC_INLINE int32_t tfm_list_is_empty(struct tfm_list_node_t *head)
{
return (head->next == head);
}
/**
* \brief Insert one node to list head.
*
* \param[in] head List head initialized by \ref tfm_list_init.
* \param[in] node List node want to be inserted.
*/
__STATIC_INLINE void
tfm_list_insert_first(struct tfm_list_node_t *head,
struct tfm_list_node_t *node)
{
node->next = head->next;
node->prev = head;
head->next->prev = node;
head->next = node;
}
/**
* \brief Retrieve the fist node from list.
*
* \param[in] head List head initialized by \ref tfm_list_init.
*
* \returns Returns the pointer to first list node.
*/
__STATIC_INLINE
struct tfm_list_node_t *tfm_list_first_node(struct tfm_list_node_t *head)
{
return head->next;
}
/**
* \brief Delete one node from list.
*
* \param[in] node List node want to be deleted.
*/
__STATIC_INLINE void tfm_list_del_node(struct tfm_list_node_t *node)
{
node->prev->next = node->next;
node->next->prev = node->prev;
}
/* Go through each node of a list */
#define TFM_LIST_FOR_EACH(node, head) \
for (node = (head)->next; node != head; node = node->next)
#endif

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_MESSAGE_QUEUE_H__
#define __TFM_MESSAGE_QUEUE_H__
#ifndef TFM_MSG_QUEUE_MAX_MSG_NUM
#define TFM_MSG_QUEUE_MAX_MSG_NUM 128
#endif
#define TFM_MSG_MAGIC 0x15154343
/* Message struct to collect parameter from client */
struct tfm_msg_body_t {
int32_t magic;
struct tfm_spm_service_t *service; /* RoT service pointer */
psa_handle_t handle; /* Connected Service handle */
struct tfm_event_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];
psa_outvec *caller_outvec; /*
* Save caller outvec pointer for
* write length update
*/
struct tfm_msg_body_t *next; /* List operators */
};
struct tfm_msg_queue_t {
struct tfm_msg_body_t *head; /* Queue head */
struct tfm_msg_body_t *tail; /* Queue tail */
uint32_t size; /* Number of the queue member */
};
/**
* \brief Enqueue a message into message queue.
*
* \param[in] queue Message queue, it will be initialized
* if has not been initialized.
* \param[in] node Message queue node want to be enqueue.
*
* \retval IPC_SUCCESS Success.
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
*/
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
struct tfm_msg_body_t *node);
/**
* \brief Dequeue a message from message queue.
*
* \param[in] queue Message queue.
*
* \retval node pointer Success.
* \retval NULL Queue is NULL or size is zero.
*/
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue);
/**
* \brief Check if a message queue is empty.
*
* \param[in] queue Message queue.
*
* \returns Returns 1 for empty, or 0 for not.
*/
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue);
#endif

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_POOLS_H__
#define __TFM_POOLS_H__
/*
* Resource pool - few known size resources allocation/free is required,
* so pool is more applicable than heap.
*/
/*
* Pool Instance:
* [ Pool Instance ] + N * [ Pool Chunks ]
*/
struct tfm_pool_chunk_t {
struct tfm_list_node_t list; /* Chunk list */
void *pool; /* Point to the parent pool */
uint8_t data[0]; /* Data indicator */
};
struct tfm_pool_instance_t {
size_t chunksz; /* Chunks size of pool member */
struct tfm_list_node_t chunks_list; /* Chunk list head in pool */
struct tfm_pool_chunk_t chunks[0]; /* Data indicator */
};
/*
* This will declares a static memory pool variable with chunk memory.
* Parameters:
* name - Variable name, will be used when register
* chunksz - chunk size in bytes
* num - Number of chunks
*/
#define TFM_POOL_DECLARE(name, chunksz, num) \
static uint8_t name##_pool_buf[((chunksz) + \
sizeof(struct tfm_pool_chunk_t)) * (num) \
+ sizeof(struct tfm_pool_instance_t)] \
__attribute__((aligned(4))); \
static struct tfm_pool_instance_t *name = \
(struct tfm_pool_instance_t *)name##_pool_buf
/* Get the head size of memory pool */
#define POOL_HEAD_SIZE (sizeof(struct tfm_pool_instance_t) + \
sizeof(struct tfm_pool_chunk_t))
/* Get the whole size of memory pool */
#define POOL_BUFFER_SIZE(name) sizeof(name##_pool_buf)
/**
* \brief Register a memory pool.
*
* \param[in] pool Pointer to memory pool declared by
* \ref TFM_POOL_DECLARE
* \param[in] poolsz Size of the pool buffer.
* \param[in] chunksz Size of chunks.
* \param[in] num Number of chunks.
*
* \retval IPC_SUCCESS Success.
* \retval IPC_ERROR_BAD_PARAMETERS Parameters error.
*/
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
size_t chunksz, size_t num);
/**
* \brief Allocate a memory from pool.
*
* \param[in] pool pool pointer decleared by \ref TFM_POOL_DECLARE
*
* \retval buffer pointer Success.
* \retval NULL Failed.
*/
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool);
/**
* \brief Free the allocated memory.
*
* \param[in] ptr Buffer pointer want to free.
*/
void tfm_pool_free(void *ptr);
#endif

View File

@ -1,326 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_H__
#define __TFM_SPM_H__
#include <stdbool.h>
#include "tfm_list.h"
#include "tfm_secure_api.h"
#ifndef TFM_SPM_MAX_ROT_SERV_NUM
#define TFM_SPM_MAX_ROT_SERV_NUM 28
#endif
#define TFM_VERSION_POLICY_RELAXED 0
#define TFM_VERSION_POLICY_STRICT 1
#ifndef TFM_CONN_HANDLE_MAX_NUM
#define TFM_CONN_HANDLE_MAX_NUM 32
#endif
/* RoT connection handle list */
struct tfm_conn_handle_t {
psa_handle_t handle; /* Handle value */
void *rhandle; /* Reverse handle value */
struct tfm_list_node_t list; /* list node */
};
/* Service database defined by manifest */
struct tfm_spm_service_db_t {
char *name; /* Service name */
uint32_t partition_id; /* Partition ID which service belong to */
psa_signal_t signal; /* Service signal */
uint32_t sid; /* Service identifier */
bool non_secure_client; /* If can be called by non secure client */
uint32_t minor_version; /* Minor version */
uint32_t minor_policy; /* Minor version policy */
};
/* RoT Service data */
struct tfm_spm_service_t {
struct tfm_spm_service_db_t *service_db; /* Service database pointer */
struct tfm_spm_ipc_partition_t *partition; /*
* Point to secure partition
* data
*/
struct tfm_list_node_t handle_list; /* Service handle list */
struct tfm_msg_queue_t msg_queue; /* Message queue */
struct tfm_list_node_t list; /* For list operation */
};
/*
* FixMe: This structure is for IPC partition which is different with library
* mode partition. There needs to be an alignment for IPC partition database
* and library mode database.
*/
/* Secure Partition data */
struct tfm_spm_ipc_partition_t {
int32_t index; /* Partition index */
int32_t id; /* Secure partition ID */
struct tfm_event_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 */
};
/*************************** Extended SPM functions **************************/
/**
* \brief Get the running partition ID.
*
* \return Returns the partition ID
*/
uint32_t tfm_spm_partition_get_running_partition_id_ext(void);
/**
* \brief Get the current partition mode.
*
* \param[in] partition_idx Index of current partition
*
* \retval TFM_PARTITION_PRIVILEGED_MODE Privileged mode
* \retval TFM_PARTITION_UNPRIVILEGED_MODE Unprivileged mode
*/
uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx);
/******************** Service handle management functions ********************/
/**
* \brief Create connection handle for client connect
*
* \param[in] service Target service context pointer
*
* \retval PSA_NULL_HANDLE Create failed \ref PSA_NULL_HANDLE
* \retval >0 Service handle created, \ref psa_handle_t
*/
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service);
/**
* \brief Free connection handle which not used anymore.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval "Does not return" Panic for not find service by handle
*/
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle);
/**
* \brief Set reverse handle value for connection.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
* \param[in] rhandle rhandle need to save
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval "Does not return" Panic for not find handle node
*/
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle,
void *rhandle);
/**
* \brief Get reverse handle value from connection hanlde.
*
* \param[in] service Target service context pointer
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle(), \ref psa_handle_t
*
* \retval void * Success
* \retval "Does not return" Panic for those:
* service pointer are NULL
* hanlde is \ref PSA_NULL_HANDLE
* handle node does not be found
*/
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle);
/******************** Partition management functions *************************/
/**
* \brief Get current running partition context.
*
* \retval NULL Failed
* \retval "Not NULL" Return the parttion context pointer
* \ref spm_partition_t structures
*/
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void);
/**
* \brief Get the service context by signal.
*
* \param[in] partition Partition context pointer
* \ref spm_partition_t structures
* \param[in] signal Signal associated with inputs to the Secure
* Partition, \ref psa_signal_t
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
psa_signal_t signal);
/**
* \brief Get the service context by service ID.
*
* \param[in] sid RoT Service identity
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid);
/**
* \brief Get the service context by connection handle.
*
* \param[in] conn_handle Connection handle created by
* tfm_spm_create_conn_handle()
*
* \retval NULL Failed
* \retval "Not NULL" Target service context pointer,
* \ref spm_service_t structures
*/
struct tfm_spm_service_t *
tfm_spm_get_service_by_handle(psa_handle_t conn_handle);
/**
* \brief Get the partition context by partition ID.
*
* \param[in] partition_id Partition identity
*
* \retval NULL Failed
* \retval "Not NULL" Target partition context pointer,
* \ref spm_partition_t structures
*/
struct tfm_spm_ipc_partition_t *
tfm_spm_get_partition_by_id(int32_t partition_id);
/************************ Message functions **********************************/
/**
* \brief Get message context by message handle.
*
* \param[in] msg_handle Message handle which is a reference generated
* by the SPM to a specific message.
*
* \return The message body context pointer
* \ref msg_body_t structures
*/
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle);
/**
* \brief Create a message for PSA client call.
*
* \param[in] service Target service context pointer, which can be
* obtained by partition management functions
* \prarm[in] handle Connect handle return by psa_connect(). Should
* be \ref PSA_NULL_HANDLE in psa_connect().
* \param[in] type Message type, PSA_IPC_CONNECT, PSA_IPC_CALL or
* PSA_IPC_DISCONNECT
* \param[in] ns_caller Whether from NS caller
* \param[in] invec Array of input \ref psa_invec structures
* \param[in] in_len Number of input \ref psa_invec structures
* \param[in] outvec Array of output \ref psa_outvec structures
* \param[in] out_len Number of output \ref psa_outvec structures
* \param[in] caller_outvec Array of caller output \ref psa_outvec structures
*
* \retval NULL Failed
* \retval "Not NULL" New message body pointer \ref msg_body_t structures
*/
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
psa_handle_t handle,
uint32_t type, int32_t ns_caller,
psa_invec *invec, size_t in_len,
psa_outvec *outvec, size_t out_len,
psa_outvec *caller_outvec);
/**
* \brief Free message which unused anymore
*
* \param[in] msg Message pointer which want to free
* \ref msg_body_t structures
*
* \retval void Success
* \retval "Does not return" Failed
*/
void tfm_spm_free_msg(struct tfm_msg_body_t *msg);
/**
* \brief Send message and wake up the SP who is waiting on
* message queue, block the current thread and
* scheduler triggered
*
* \param[in] service Target service context pointer, which can be
* obtained by partition management functions
* \param[in] msg message created by spm_create_msg()
* \ref msg_body_t structures
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_GENERIC Failed to enqueue message to service message queue
*/
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
struct tfm_msg_body_t *msg);
/**
* \brief Check the client minor version according to
* version policy
*
* \param[in] service Target service context pointer, which can be get
* by partition management functions
* \param[in] minor_version Client support minor version
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_VERSION Check failed
*/
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
uint32_t minor_version);
/**
* \brief Check the memory reference is valid.
*
* \param[in] buffer Pointer of memory reference
* \param[in] len Length of memory reference in bytes
* \param[in] ns_caller From non-secure caller
* \param[in] access Type of access specified by the
* \ref tfm_memory_access_e
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \retval IPC_SUCCESS Success
* \retval IPC_ERROR_BAD_PARAMETERS Bad parameters input
* \retval IPC_ERROR_MEMORY_CHECK Check failed
*/
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
enum tfm_memory_access_e access,
uint32_t privileged);
/* This function should be called before schedule function */
void tfm_spm_init(void);
/*
* PendSV specified function.
*
* Parameters :
* ctxb - State context storage pointer
*
* Notes:
* This is a staging API. Scheduler should be called in SPM finally and
* this function will be obsoleted later.
*/
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb);
#endif

View File

@ -1,108 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SVCALLS_H__
#define __TFM_SVCALLS_H__
/* Svcall for PSA Client APIs */
/**
* \brief SVC handler for \ref psa_framework_version.
*
* \return version The version of the PSA Framework implementation
* that is providing the runtime services to the
* caller.
*/
uint32_t tfm_svcall_psa_framework_version(void);
/**
* \brief SVC handler for \ref psa_version.
*
* \param[in] args Include all input arguments: sid.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
* caller is not permitted to access the service.
* \retval > 0 The minor version of the implemented RoT
* Service.
*/
uint32_t tfm_svcall_psa_version(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for \ref psa_connect.
*
* \param[in] args Include all input arguments:
* sid, minor_version.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval > 0 A handle for the connection.
* \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
* connection.
* \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the
* connection at the moment.
* \retval "Does not return" The RoT Service ID and version are not
* supported, or the caller is not permitted to
* access the service.
*/
psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for \ref psa_call.
*
* \param[in] args Include all input arguments:
* handle, in_vec, in_len, out_vec, out_len.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
* \param[in] lr EXC_RETURN value of the SVC.
*
* \retval >=0 RoT Service-specific status value.
* \retval <0 RoT Service-specific error code.
* \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
* Service. This indicates that either this or
* a previous message was invalid.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was passed.
* \arg The connection is already handling a request.
* \arg An invalid memory reference was provided.
* \arg in_len + out_len > PSA_MAX_IOVEC.
* \arg The message is unrecognized by the RoT
* Service or incorrectly formatted.
*/
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller,
uint32_t lr);
/**
* \brief SVC handler for \ref psa_close.
*
* \param[in] args Include all input arguments: handle.
* \param[in] ns_caller If 'non-zero', call from non-secure client.
* Or from secure client.
*
* \retval void Success.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was provided that is not
* the null handle.
* \arg The connection is handling a request.
*/
void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller);
/**
* \brief SVC handler for IPC functions
*
* \param[in] svc_num SVC number
* \param[in] ctx Argument context
* \param[in] lr EXC_RETURN value of the SVC.
*
* \returns Return values from those who has,
* or PSA_SUCCESS.
*/
int32_t SVC_Handler_IPC(tfm_svc_number_t svc_num, uint32_t *ctx, uint32_t lr);
#endif

View File

@ -1,232 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_THREAD_H__
#define __TFM_THREAD_H__
#include "tfm_arch_v8m.h"
#include "cmsis_compiler.h"
/* Status code */
#define THRD_STAT_CREATING 0
#define THRD_STAT_RUNNING 1
#define THRD_STAT_BLOCK 2
#define THRD_STAT_DETACH 3
#define THRD_STAT_INVALID 4
/* Security attribute - default as security */
#define THRD_ATTR_SECURE_OFFSET 16
#define THRD_ATTR_SECURE (0)
#define THRD_ATTR_NON_SECURE (1 << THRD_ATTR_SECURE_OFFSET)
/* Lower value has higher priority */
#define THRD_PRIOR_MASK 0xFF
#define THRD_PRIOR_HIGHEST 0x0
#define THRD_PRIOR_MEDIUM 0x7F
#define THRD_PRIOR_LOWEST 0xFF
/* Error code */
#define THRD_SUCCESS 0
#define THRD_ERR_INVALID_PARAM 1
/* Thread entry function type */
typedef void *(*tfm_thrd_func_t)(void *);
/* Thread context */
struct tfm_thrd_ctx {
tfm_thrd_func_t pfn; /* entry function */
void *param; /* entry parameter */
uint8_t *sp_base; /* stack bottom */
uint8_t *sp_top; /* stack top */
uint32_t prior; /* priority */
uint32_t status; /* status */
struct tfm_state_context state_ctx; /* State context */
struct tfm_thrd_ctx *next; /* next thread in list */
};
/*
* Initialize a thread context with the necessary info.
*
* Parameters :
* pth - pointer of caller provided thread context
* pfn - thread entry function
* param - thread entry function parameter
* sp_base - stack pointer base (higher address)
* sp_top - stack pointer top (lower address)
*
* Notes :
* Thread contex rely on caller allocated memory; initialize members in
* context. This function does not insert thread into schedulable list.
*/
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
tfm_thrd_func_t pfn, void *param,
uint8_t *sp_base, uint8_t *sp_top);
/* Set thread priority.
*
* Parameters :
* pth - pointer of thread context
* prior - priority value (0~255)
*
* Notes :
* Set thread priority. Priority is set to THRD_PRIOR_MEDIUM in
* tfm_thrd_init().
*/
void __STATIC_INLINE tfm_thrd_priority(struct tfm_thrd_ctx *pth,
uint32_t prior)
{
pth->prior &= ~THRD_PRIOR_MASK;
pth->prior |= prior & THRD_PRIOR_MASK;
}
/*
* Set thread security attribute.
*
* Parameters :
* pth - pointer of thread context
* attr_secure - THRD_ATTR_SECURE or THRD_ATTR_NON_SECURE
*
* Notes
* Reuse prior of thread context to shift down non-secure thread priority.
*/
void __STATIC_INLINE tfm_thrd_secure(struct tfm_thrd_ctx *pth,
uint32_t attr_secure)
{
pth->prior &= ~THRD_ATTR_NON_SECURE;
pth->prior |= attr_secure;
}
/*
* Set thread status.
*
* Parameters :
* pth - pointer of thread context
* new_status - new status of thread
*
* Return :
* None
*
* Notes :
* Thread status is not changed if invalid status value inputed.
*/
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status);
/*
* Get thread status.
*
* Parameters :
* pth - pointer of thread context
*
* Return :
* Status of thread
*/
uint32_t __STATIC_INLINE tfm_thrd_get_status(struct tfm_thrd_ctx *pth)
{
return pth->status;
}
/*
* Set thread state return value.
*
* Parameters :
* pth - pointer of thread context
* retval - return value to be set for thread state
*
* Notes :
* This API is useful for blocked syscall blocking thread. Syscall
* could set its return value to the caller before caller goes.
*/
void __STATIC_INLINE tfm_thrd_set_retval(struct tfm_thrd_ctx *pth,
uint32_t retval)
{
TFM_STATE_RET_VAL(&pth->state_ctx) = retval;
}
/*
* Validate thread context and insert it into schedulable list.
*
* Parameters :
* pth - pointer of thread context
*
* Return :
* THRD_SUCCESS for success. Or an error is returned.
*
* Notes :
* This function validates thread info. It returns error if thread info
* is not correct. Thread is avaliable after successful tfm_thrd_start().
*/
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth);
/*
* Get current running thread.
*
* Return :
* Current running thread context pointer.
*/
struct tfm_thrd_ctx *tfm_thrd_curr_thread(void);
/*
* Get next running thread in list.
*
* Return :
* Pointer of next thread to be run.
*/
struct tfm_thrd_ctx *tfm_thrd_next_thread(void);
/*
* Start scheduler for existing threads
*
* Parameters:
* pth - pointer of the caller context collecting thread
*
* Notes :
* This function should be called only ONCE to start the scheduler.
* Caller needs to provide a thread object to collect current context.
* The usage of the collected context is caller defined.
*/
void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth);
/*
* Activate a scheduling action after exception.
*
* Notes :
* This function could be called multiple times before scheduling.
*/
void tfm_thrd_activate_schedule(void);
/*
* Save current context into 'prev' thread and switch to 'next'.
*
* Parameters :
* ctxb - latest caller context
* prev - previous thread to be switched out
* next - thread to be run
*
* Notes :
* This function could be called multiple times before scheduling.
*/
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
struct tfm_thrd_ctx *prev,
struct tfm_thrd_ctx *next);
/*
* Svcall to exit current running thread.
*
* Notes :
* Remove current thread out of schedulable list.
*/
void tfm_svcall_thrd_exit(void);
/*
* Exit current running thread for client.
*
* Notes:
* Must be called in thread mode.
*/
void tfm_thrd_exit(void);
#endif

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_UTILS_H__
#define __TFM_UTILS_H__
/* CPU spin here */
void tfm_panic(void);
/* Assert and spin */
#define TFM_ASSERT(cond) \
do { \
if (!(cond)) { \
printf("Assert:%s:%d", __FUNCTION__, __LINE__); \
while (1) \
; \
} \
} while (0)
/* Get container structure start address from member */
#define TFM_GET_CONTAINER_PTR(ptr, type, member) \
(type *)((unsigned long)(ptr) - offsetof(type, member))
int32_t tfm_bitcount(uint32_t n);
#endif

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_WAIT_H__
#define __TFM_WAIT_H__
#include "cmsis_compiler.h"
/* The magic number has two purposes: corruption detection and debug */
#define TFM_EVENT_MAGIC 0x65766e74
struct tfm_event_t {
uint32_t magic; /* 'evnt' */
struct tfm_thrd_ctx *owner; /* Event blocked thread */
};
/*
* Initialize an event object.
*
* Parameters:
* pevnt - The pointer of event object allocated by the caller
*/
void __STATIC_INLINE tfm_event_init(struct tfm_event_t *pevnt)
{
pevnt->magic = TFM_EVENT_MAGIC;
pevnt->owner = NULL;
}
/*
* Wait on an event object.
*
* Parameters:
* pevnt - The pointer of event object allocated by the caller
*
* Notes:
* Block caller thread by calling this function.
*/
void tfm_event_wait(struct tfm_event_t *pevnt);
/*
* Wake up an event object.
*
* Parameters :
* pevnt - The pointer of event object allocated by the caller
* retval - Value to be returned to owner
*
* Notes:
* Wake up the blocked thread and set parameter 'retval' as the return value.
*/
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval);
#endif

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_svc.h"
#include "psa_client.h"
__attribute__((naked, section("SFN")))
uint32_t psa_framework_version(void)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_FRAMEWORK_VERSION));
}
__attribute__((naked, section("SFN")))
uint32_t psa_version(uint32_t sid)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_VERSION));
}
__attribute__((naked, section("SFN")))
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CONNECT));
}
__attribute__((naked, section("SFN")))
psa_status_t psa_call(psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CALL));
}
__attribute__((naked, section("SFN")))
void psa_close(psa_handle_t handle)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CLOSE));
}

View File

@ -1,96 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_svc.h"
#include "psa_client.h"
#include "psa_service.h"
__attribute__((naked, section("SFN")))
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_WAIT));
}
__attribute__((naked, section("SFN")))
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_GET));
}
__attribute__((naked, section("SFN")))
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_SET_RHANDLE));
}
__attribute__((naked, section("SFN")))
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
void *buffer, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_READ));
}
__attribute__((naked, section("SFN")))
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_SKIP));
}
__attribute__((naked, section("SFN")))
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
const void *buffer, size_t num_bytes)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_WRITE));
}
__attribute__((naked, section("SFN")))
void psa_reply(psa_handle_t msg_handle, psa_status_t retval)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_REPLY));
}
__attribute__((naked, section("SFN")))
void psa_notify(int32_t partition_id)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_NOTIFY));
}
__attribute__((naked, section("SFN")))
void psa_clear(void)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_CLEAR));
}
__attribute__((naked, section("SFN")))
void psa_eoi(psa_signal_t irq_signal)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_PSA_EOI));
}

View File

@ -1,147 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_arch_v8m.h"
#include "cmsis.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_utils.h"
#include "tfm_thread.h"
#include "tfm_memory_utils.h"
/* This file contains the ARCH code for ARM V8M */
__attribute__((section("SFN")))
static void exit_zone(void)
{
tfm_thrd_exit();
}
void tfm_initialize_context(struct tfm_state_context *ctx,
uint32_t r0, uint32_t ra,
uint32_t sp, uint32_t sp_limit)
{
/*
* For security consideration, set unused registers into ZERO;
* and only necessary registers are set here.
*/
struct tfm_state_context_base *p_ctxa =
(struct tfm_state_context_base *)sp;
/*
* Shift back SP to leave space for holding base context
* since thread is kicked off through exception return.
*/
p_ctxa--;
/* Basic context is considerate at thread start.*/
tfm_memset(p_ctxa, 0, sizeof(*p_ctxa));
p_ctxa->r0 = r0;
p_ctxa->ra = ra;
p_ctxa->ra_lr = (uint32_t)exit_zone;
p_ctxa->xpsr = XPSR_T32;
tfm_memset(ctx, 0, sizeof(*ctx));
ctx->ctxb.sp = (uint32_t)p_ctxa;
ctx->ctxb.sp_limit = sp_limit;
ctx->ctxb.lr = LR_UNPRIVILEGED;
}
/*
* Stack status at PendSV entry:
*
* [ R0 - R3 ]<- PSP
* [ R12 ]
* [ LR_of_RA ]
* MSP->[ ........ ] [ RA ]
* [ ........ ] [ XPSR ]
* [ ........ ]
* [ ........ ]
*
* Stack status before calling pendsv_do_schedule():
*
* MSP->[ R4 - R11 ]
* [ PSP ]--->[ R0 - R3 ]
* [ PSP Limit] [ R12 ]
* [ R2(dummy)] [ LR_of_RA ]
* [ LR ] [ RA ]
* [ ........ ] [ XPSR ]
* [ ........ ] [ ........ ]
* [ ........ ]
*
* pendsv_do_schedule() updates stacked context into current thread and
* replace stacked context with context of next thread.
*
* Scheduler does not support handler mode thread so take PSP/PSP_LIMIT as
* thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
* aligned.
*/
#if defined(__ARM_ARCH_8M_MAIN__)
__attribute__((naked)) void PendSV_Handler(void)
{
__ASM volatile(
"mrs r0, psp \n"
"mrs r1, psplim \n"
"push {r0, r1, r2, lr} \n"
"push {r4-r11} \n"
"mov r0, sp \n"
"bl tfm_pendsv_do_schedule \n"
"pop {r4-r11} \n"
"pop {r0, r1, r2, lr} \n"
"msr psp, r0 \n"
"msr psplim, r1 \n"
"bx lr \n"
);
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) void PendSV_Handler(void)
{
__ASM volatile(
"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)
{
__ASM volatile("b .");
}
__attribute__((naked)) void BusFault_Handler(void)
{
__ASM volatile("b .");
}
__attribute__((naked)) void UsageFault_Handler(void)
{
__ASM volatile("b .");
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_internal_defines.h"
#include "tfm_message_queue.h"
/* Message queue process */
int32_t tfm_msg_enqueue(struct tfm_msg_queue_t *queue,
struct tfm_msg_body_t *node)
{
if (!queue || !node) {
return IPC_ERROR_BAD_PARAMETERS;
}
if (queue->size == 0) {
queue->head = node;
queue->tail = node;
} else {
queue->tail->next = node;
queue->tail = node;
}
queue->size++;
return IPC_SUCCESS;
}
struct tfm_msg_body_t *tfm_msg_dequeue(struct tfm_msg_queue_t *queue)
{
struct tfm_msg_body_t *pop_node;
if (!queue) {
return NULL;
}
if (queue->size == 0) {
return NULL;
}
pop_node = queue->head;
queue->head = queue->head->next;
queue->size--;
return pop_node;
}
int32_t tfm_msg_queue_is_empty(struct tfm_msg_queue_t *queue)
{
return queue->size == 0 ? 1 : 0;
}

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_internal_defines.h"
#include "cmsis_compiler.h"
#include "tfm_utils.h"
#include "tfm_list.h"
#include "tfm_pools.h"
#include "tfm_memory_utils.h"
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
size_t chunksz, size_t num)
{
struct tfm_pool_chunk_t *pchunk;
size_t i;
if (!pool || num == 0) {
return IPC_ERROR_BAD_PARAMETERS;
}
/* Ensure buffer is large enough */
if (poolsz != ((chunksz + sizeof(struct tfm_pool_chunk_t)) * num +
sizeof(struct tfm_pool_instance_t))) {
return IPC_ERROR_BAD_PARAMETERS;
}
/* Buffer should be BSS cleared but clear it again */
tfm_memset(pool, 0, poolsz);
/* Chain pool chunks */
tfm_list_init(&pool->chunks_list);
pchunk = (struct tfm_pool_chunk_t *)pool->chunks;
for (i = 0; i < num; i++) {
pchunk->pool = pool;
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
pchunk = (struct tfm_pool_chunk_t *)&pchunk->data[chunksz];
}
/* Prepare instance and insert to pool list */
pool->chunksz = chunksz;
return IPC_SUCCESS;
}
void *tfm_pool_alloc(struct tfm_pool_instance_t *pool)
{
struct tfm_list_node_t *node;
struct tfm_pool_chunk_t *pchunk;
if (!pool) {
return NULL;
}
if (tfm_list_is_empty(&pool->chunks_list)) {
return NULL;
}
node = tfm_list_first_node(&pool->chunks_list);
pchunk = TFM_GET_CONTAINER_PTR(node, struct tfm_pool_chunk_t, list);
/* Remove node from list node, it will be added when pool free */
tfm_list_del_node(node);
return &pchunk->data;
}
void tfm_pool_free(void *ptr)
{
struct tfm_pool_chunk_t *pchunk;
struct tfm_pool_instance_t *pool;
pchunk = TFM_GET_CONTAINER_PTR(ptr, struct tfm_pool_chunk_t, data);
pool = (struct tfm_pool_instance_t *)pchunk->pool;
tfm_list_add_tail(&pool->chunks_list, &pchunk->list);
}

View File

@ -1,618 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_utils.h"
#include "platform/include/tfm_spm_hal.h"
#include "spm_api.h"
#include "spm_db.h"
#include "spm_db_setup.h"
#include "tfm_internal_defines.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_list.h"
#include "tfm_pools.h"
#include "tfm_spm.h"
#include "tfm_spm_signal_defs.h"
#include "tfm_thread.h"
#include "region_defs.h"
#include "tfm_nspm.h"
#include "tfm_memory_utils.h"
/*
* IPC partitions.
* FixMe: Need to get align with spm_partition_db_t.
*/
static struct tfm_spm_ipc_partition_t
g_spm_ipc_partition[SPM_MAX_PARTITIONS] = {};
/* Extern SPM variable */
extern struct spm_partition_db_t g_spm_partition_db;
/* Extern secure lock variable */
extern int32_t tfm_secure_lock;
/* Pools */
TFM_POOL_DECLARE(conn_handle_pool, sizeof(struct tfm_conn_handle_t),
TFM_CONN_HANDLE_MAX_NUM);
TFM_POOL_DECLARE(spm_service_pool, sizeof(struct tfm_spm_service_t),
TFM_SPM_MAX_ROT_SERV_NUM);
TFM_POOL_DECLARE(msg_db_pool, sizeof(struct tfm_msg_body_t),
TFM_MSG_QUEUE_MAX_MSG_NUM);
static struct tfm_spm_service_db_t g_spm_service_db[] = {
#include "tfm_service_list.inc"
};
/********************** SPM functions for handler mode ***********************/
/* Service handle management functions */
psa_handle_t tfm_spm_create_conn_handle(struct tfm_spm_service_t *service)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Get buffer for handle list structure from handle pool */
node = (struct tfm_conn_handle_t *)tfm_pool_alloc(conn_handle_pool);
if (!node) {
return PSA_NULL_HANDLE;
}
/* Global unique handle, use handle buffer address directly */
node->handle = (psa_handle_t)node;
/* Add handle node to list for next psa functions */
tfm_list_add_tail(&service->handle_list, &node->list);
return node->handle;
}
static struct tfm_conn_handle_t *
tfm_spm_find_conn_handle_node(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *handle_node;
struct tfm_list_node_t *node, *head;
TFM_ASSERT(service);
head = &service->handle_list;
TFM_LIST_FOR_EACH(node, head) {
handle_node = TFM_GET_CONTAINER_PTR(node, struct tfm_conn_handle_t,
list);
if (handle_node->handle == conn_handle) {
return handle_node;
}
}
return NULL;
}
int32_t tfm_spm_free_conn_handle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
/* Remove node from handle list */
tfm_list_del_node(&node->list);
node->rhandle = NULL;
/* Back handle buffer to pool */
tfm_pool_free(node);
return IPC_SUCCESS;
}
int32_t tfm_spm_set_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle,
void *rhandle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Set reverse handle value only be allowed for a connected handle */
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
node->rhandle = rhandle;
return IPC_SUCCESS;
}
void *tfm_spm_get_rhandle(struct tfm_spm_service_t *service,
psa_handle_t conn_handle)
{
struct tfm_conn_handle_t *node;
TFM_ASSERT(service);
/* Get reverse handle value only be allowed for a connected handle */
TFM_ASSERT(conn_handle != PSA_NULL_HANDLE);
/* There are many handles for each RoT Service */
node = tfm_spm_find_conn_handle_node(service, conn_handle);
if (!node) {
tfm_panic();
}
return node->rhandle;
}
/* Partition management functions */
struct tfm_spm_service_t *
tfm_spm_get_service_by_signal(struct tfm_spm_ipc_partition_t *partition,
psa_signal_t signal)
{
struct tfm_list_node_t *node, *head;
struct tfm_spm_service_t *service;
TFM_ASSERT(partition);
if (tfm_list_is_empty(&partition->service_list)) {
tfm_panic();
}
head = &partition->service_list;
TFM_LIST_FOR_EACH(node, head) {
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t, list);
if (service->service_db->signal == signal) {
return service;
}
}
return NULL;
}
struct tfm_spm_service_t *tfm_spm_get_service_by_sid(uint32_t sid)
{
uint32_t i;
struct tfm_list_node_t *node, *head;
struct tfm_spm_service_t *service;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
/* Skip partition without IPC flag */
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
SPM_PART_FLAG_IPC) == 0) {
continue;
}
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
continue;
}
head = &g_spm_ipc_partition[i].service_list;
TFM_LIST_FOR_EACH(node, head) {
service = TFM_GET_CONTAINER_PTR(node, struct tfm_spm_service_t,
list);
if (service->service_db->sid == sid) {
return service;
}
}
}
return NULL;
}
struct tfm_spm_service_t *
tfm_spm_get_service_by_handle(psa_handle_t conn_handle)
{
uint32_t i;
struct tfm_conn_handle_t *handle;
struct tfm_list_node_t *service_node, *service_head;
struct tfm_list_node_t *handle_node, *handle_head;
struct tfm_spm_service_t *service;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
/* Skip partition without IPC flag */
if ((tfm_spm_partition_get_flags(g_spm_ipc_partition[i].index) &
SPM_PART_FLAG_IPC) == 0) {
continue;
}
if (tfm_list_is_empty(&g_spm_ipc_partition[i].service_list)) {
continue;
}
service_head = &g_spm_ipc_partition[i].service_list;
TFM_LIST_FOR_EACH(service_node, service_head) {
service = TFM_GET_CONTAINER_PTR(service_node,
struct tfm_spm_service_t, list);
handle_head = &service->handle_list;
TFM_LIST_FOR_EACH(handle_node, handle_head) {
handle = TFM_GET_CONTAINER_PTR(handle_node,
struct tfm_conn_handle_t, list);
if (handle->handle == conn_handle) {
return service;
}
}
}
}
return NULL;
}
struct tfm_spm_ipc_partition_t *
tfm_spm_get_partition_by_id(int32_t partition_id)
{
uint32_t i;
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
if (g_spm_ipc_partition[i].id == partition_id) {
return &g_spm_ipc_partition[i];
}
}
return NULL;
}
struct tfm_spm_ipc_partition_t *tfm_spm_get_running_partition(void)
{
uint32_t spid;
spid = tfm_spm_partition_get_running_partition_id_ext();
return tfm_spm_get_partition_by_id(spid);
}
int32_t tfm_spm_check_client_version(struct tfm_spm_service_t *service,
uint32_t minor_version)
{
TFM_ASSERT(service);
switch (service->service_db->minor_policy) {
case TFM_VERSION_POLICY_RELAXED:
if (minor_version > service->service_db->minor_version) {
return IPC_ERROR_VERSION;
}
break;
case TFM_VERSION_POLICY_STRICT:
if (minor_version != service->service_db->minor_version) {
return IPC_ERROR_VERSION;
}
break;
default:
return IPC_ERROR_VERSION;
}
return IPC_SUCCESS;
}
/* Message functions */
struct tfm_msg_body_t *tfm_spm_get_msg_from_handle(psa_handle_t msg_handle)
{
/*
* There may be one error handle passed by the caller in two conditions:
* 1. Not a valid message handle.
* 2. Handle between different Partitions. Partition A passes one handle
* belong to other Partitions and tries to access other's data.
* So, need do necessary checking to prevent those conditions.
*/
struct tfm_msg_body_t *msg;
uint32_t partition_id;
msg = (struct tfm_msg_body_t *)msg_handle;
if (!msg) {
return NULL;
}
/*
* FixMe: For condition 1: using a magic number to define it's a message.
* It needs to be an enhancement to check the handle belong to service.
*/
if (msg->magic != TFM_MSG_MAGIC) {
return NULL;
}
/* For condition 2: check if the partition ID is same */
partition_id = tfm_spm_partition_get_running_partition_id_ext();
if (partition_id != msg->service->partition->id) {
return NULL;
}
return msg;
}
struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
psa_handle_t handle,
uint32_t type, int32_t ns_caller,
psa_invec *invec, size_t in_len,
psa_outvec *outvec, size_t out_len,
psa_outvec *caller_outvec)
{
struct tfm_msg_body_t *msg = NULL;
uint32_t i;
TFM_ASSERT(service);
TFM_ASSERT(!(invec == NULL && in_len != 0));
TFM_ASSERT(!(outvec == NULL && out_len != 0));
TFM_ASSERT(in_len <= PSA_MAX_IOVEC);
TFM_ASSERT(out_len <= PSA_MAX_IOVEC);
TFM_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
/* Get message buffer from message pool */
msg = (struct tfm_msg_body_t *)tfm_pool_alloc(msg_db_pool);
if (!msg) {
return NULL;
}
/* Clear message buffer before using it */
tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
tfm_event_init(&msg->ack_evnt);
msg->magic = TFM_MSG_MAGIC;
msg->service = service;
msg->handle = handle;
msg->caller_outvec = caller_outvec;
/* Get current partition id */
if (ns_caller) {
msg->msg.client_id = tfm_nspm_get_current_client_id();
} else {
msg->msg.client_id = tfm_spm_partition_get_running_partition_id_ext();
}
/* Copy contents */
msg->msg.type = type;
for (i = 0; i < in_len; i++) {
msg->msg.in_size[i] = invec[i].len;
msg->invec[i].base = invec[i].base;
}
for (i = 0; i < out_len; i++) {
msg->msg.out_size[i] = outvec[i].len;
msg->outvec[i].base = outvec[i].base;
/* Out len is used to record the writed number, set 0 here again */
msg->outvec[i].len = 0;
}
/* Use message address as handle */
msg->msg.handle = (psa_handle_t)msg;
/* For connected handle, set rhandle to every message */
if (handle != PSA_NULL_HANDLE) {
msg->msg.rhandle = tfm_spm_get_rhandle(service, handle);
}
return msg;
}
void tfm_spm_free_msg(struct tfm_msg_body_t *msg)
{
tfm_pool_free(msg);
}
int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
struct tfm_msg_body_t *msg)
{
TFM_ASSERT(service);
TFM_ASSERT(msg);
/* Enqueue message to service message queue */
if (tfm_msg_enqueue(&service->msg_queue, msg) != IPC_SUCCESS) {
return IPC_ERROR_GENERIC;
}
/* Messages put. Update signals */
service->partition->signals |= service->service_db->signal;
tfm_event_wake(&service->partition->signal_evnt,
(service->partition->signals &
service->partition->signal_mask));
tfm_event_wait(&msg->ack_evnt);
return IPC_SUCCESS;
}
/* SPM extend functions */
uint32_t tfm_spm_partition_get_running_partition_id_ext(void)
{
struct tfm_thrd_ctx *pth = tfm_thrd_curr_thread();
struct spm_partition_desc_t *partition;
partition = TFM_GET_CONTAINER_PTR(pth, struct spm_partition_desc_t,
sp_thrd);
return partition->static_data.partition_id;
}
static struct tfm_thrd_ctx *
tfm_spm_partition_get_thread_info_ext(uint32_t partition_idx)
{
return &g_spm_partition_db.partitions[partition_idx].sp_thrd;
}
static tfm_thrd_func_t
tfm_spm_partition_get_init_func_ext(uint32_t partition_idx)
{
return (tfm_thrd_func_t)(g_spm_partition_db.partitions[partition_idx].
static_data.partition_init);
}
static uint32_t tfm_spm_partition_get_priority_ext(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_priority;
}
int32_t tfm_memory_check(void *buffer, size_t len, int32_t ns_caller,
enum tfm_memory_access_e access,
uint32_t privileged)
{
int32_t err;
/* If len is zero, this indicates an empty buffer and base is ignored */
if (len == 0) {
return IPC_SUCCESS;
}
if (!buffer) {
return IPC_ERROR_BAD_PARAMETERS;
}
if ((uintptr_t)buffer > (UINTPTR_MAX - len)) {
return IPC_ERROR_MEMORY_CHECK;
}
if (access == TFM_MEMORY_ACCESS_RW) {
err = tfm_core_has_write_access_to_region(buffer, len, ns_caller,
privileged);
} else {
err = tfm_core_has_read_access_to_region(buffer, len, ns_caller,
privileged);
}
if (err == TFM_SUCCESS) {
return IPC_SUCCESS;
}
return IPC_ERROR_MEMORY_CHECK;
}
uint32_t tfm_spm_partition_get_privileged_mode(uint32_t partition_idx)
{
if (tfm_spm_partition_get_flags(partition_idx) & SPM_PART_FLAG_PSA_ROT) {
return TFM_PARTITION_PRIVILEGED_MODE;
} else {
return TFM_PARTITION_UNPRIVILEGED_MODE;
}
}
/********************** SPM functions for thread mode ************************/
void tfm_spm_init(void)
{
uint32_t i, num;
struct tfm_spm_ipc_partition_t *partition;
struct tfm_spm_service_t *service;
struct tfm_thrd_ctx *pth, this_thrd;
struct spm_partition_desc_t *part;
tfm_pool_init(conn_handle_pool,
POOL_BUFFER_SIZE(conn_handle_pool),
sizeof(struct tfm_conn_handle_t),
TFM_CONN_HANDLE_MAX_NUM);
tfm_pool_init(spm_service_pool, POOL_BUFFER_SIZE(spm_service_pool),
sizeof(struct tfm_spm_service_t),
TFM_SPM_MAX_ROT_SERV_NUM);
tfm_pool_init(msg_db_pool, POOL_BUFFER_SIZE(msg_db_pool),
sizeof(struct tfm_msg_body_t),
TFM_MSG_QUEUE_MAX_MSG_NUM);
/* Init partition first for it will be used when init service */
for (i = 0; i < SPM_MAX_PARTITIONS; i++) {
part = &g_spm_partition_db.partitions[i];
tfm_spm_hal_configure_default_isolation(part->platform_data);
g_spm_ipc_partition[i].index = i;
if ((tfm_spm_partition_get_flags(i) & SPM_PART_FLAG_IPC) == 0) {
continue;
}
g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
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);
if (!pth) {
tfm_panic();
}
tfm_thrd_init(pth,
tfm_spm_partition_get_init_func_ext(i),
NULL,
(uint8_t *)tfm_spm_partition_get_stack_top(i),
(uint8_t *)tfm_spm_partition_get_stack_bottom(i));
pth->prior = tfm_spm_partition_get_priority_ext(i);
/* Kick off */
if (tfm_thrd_start(pth) != THRD_SUCCESS) {
tfm_panic();
}
}
/* Init Service */
num = sizeof(g_spm_service_db) / sizeof(struct tfm_spm_service_db_t);
for (i = 0; i < num; i++) {
partition =
tfm_spm_get_partition_by_id(g_spm_service_db[i].partition_id);
if (!partition) {
tfm_panic();
}
service = (struct tfm_spm_service_t *)tfm_pool_alloc(spm_service_pool);
if (!service) {
tfm_panic();
}
service->service_db = &g_spm_service_db[i];
service->partition = partition;
tfm_list_init(&service->handle_list);
tfm_list_add_tail(&partition->service_list, &service->list);
}
/*
* All threads initialized, start the scheduler.
*
* NOTE:
* Here is the booting privileged thread mode, and will never
* return to this place after scheduler is started. The start
* function has to save current runtime context to act as a
* 'current thread' to avoid repeating NULL 'current thread'
* checking while context switching. This saved context is worthy
* of being saved somewhere if there are potential usage purpose.
* Let's save this context in a local variable 'this_thrd' at
* current since there is no usage for it.
* Also set tfm_nspm_thread_entry as pfn for this thread to
* use in detecting NS/S thread scheduling changes.
*/
this_thrd.pfn = (tfm_thrd_func_t)tfm_nspm_thread_entry;
tfm_thrd_start_scheduler(&this_thrd);
}
void tfm_pendsv_do_schedule(struct tfm_state_context_ext *ctxb)
{
#if TFM_LVL == 2
struct spm_partition_desc_t *p_next_partition;
uint32_t is_privileged;
#endif
struct tfm_thrd_ctx *pth_next = tfm_thrd_next_thread();
struct tfm_thrd_ctx *pth_curr = tfm_thrd_curr_thread();
if (pth_curr != pth_next) {
#if TFM_LVL == 2
p_next_partition = TFM_GET_CONTAINER_PTR(pth_next,
struct spm_partition_desc_t,
sp_thrd);
if (p_next_partition->static_data.partition_flags &
SPM_PART_FLAG_PSA_ROT) {
is_privileged = TFM_PARTITION_PRIVILEGED_MODE;
} else {
is_privileged = TFM_PARTITION_UNPRIVILEGED_MODE;
}
tfm_spm_partition_change_privilege(is_privileged);
#endif
/* Increase the secure lock, if we enter secure from non-secure */
if ((void *)pth_curr->pfn == (void *)tfm_nspm_thread_entry) {
++tfm_secure_lock;
}
/* Decrease the secure lock, if we return from secure to non-secure */
if ((void *)pth_next->pfn == (void *)tfm_nspm_thread_entry) {
--tfm_secure_lock;
}
tfm_thrd_context_switch(ctxb, pth_curr, pth_next);
}
}

View File

@ -1,181 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_arch_v8m.h"
#include "tfm_thread.h"
#include "tfm_utils.h"
#include "tfm_memory_utils.h"
#include "tfm_svc.h"
#include "spm_api.h"
/* Force ZERO in case ZI(bss) clear is missing */
static struct tfm_thrd_ctx *p_thrd_head = NULL;
static struct tfm_thrd_ctx *p_runn_head = NULL;
static struct tfm_thrd_ctx *p_curr_thrd = NULL;
/* Define Macro to fetch global to support future expansion (PERCPU e.g.) */
#define LIST_HEAD p_thrd_head
#define RUNN_HEAD p_runn_head
#define CURR_THRD p_curr_thrd
static struct tfm_thrd_ctx *find_next_running_thread(struct tfm_thrd_ctx *pth)
{
while (pth && pth->status != THRD_STAT_RUNNING) {
pth = pth->next;
}
return pth;
}
/* To get next running thread for scheduler */
struct tfm_thrd_ctx *tfm_thrd_next_thread(void)
{
/*
* First RUNNING thread has highest priority since threads are sorted with
* priority.
*/
return find_next_running_thread(RUNN_HEAD);
}
/* To get current thread for caller */
struct tfm_thrd_ctx *tfm_thrd_curr_thread()
{
return CURR_THRD;
}
/* Insert a new thread into list by descending priority (Highest at head) */
static void insert_by_prior(struct tfm_thrd_ctx **head,
struct tfm_thrd_ctx *node)
{
if (*head == NULL || (node->prior <= (*head)->prior)) {
node->next = *head;
*head = node;
} else {
struct tfm_thrd_ctx *iter = *head;
while (iter->next && (node->prior > iter->next->prior)) {
iter = iter->next;
}
node->next = iter->next;
iter->next = node;
}
}
/*
* Set first running thread as head to reduce enumerate
* depth while searching for a first running thread.
*/
static void update_running_head(struct tfm_thrd_ctx **runn,
struct tfm_thrd_ctx *node)
{
if ((node->status == THRD_STAT_RUNNING) &&
(*runn == NULL || (node->prior < (*runn)->prior))) {
*runn = node;
} else {
*runn = find_next_running_thread(LIST_HEAD);
}
}
/* Set context members only. No validation here */
void tfm_thrd_init(struct tfm_thrd_ctx *pth,
tfm_thrd_func_t pfn, void *param,
uint8_t *sp_base, uint8_t *sp_top)
{
pth->prior = THRD_PRIOR_MEDIUM;
pth->status = THRD_STAT_CREATING;
pth->pfn = pfn;
pth->param = param;
pth->sp_base = sp_base;
pth->sp_top = sp_top;
}
uint32_t tfm_thrd_start(struct tfm_thrd_ctx *pth)
{
/* Validate parameters before really start */
if ((pth->status != THRD_STAT_CREATING) ||
(pth->pfn == NULL) ||
(pth->sp_base == NULL) ||
(pth->sp_top == NULL)) {
return THRD_ERR_INVALID_PARAM;
}
/* Thread management runs in handler mode; set context for thread mode. */
tfm_initialize_context(&pth->state_ctx,
(uint32_t)pth->param, (uint32_t)pth->pfn,
(uint32_t)pth->sp_base, (uint32_t)pth->sp_top);
/* Insert a new thread with priority */
insert_by_prior(&LIST_HEAD, pth);
/* Mark it as RUNNING after insertion */
tfm_thrd_set_status(pth, THRD_STAT_RUNNING);
return THRD_SUCCESS;
}
void tfm_thrd_set_status(struct tfm_thrd_ctx *pth, uint32_t new_status)
{
TFM_ASSERT(pth != NULL && new_status < THRD_STAT_INVALID);
pth->status = new_status;
update_running_head(&RUNN_HEAD, pth);
}
/* Scheduling won't happen immediately but after the exception returns */
void tfm_thrd_activate_schedule(void)
{
tfm_trigger_pendsv();
}
void tfm_thrd_start_scheduler(struct tfm_thrd_ctx *pth)
{
/*
* There is no selected thread before scheduler start, assign
* a caller provided thread as current thread. This function
* should get called only ONCE; further calling triggers assert.
*/
TFM_ASSERT(CURR_THRD == NULL);
TFM_ASSERT(pth != NULL);
CURR_THRD = pth;
tfm_thrd_activate_schedule();
}
/* Remove current thread out of the schedulable list */
void tfm_svcall_thrd_exit(void)
{
CURR_THRD->status = THRD_STAT_DETACH;
tfm_trigger_pendsv();
}
__attribute__((section("SFN")))
void tfm_thrd_exit(void)
{
SVC(TFM_SVC_EXIT_THRD);
while (1) {
;
}
}
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
struct tfm_thrd_ctx *prev,
struct tfm_thrd_ctx *next)
{
TFM_ASSERT(prev != NULL);
TFM_ASSERT(next != NULL);
/*
* First, update latest context into the current thread context.
* Then, update background context with next thread's context.
*/
tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
/* Update current thread indicator */
CURR_THRD = next;
}

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <inttypes.h>
#include <stdio.h>
#include "tfm_utils.h"
void tfm_panic(void)
{
while (1)
;
}
int32_t tfm_bitcount(uint32_t n)
{
int32_t count = 0;
uint8_t tmp;
while (n) {
tmp = n & 0xFF;
while (tmp) {
count += tmp & 0x1;
tmp >>= 1;
}
n >>= 8;
}
return count;
}

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "tfm_thread.h"
#include "tfm_utils.h"
#include "tfm_wait.h"
void tfm_event_wait(struct tfm_event_t *pevnt)
{
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
pevnt->owner = tfm_thrd_curr_thread();
tfm_thrd_set_status(pevnt->owner, THRD_STAT_BLOCK);
tfm_thrd_activate_schedule();
}
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval)
{
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
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();
}
}

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SECURE_UTILITIES_H__
#define __SECURE_UTILITIES_H__
#include <stdio.h>
#include "cmsis_compiler.h"
#include "tfm_svc.h"
#define EXC_RETURN_INDICATOR (0xF << 28)
#define EXC_RETURN_SECURITY_STACK_STATUS_MASK (0x3 << 5)
#define EXC_RETURN_SECURE_STACK (1 << 6)
#define EXC_RETURN_FPU_FRAME_BASIC (1 << 4)
#define EXC_RETURN_MODE_THREAD (1 << 3)
#define EXC_RETURN_STACK_PROCESS (1 << 2)
#define EXC_RETURN_EXC_SECURE (1)
#define EXC_NUM_THREAD_MODE (0)
#define EXC_NUM_SVCALL (11)
#define EXC_NUM_PENDSV (14)
#define EXC_NUM_SYSTICK (15)
#define printf(...)
/* Disable NS exceptions by setting NS PRIMASK to 1 */
#define TFM_NS_EXC_DISABLE() __TZ_set_PRIMASK_NS(1)
/* Enable NS exceptions by setting NS PRIMASK to 0 */
#define TFM_NS_EXC_ENABLE() __TZ_set_PRIMASK_NS(0)
struct tfm_exc_stack_t {
uint32_t R0;
uint32_t R1;
uint32_t R2;
uint32_t R3;
uint32_t R12;
uint32_t LR;
uint32_t RetAddr;
uint32_t XPSR;
};
#ifdef TFM_CORE_DEBUG
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
#else
/* FixMe: redirect to secure log area */
#define LOG_MSG_HDLR(MSG) printf("[Sec Handler] %s\r\n", MSG)
#endif
#define LOG_MSG_THR(MSG) \
__ASM volatile("MOV r0, %0\n" \
"SVC %1\n" \
: : "r" (MSG), "I" (TFM_SVC_PRINT))
#define LOG_MSG(MSG) \
do { \
if (__get_active_exc_num()) { \
LOG_MSG_HDLR(MSG); \
} else { \
LOG_MSG_THR(MSG); \
} \
} while (0)
#ifdef TFM_CORE_DEBUG
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
#else
/* FixMe: redirect to secure log area */
#define ERROR_MSG(MSG) printf("[Sec Error] %s\r\n", MSG)
#endif
/**
* \brief Get Link Register
* \details Returns the value of the Link Register (LR)
* \return LR value
*/
__attribute__ ((always_inline)) __STATIC_INLINE uint32_t __get_LR(void)
{
register uint32_t result;
__ASM volatile ("MOV %0, LR\n" : "=r" (result));
return result;
}
__attribute__ ((always_inline))
__STATIC_INLINE uint32_t __get_active_exc_num(void)
{
IPSR_Type IPSR;
/* if non-zero, exception is active. NOT banked S/NS */
IPSR.w = __get_IPSR();
return IPSR.b.ISR;
}
__attribute__ ((always_inline))
__STATIC_INLINE void __set_CONTROL_SPSEL(uint32_t SPSEL)
{
CONTROL_Type ctrl;
ctrl.w = __get_CONTROL();
ctrl.b.SPSEL = SPSEL;
__set_CONTROL(ctrl.w);
__ISB();
}
#endif /* __SECURE_UTILITIES_H__ */

View File

@ -1,158 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdint.h>
#include "bl2/include/tfm_boot_status.h"
#include "tfm_memory_utils.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "flash_layout.h"
#include "secure_fw/spm/spm_api.h"
#ifdef TFM_PSA_API
#include "tfm_internal_defines.h"
#include "tfm_utils.h"
#include "psa_service.h"
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_spm.h"
#endif
/*!
* \def BOOT_DATA_VALID
*
* \brief Indicates that shared data between bootloader and runtime firmware was
* passed the sanity check with success.
*/
#define BOOT_DATA_VALID (1u)
/*!
* \def BOOT_DATA_INVALID
*
* \brief Indicates that shared data between bootloader and runtime firmware was
* failed on sanity check.
*/
#define BOOT_DATA_INVALID (0u)
/*!
* \var is_boot_data_valid
*
* \brief Indicates the status of shared data between bootloader and runtime
* firmware
*/
static uint32_t is_boot_data_valid = BOOT_DATA_INVALID;
void tfm_core_validate_boot_data(void)
{
struct tfm_boot_data *boot_data;
boot_data = (struct tfm_boot_data *)BOOT_TFM_SHARED_DATA_BASE;
/* FixMe: Enhance sanity check of shared memory area, it might be invalid:
* - temporal exposure of RAM to non-secure actors
* - mismatched addresses
* - version mismatch between bootloader and runtime binary
* - etc.
*/
if (boot_data->header.tlv_magic == SHARED_DATA_TLV_INFO_MAGIC) {
is_boot_data_valid = BOOT_DATA_VALID;
}
}
void tfm_core_get_boot_data_handler(uint32_t args[])
{
uint8_t tlv_major = (uint8_t)args[0];
uint8_t *buf_start = (uint8_t *)args[1];
uint16_t buf_size = (uint16_t)args[2];
uint8_t *ptr;
struct tfm_boot_data *boot_data;
struct shared_data_tlv_entry tlv_entry;
uintptr_t tlv_end, offset;
#ifndef TFM_PSA_API
uint32_t running_partition_idx =
tfm_spm_partition_get_running_partition_idx();
uint32_t res;
#else
struct tfm_spm_ipc_partition_t *partition = NULL;
uint32_t privileged;
#endif
#ifndef TFM_PSA_API
/* Make sure that the output pointer points to a memory area that is owned
* by the partition
*/
res = tfm_core_check_buffer_access(running_partition_idx,
(void *)buf_start,
buf_size,
2); /* Check 4 bytes alignment */
if (!res) {
/* Not in accessible range, return error */
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
#else
partition = tfm_spm_get_running_partition();
if (!partition) {
tfm_panic();
}
privileged = tfm_spm_partition_get_privileged_mode(partition->index);
if (tfm_memory_check(buf_start, buf_size, false, TFM_MEMORY_ACCESS_RW,
privileged) != IPC_SUCCESS) {
/* Not in accessible range, return error */
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
#endif
/* FixMe: Check whether caller has access right to given tlv_major_type */
if (is_boot_data_valid != BOOT_DATA_VALID) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
/* Get the boundaries of TLV section */
boot_data = (struct tfm_boot_data *)BOOT_TFM_SHARED_DATA_BASE;
tlv_end = BOOT_TFM_SHARED_DATA_BASE + boot_data->header.tlv_tot_len;
offset = BOOT_TFM_SHARED_DATA_BASE + SHARED_DATA_HEADER_SIZE;
/* Add header to output buffer as well */
if (buf_size < SHARED_DATA_HEADER_SIZE) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
} else {
boot_data = (struct tfm_boot_data *)buf_start;
boot_data->header.tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
boot_data->header.tlv_tot_len = SHARED_DATA_HEADER_SIZE;
ptr = boot_data->data;
}
/* 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) {
/* 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) {
args[0] = TFM_ERROR_INVALID_PARAMETER;
return;
}
tfm_memcpy(ptr, (const void *)offset, tlv_entry.tlv_len);
ptr += tlv_entry.tlv_len;
boot_data->header.tlv_tot_len += tlv_entry.tlv_len;
}
}
args[0] = TFM_SUCCESS;
return;
}

View File

@ -1,234 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include "region_defs.h"
#include "tfm_core.h"
#include "tfm_internal.h"
#include "tfm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "secure_utilities.h"
#include "secure_fw/spm/spm_api.h"
#include "secure_fw/include/tfm_spm_services_api.h"
#ifdef TFM_PSA_API
#include "psa_client.h"
#include "psa_service.h"
#include "tfm_thread.h"
#include "tfm_wait.h"
#include "tfm_message_queue.h"
#include "tfm_spm.h"
#endif
/*
* Avoids the semihosting issue
* FixMe: describe 'semihosting issue'
*/
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
__asm(" .global __ARM_use_no_argv\n");
#endif
#if defined ( __GNUC__ )
/* The macro cmse_nsfptr_create defined in the gcc library uses the non-standard
* gcc C lanuage extension 'typeof'. TF-M is built with '-std=c99' so typeof
* cannot be used in the code. As a workaround cmse_nsfptr_create is redefined
* here to use only standard language elements. */
#undef cmse_nsfptr_create
#define cmse_nsfptr_create(p) ((intptr_t) (p) & ~1)
#endif
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
#if (TFM_LVL != 1) && (TFM_LVL != 2) && (TFM_LVL != 3)
#error Only TFM_LVL 1, 2 and 3 are supported!
#endif
#ifndef TFM_PSA_API
/* Macros to pick linker symbols and allow to form the partition data base */
#define REGION(a, b, c) a##b##c
#define REGION_NAME(a, b, c) REGION(a, b, c)
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif
void configure_ns_code(void)
{
/* SCB_NS.VTOR points to the Non-secure vector table base address */
SCB_NS->VTOR = tfm_spm_hal_get_ns_VTOR();
/* Setups Main stack pointer of the non-secure code */
uint32_t ns_msp = tfm_spm_hal_get_ns_MSP();
__TZ_set_MSP_NS(ns_msp);
/* Get the address of non-secure code entry point to jump there */
uint32_t entry_ptr = tfm_spm_hal_get_ns_entry_point();
/* Clears LSB of the function address to indicate the function-call
* will perform the switch from secure to non-secure
*/
ns_entry = (nsfptr_t) cmse_nsfptr_create(entry_ptr);
}
int32_t tfm_core_init(void)
{
/* Enables fault handlers */
enable_fault_handlers();
/* Configures the system reset request properties */
system_reset_cfg();
/* Configures debug authentication */
tfm_spm_hal_init_debug();
__enable_irq();
LOG_MSG("Secure image initializing!");
#ifdef TFM_CORE_DEBUG
printf("TFM level is: %d\r\n", TFM_LVL);
#endif
tfm_core_validate_boot_data();
tfm_spm_hal_init_isolation_hw();
configure_ns_code();
/* Configures all interrupts to retarget NS state, except for
* secure peripherals
*/
nvic_interrupt_target_state_cfg();
/* Enable secure peripherals interrupts */
nvic_interrupt_enable();
#ifdef TFM_PSA_API
/* FixMe: In case of IPC messaging, scratch area must not be referenced
* These variables should be removed when all obsolete references are
* removed from the codebase
*/
tfm_scratch_area = NULL;
tfm_scratch_area_size = 0;
#else
tfm_scratch_area =
(uint8_t *)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
tfm_scratch_area_size =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit) -
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
#endif
return 0;
}
static int32_t tfm_core_set_secure_exception_priorities(void)
{
uint32_t VECTKEY;
SCB_Type *scb = SCB;
uint32_t AIRCR;
/* Set PRIS flag is AIRCR */
AIRCR = scb->AIRCR;
VECTKEY = (~AIRCR & SCB_AIRCR_VECTKEYSTAT_Msk);
scb->AIRCR = SCB_AIRCR_PRIS_Msk |
VECTKEY |
(AIRCR & ~SCB_AIRCR_VECTKEY_Msk);
/* FixMe: Explicitly set secure fault and Secure SVC priority to highest */
/*
* Set secure PendSV priority to the lowest in SECURE state.
*
* IMPORTANT NOTE:
*
* Although the priority of the secure PendSV must be the lowest possible
* among other interrupts in the Secure state, it must be ensured that
* PendSV is not preempted nor masked by Non-Secure interrupts to ensure
* the integrity of the Secure operation.
* When AIRCR.PRIS is set, the Non-Secure execution can act on
* FAULTMASK_NS, PRIMASK_NS or BASEPRI_NS register to boost its priority
* number up to the value 0x80.
* For this reason, set the priority of the PendSV interrupt to the next
* priority level configurable on the platform, just below 0x80.
*/
NVIC_SetPriority(PendSV_IRQn, (1 << (__NVIC_PRIO_BITS - 1)) - 1);
return TFM_SUCCESS;
}
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx)
{
uint32_t *res_ptr = (uint32_t *)&svc_ctx->R0;
/* FixMe: check if caller partition is permitted to make an SPM request */
switch (svc_ctx->R0) {
case TFM_SPM_REQUEST_RESET_VOTE:
/* FixMe: this is a placeholder for checks to be performed before
* allowing execution of reset
*/
*res_ptr = TFM_SUCCESS;
break;
default:
*res_ptr = TFM_ERROR_INVALID_PARAMETER;
}
}
int main(void)
{
if (tfm_core_init() != 0) {
/* Placeholder for error handling, currently ignored. */
}
if (tfm_spm_db_init() != SPM_ERR_OK) {
/* Placeholder for error handling, currently ignored. */
}
tfm_spm_hal_setup_isolation_hw();
#ifndef TFM_PSA_API
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_RUNNING);
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
__set_PSPLIM(psp_stack_bottom);
if (tfm_spm_partition_init() != SPM_ERR_OK) {
/* Certain systems might refuse to boot altogether if partitions fail
* to initialize. This is a placeholder for such an error handler
*/
}
/*
* Prioritise secure exceptions to avoid NS being able to pre-empt
* secure SVC or SecureFault. Do it before PSA API initialization.
*/
tfm_core_set_secure_exception_priorities();
/* We close the TFM_SP_CORE_ID partition, because its only purpose is
* to be able to pass the state checks for the tests started from secure.
*/
tfm_spm_partition_set_state(TFM_SP_CORE_ID, SPM_PARTITION_STATE_CLOSED);
tfm_spm_partition_set_state(TFM_SP_NON_SECURE_ID,
SPM_PARTITION_STATE_RUNNING);
#ifdef TFM_CORE_DEBUG
/* Jumps to non-secure code */
LOG_MSG("Jumping to non-secure code...");
#endif
jump_to_ns_code();
#else
/*
* Prioritise secure exceptions to avoid NS being able to pre-empt
* secure SVC or SecureFault. Do it before PSA API initialization.
*/
tfm_core_set_secure_exception_priorities();
tfm_spm_init();
#endif
}

View File

@ -1,18 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_CORE_H__
#define __TFM_CORE_H__
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "secure_utilities.h"
extern uint32_t tfm_scratch_area_size;
extern uint8_t *tfm_scratch_area;
#endif /* __TFM_CORE_H__ */

View File

@ -1,224 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <string.h>
#include "secure_utilities.h"
#include "tfm_svc.h"
#include "tfm_secure_api.h"
#include "region_defs.h"
#include "tfm_api.h"
#include "tfm_internal.h"
#include "tfm_memory_utils.h"
#ifdef TFM_PSA_API
#include <stdbool.h>
#include "tfm_svcalls.h"
#endif
/* This SVC handler is called when a secure partition requests access to a
* buffer area
*/
extern int32_t tfm_core_set_buffer_area_handler(const uint32_t args[]);
#ifdef TFM_PSA_API
extern void tfm_psa_ipc_request_handler(const uint32_t svc_args[]);
#endif
struct tfm_fault_context_s {
uint32_t R0;
uint32_t R1;
uint32_t R2;
uint32_t R3;
uint32_t R12;
uint32_t LR;
uint32_t ReturnAddress;
uint32_t RETPSR;
} tfm_fault_context;
#if defined(__ARM_ARCH_8M_MAIN__)
/**
* \brief Overwrites default Secure fault handler.
*/
void SecureFault_Handler(void)
{
/* figure out context from which we landed in fault handler */
uint32_t lr = __get_LR();
uint32_t sp;
if (lr & EXC_RETURN_SECURE_STACK) {
if (lr & EXC_RETURN_STACK_PROCESS) {
sp = __get_PSP();
} else {
sp = __get_MSP();
}
} else {
if (lr & EXC_RETURN_STACK_PROCESS) {
sp = __TZ_get_PSP_NS();
} else {
sp = __TZ_get_MSP_NS();
}
}
/* Only save the context if sp is valid */
if ((sp >= S_DATA_START &&
sp <= (S_DATA_LIMIT - sizeof(tfm_fault_context)) + 1) ||
(sp >= NS_DATA_START &&
sp <= (NS_DATA_LIMIT - sizeof(tfm_fault_context)) + 1)) {
tfm_memcpy(&tfm_fault_context,
(const void *)sp,
sizeof(tfm_fault_context));
}
LOG_MSG("Oops... Secure fault!!! You're not going anywhere!");
while (1) {
;
}
}
#elif defined(__ARM_ARCH_8M_BASE__)
/**
* \brief Overwrites default Hard fault handler.
*
* In case of a baseline implementation fault conditions that would generate a
* SecureFault in a mainline implementation instead generate a Secure HardFault.
*/
void HardFault_Handler(void)
{
/* In a baseline implementation there is no way, to find out whether this is
* a hard fault triggered directly, or another fault that has been
* escalated.
*/
while (1) {
;
}
}
#else
#error "Unsupported ARM Architecture."
#endif
#if defined(__ARM_ARCH_8M_MAIN__)
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
"TST lr, #4\n" /* Check store SP in thread mode to r0 */
"IT EQ\n"
"BXEQ lr\n"
"MRS r0, PSP\n"
"MOV r1, lr\n"
"BL SVCHandler_main\n"
"BX r0\n"
);
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) void SVC_Handler(void)
{
__ASM volatile(
".syntax unified\n"
"MOVS r0, #4\n" /* Check store SP in thread mode to r0 */
"MOV r1, lr\n"
"TST r0, r1\n"
"BEQ handler\n"
"MRS r0, PSP\n" /* Coming from thread mode */
"B sp_stored\n"
"handler:\n"
"BX lr\n" /* Coming from handler mode */
"sp_stored:\n"
"MOV r1, lr\n"
"BL SVCHandler_main\n"
"BX r0\n"
);
}
#else
#error "Unsupported ARM Architecture."
#endif
uint32_t SVCHandler_main(uint32_t *svc_args, uint32_t lr)
{
uint8_t svc_number;
/*
* Stack contains:
* r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
* First argument (r0) is svc_args[0]
*/
if (lr & EXC_RETURN_SECURE_STACK) {
/* SV called directly from secure context. Check instruction for
* svc_number
*/
svc_number = ((uint8_t *)svc_args[6])[-2];
} else {
/* Secure SV executing with NS return.
* NS cannot directly trigger S SVC so this should not happen
* FixMe: check for security implications
*/
return lr;
}
switch (svc_number) {
#ifdef TFM_PSA_API
case TFM_SVC_IPC_REQUEST:
tfm_psa_ipc_request_handler(svc_args);
break;
case TFM_SVC_SCHEDULE:
case TFM_SVC_EXIT_THRD:
case TFM_SVC_PSA_FRAMEWORK_VERSION:
case TFM_SVC_PSA_VERSION:
case TFM_SVC_PSA_CONNECT:
case TFM_SVC_PSA_CALL:
case TFM_SVC_PSA_CLOSE:
case TFM_SVC_PSA_WAIT:
case TFM_SVC_PSA_GET:
case TFM_SVC_PSA_SET_RHANDLE:
case TFM_SVC_PSA_READ:
case TFM_SVC_PSA_SKIP:
case TFM_SVC_PSA_WRITE:
case TFM_SVC_PSA_REPLY:
case TFM_SVC_PSA_NOTIFY:
case TFM_SVC_PSA_CLEAR:
case TFM_SVC_PSA_EOI:
svc_args[0] = SVC_Handler_IPC(svc_number, svc_args, lr);
break;
#else
case TFM_SVC_SFN_REQUEST:
lr = tfm_core_partition_request_svc_handler(svc_args, lr);
break;
case TFM_SVC_SFN_RETURN:
lr = tfm_core_partition_return_handler(lr);
break;
case TFM_SVC_VALIDATE_SECURE_CALLER:
tfm_core_validate_secure_caller_handler(svc_args);
break;
case TFM_SVC_GET_CALLER_CLIENT_ID:
tfm_core_get_caller_client_id_handler(svc_args);
break;
case TFM_SVC_SPM_REQUEST:
tfm_core_spm_request_handler((struct tfm_exc_stack_t *)svc_args);
break;
case TFM_SVC_MEMORY_CHECK:
tfm_core_memory_permission_check_handler(svc_args);
break;
case TFM_SVC_SET_SHARE_AREA:
tfm_core_set_buffer_area_handler(svc_args);
break;
#endif
case TFM_SVC_PRINT:
printf("\e[1;34m[Sec Thread] %s\e[0m\r\n", (char *)svc_args[0]);
break;
case TFM_SVC_GET_BOOT_DATA:
tfm_core_get_boot_data_handler(svc_args);
break;
default:
LOG_MSG("Unknown SVC number requested!");
break;
}
return lr;
}
void tfm_access_violation_handler(void)
{
while (1) {
;
}
}

View File

@ -1,100 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "secure_utilities.h"
#ifndef __TFM_INTERNAL_H__
#define __TFM_INTERNAL_H__
/*
* This function pointer is meant to only hold non secure function pointers.
* It will be turned into a non-secure one (LSB cleared) before being called
* whatever happens anyway (unless cast to another function pointer type).
* Registers will be cleared before branching so that no information leaks
* from secure to non-secure world.
*/
typedef void __attribute__((cmse_nonsecure_call)) (*nsfptr_t) (void);
extern nsfptr_t ns_entry;
/**
* \brief Signal that secure partition initialisation is finished
*/
void tfm_secure_api_init_done(void);
/**
* \brief Jumps to non-secure code.
*/
void jump_to_ns_code(void);
/**
* \brief Called if veneer is running in thread mode
*/
uint32_t tfm_core_partition_request_svc_handler(
const uint32_t *svc_args, uint32_t lr);
/**
* \brief Called when secure service returns
*/
uint32_t tfm_core_partition_return_handler(uint32_t lr);
/**
* \brief Called by secure service to check if client is secure
*/
void tfm_core_validate_secure_caller_handler(const uint32_t svc_args[]);
/**
* \brief Stores caller's client id in state context
*/
void tfm_core_get_caller_client_id_handler(const uint32_t svc_args[]);
/**
* \brief Checks if a secure service's access to a memory location is permitted
*/
void tfm_core_memory_permission_check_handler(const uint32_t svc_args[]);
/**
* \brief Handle an SPM request by a secure service
*/
void tfm_core_spm_request_handler(const struct tfm_exc_stack_t *svc_ctx);
/**
* \brief Check whether a buffer is ok for writing to by the privileged API
* function.
*
* This function checks whether the caller partition owns the buffer, can write
* to it, and the buffer has proper alignment.
*
* \param[in] partition_idx Partition index
* \param[in] start_addr The start address of the buffer
* \param[in] len The length of the buffer
* \param[in] alignment The expected alignment (in bits)
*
* \return 1 if the check passes, 0 otherwise.
*
* \note For a 0 long buffer the check fails.
*/
int32_t tfm_core_check_buffer_access(uint32_t partition_idx,
void *start_addr,
size_t len,
uint32_t alignment);
/**
* \brief Retrieve secure partition related data from shared memory area, which
* stores shared data between bootloader and runtime firmware.
*
* \param[in] args Pointer to stack frame, which carries input parameters.
*/
void tfm_core_get_boot_data_handler(uint32_t args[]);
/**
* \brief Validate the content of shared memory area, which stores the shared
* data between bootloader and runtime firmware.
*/
void tfm_core_validate_boot_data(void);
#endif /* __TFM_INTERNAL_H__ */

View File

@ -1,45 +0,0 @@
/*
* 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 <string.h>
#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__ */

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <stdbool.h>
#include "secure_utilities.h"
#include "tfm_api.h"
#ifdef TFM_PSA_API
#include "tfm_utils.h"
#include "tfm_internal.h"
#endif
#ifndef TFM_MAX_NS_THREAD_COUNT
#define TFM_MAX_NS_THREAD_COUNT 8
#endif
#define INVALID_CLIENT_ID 0
#define DEFAULT_NS_CLIENT_ID ((int32_t)-1)
#define INVALID_NS_CLIENT_IDX (-1)
#define DEFAULT_NS_CLIENT_IDX 0
typedef uint32_t TZ_ModuleId_t;
typedef uint32_t TZ_MemoryId_t;
static struct ns_client_list_t {
int32_t ns_client_id;
int32_t next_free_index;
} NsClientIdList[TFM_MAX_NS_THREAD_COUNT];
static int32_t free_index = 0U;
static int32_t active_ns_client_idx = INVALID_NS_CLIENT_IDX;
static int get_next_ns_client_id()
{
#ifdef TFM_NS_CLIENT_IDENTIFICATION
static int32_t next_ns_client_id = DEFAULT_NS_CLIENT_ID;
if (next_ns_client_id > 0)
{
next_ns_client_id = DEFAULT_NS_CLIENT_ID;
}
return next_ns_client_id--;
#else
return DEFAULT_NS_CLIENT_ID;
#endif
}
void tfm_nspm_configure_clients(void)
{
int32_t i;
/* Default to one NS client */
free_index = 1;
NsClientIdList[0].ns_client_id = get_next_ns_client_id();
for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
}
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
}
int32_t tfm_nspm_get_current_client_id()
{
if (active_ns_client_idx == INVALID_NS_CLIENT_IDX)
{
return 0;
} else {
return NsClientIdList[active_ns_client_idx].ns_client_id;
}
}
/* TF-M implementation of the CMSIS TZ RTOS thread context management API */
/// Initialize secure context memory system
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_InitContextSystem_S(void)
{
int32_t i;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
/* NS RTOS supports TZ context management, override defaults */
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("NS RTOS initialized TZ RTOS context management");
#endif /* PRINT_NSPM_DEBUG */
for (i = 1; i < TFM_MAX_NS_THREAD_COUNT; ++i) {
NsClientIdList[i].ns_client_id = INVALID_CLIENT_ID;
NsClientIdList[i].next_free_index = i + 1;
}
/* Terminate list */
NsClientIdList[i - 1].next_free_index = INVALID_NS_CLIENT_IDX;
/* Success */
return 1U;
}
/// Allocate context memory for calling secure software modules in TrustZone
/// \param[in] module identifies software modules called from non-secure mode
/// \return value != 0 id TrustZone memory slot identifier
/// \return value 0 no memory available or internal error
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
TZ_MemoryId_t TZ_AllocModuleContext_S (TZ_ModuleId_t module)
{
TZ_MemoryId_t tz_id;
(void) module; /* Currently unused */
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
if (free_index < 0) {
/* No more free slots */
return 0U;
}
/* TZ_MemoryId_t must be a positive integer */
tz_id = (TZ_MemoryId_t)free_index + 1;
NsClientIdList[free_index].ns_client_id = get_next_ns_client_id();
#ifdef PRINT_NSPM_DEBUG
printf("TZ_AllocModuleContext_S called, returning id %d\r\n",
NsClientIdList[free_index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
free_index = NsClientIdList[free_index].next_free_index;
return tz_id;
}
/// Free context memory that was previously allocated with \ref TZ_AllocModuleContext_S
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_FreeModuleContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
printf("TZ_FreeModuleContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
if (active_ns_client_idx == index) {
#ifdef PRINT_NSPM_DEBUG
printf("Freeing active NS client, NS inactive\r\n");
#endif /* PRINT_NSPM_DEBUG */
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
}
NsClientIdList[index].ns_client_id = INVALID_CLIENT_ID;
NsClientIdList[index].next_free_index = free_index;
free_index = index;
return 1U; // Success
}
/// Load secure context (called on RTOS thread context switch)
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_LoadContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("TZ_LoadContext_S called");
#endif /* PRINT_NSPM_DEBUG */
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
active_ns_client_idx = index;
#ifdef PRINT_NSPM_DEBUG
printf("TZ_LoadContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return 1U; // Success
}
/// Store secure context (called on RTOS thread context switch)
/// \param[in] id TrustZone memory slot identifier
/// \return execution status (1: success, 0: error)
/* This veneer is TF-M internal, not a secure service */
__attribute__((cmse_nonsecure_entry))
uint32_t TZ_StoreContext_S (TZ_MemoryId_t id)
{
uint32_t index;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
LOG_MSG("TZ_StoreContext_S called");
#endif /* PRINT_NSPM_DEBUG */
/* id corresponds to context being swapped out on NS side */
if ((id == 0U) || (id > TFM_MAX_NS_THREAD_COUNT)) {
/* Invalid TZ_MemoryId_t */
return 0U;
}
index = id - 1;
if (NsClientIdList[index].ns_client_id == INVALID_CLIENT_ID) {
/* Non-existent client */
return 0U;
}
if (active_ns_client_idx != index) {
#ifdef PRINT_NSPM_DEBUG
printf("TZ_StoreContext_S called for id %d, active id: %d\r\n",
NsClientIdList[index].ns_client_id,
NsClientIdList[active_ns_client_idx].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return 0U;
}
#ifdef PRINT_NSPM_DEBUG
printf("TZ_StoreContext_S called for id %d\r\n",
NsClientIdList[index].ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
active_ns_client_idx = DEFAULT_NS_CLIENT_IDX;
return 1U; // Success
}
#ifdef TFM_NS_CLIENT_IDENTIFICATION
__attribute__((cmse_nonsecure_entry))
enum tfm_status_e tfm_register_client_id (int32_t ns_client_id)
{
int current_client_id;
if (__get_active_exc_num() == EXC_NUM_THREAD_MODE) {
/* This veneer should only be called by NS RTOS in handler mode */
return TFM_ERROR_NS_THREAD_MODE_CALL;
}
if (ns_client_id >= 0) {
/* The client ID is invalid */
return TFM_ERROR_INVALID_PARAMETER;
}
if (active_ns_client_idx < 0) {
/* No client is active */
return TFM_ERROR_GENERIC;
}
current_client_id = NsClientIdList[active_ns_client_idx].ns_client_id;
if (current_client_id >= 0 ) {
/* The client ID is invalid */
return TFM_ERROR_INVALID_PARAMETER;
}
NsClientIdList[active_ns_client_idx].ns_client_id = ns_client_id;
#ifdef PRINT_NSPM_DEBUG
printf("tfm_register_client_id called with id %d\r\n", ns_client_id);
#endif /* PRINT_NSPM_DEBUG */
return TFM_SUCCESS;
}
#endif
#ifdef TFM_PSA_API
__attribute__((section("SFN")))
psa_status_t tfm_nspm_thread_entry(void)
{
#ifdef TFM_CORE_DEBUG
/* Jumps to non-secure code */
LOG_MSG("Jumping to non-secure code...");
#endif
jump_to_ns_code();
/* Should not run here */
TFM_ASSERT(false);
return PSA_SUCCESS;
}
#endif

View File

@ -1,37 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_NSPM_H__
#define __TFM_NSPM_H__
#include <stdint.h>
/**
* \brief initialise the NS context database
*/
void tfm_nspm_configure_clients(void);
/**
* \brief Get the client ID of the current NS client
*
* \return The client id of the current NS client. 0 (invalid client id) is
* returned in case of error.
*/
int32_t tfm_nspm_get_current_client_id(void);
#ifdef TFM_PSA_API
/**
* \brief NSPM thread main entry function
*
* \return PSA_SUCCESS indicates failed.
*
* Note: This function should not return back.
*/
psa_status_t tfm_nspm_thread_entry(void);
#endif
#endif /* __TFM_NSPM_H__ */

View File

@ -1,24 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_PLATFORM_CORE_API_H__
#define __TFM_PLATFORM_CORE_API_H__
/**
* \brief Should be called in case of access violation.
*
* There might be platform specific means, by which it is possible on a
* subsystem to detect access violation. For example a platform can have a
* Peripheral Protection Controller, to detect unauthorised accesses to
* peripheral registers. Setting up the protection, and handling the violation
* is implemented in platform specific code. However TF-M should be able to
* decide how to proceed if a violation happens. So to notify TF-M, platform
* code have to call this function, if a violation happens.
*/
void tfm_access_violation_handler(void);
#endif /* __TFM_PLATFORM_CORE_API_H__ */

View File

@ -1,176 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <arm_cmse.h>
#include "tfm_secure_api.h"
#include "tfm_nspm.h"
#include "secure_utilities.h"
#include "secure_fw/spm/spm_api.h"
#include "region_defs.h"
#include "tfm_api.h"
#define EXC_RETURN_SECURE_FUNCTION 0xFFFFFFFD
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
/* 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)
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif /* !defined(TFM_PSA_API) */
/* This is the "Big Lock" on the secure side, to guarantee single entry
* to SPE
*/
int32_t tfm_secure_lock;
/**
* \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 TFM_SUCCESS if the region contains the range,
* TFM_ERROR_GENERIC 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;
/* Check for overflow in the range parameters */
if ((uintptr_t)p > UINTPTR_MAX-s) {
return TFM_ERROR_GENERIC;
}
/* 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);
if (range_in_region) {
return TFM_SUCCESS;
} else {
return TFM_ERROR_GENERIC;
}
}
/**
* \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 TFM_SUCCESS if the partition has access to the memory range,
* TFM_ERROR_GENERIC otherwise.
*/
static int32_t has_access_to_region(const void *p, size_t s, int flags)
{
int32_t range_access_allowed_by_mpu;
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
uint32_t scratch_base =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
uint32_t scratch_limit =
(uint32_t)&REGION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
#endif /* !defined(TFM_PSA_API) */
/* 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 TFM_SUCCESS;
}
#ifndef TFM_PSA_API /* Only use scratch if using veneer functions, not IPC */
/* 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) == TFM_SUCCESS) {
return TFM_SUCCESS;
}
}
#endif /* !defined(TFM_PSA_API) */
/* If all else fails, check whether the region is in the non-secure
* memory
*/
if (check_address_range(p, s, NS_CODE_START,
NS_CODE_LIMIT+1-NS_CODE_START) == TFM_SUCCESS ||
check_address_range(p, s, NS_DATA_START,
NS_DATA_LIMIT+1-NS_DATA_START) == TFM_SUCCESS) {
return TFM_SUCCESS;
} else {
return TFM_ERROR_GENERIC;
}
}
int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged)
{
int flags = CMSE_MPU_READ;
if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
flags |= CMSE_MPU_UNPRIV;
}
if (ns_caller) {
flags |= CMSE_NONSECURE;
}
return has_access_to_region(p, s, flags);
}
int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged)
{
int flags = CMSE_MPU_READWRITE;
if (privileged == TFM_PARTITION_UNPRIVILEGED_MODE) {
flags |= CMSE_MPU_UNPRIV;
}
if (ns_caller) {
flags |= CMSE_NONSECURE;
}
return has_access_to_region(p, s, flags);
}
void tfm_secure_api_error_handler(void)
{
ERROR_MSG("Security violation when calling secure API");
while (1) {
;
}
}

View File

@ -1,214 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SECURE_API_H__
#define __TFM_SECURE_API_H__
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "secure_utilities.h"
#include "tfm_core.h"
#include "tfm_api.h"
#include "bl2/include/tfm_boot_status.h"
/*!
* \def __tfm_secure_gateway_attributes__
*
* \brief Attributes for secure gateway functions
*/
#define __tfm_secure_gateway_attributes__ \
__attribute__((cmse_nonsecure_entry, noinline, section("SFN")))
/* Hide specific errors if not debugging */
#ifdef TFM_CORE_DEBUG
#define TFM_ERROR_STATUS(status) (status)
#else
#define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY)
#endif
#define TFM_SFN_API_LEGACY 0
#define TFM_SFN_API_IOVEC 1
#ifndef TFM_LVL
#error TFM_LVL is not defined!
#endif
extern void tfm_secure_api_error_handler(void);
typedef int32_t(*sfn_t)(int32_t, int32_t, int32_t, int32_t);
struct tfm_sfn_req_s {
uint32_t sp_id;
sfn_t sfn;
int32_t *args;
uint32_t caller_part_idx;
int32_t iovec_api;
uint32_t ns_caller;
};
enum tfm_buffer_share_region_e {
TFM_BUFFER_SHARE_DISABLE,
TFM_BUFFER_SHARE_NS_CODE,
TFM_BUFFER_SHARE_SCRATCH,
TFM_BUFFER_SHARE_PRIV, /* only for TCB in level 2, all in level 1 */
TFM_BUFFER_SHARE_DEFAULT,
};
enum tfm_ns_region_e {
TFM_NS_REGION_CODE = 0,
TFM_NS_REGION_DATA,
TFM_NS_REGION_VENEER,
TFM_NS_REGION_PERIPH_1,
TFM_NS_REGION_PERIPH_2,
TFM_NS_SECONDARY_IMAGE_REGION,
};
enum tfm_memory_access_e {
TFM_MEMORY_ACCESS_RO = 1,
TFM_MEMORY_ACCESS_RW = 2,
};
extern int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share);
extern int32_t tfm_core_validate_secure_caller(void);
extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
extern int32_t tfm_core_memory_permission_check(const void *ptr,
uint32_t size,
int32_t access);
extern int32_t tfm_core_get_boot_data(uint8_t major_type,
struct tfm_boot_data *boot_data,
uint32_t len);
int32_t tfm_core_sfn_request(const struct tfm_sfn_req_s *desc_ptr);
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
/**
* \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
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \return TFM_SUCCESS if the partition has access to the memory range,
* TFM_ERROR_GENERIC otherwise.
*/
int32_t tfm_core_has_read_access_to_region(const void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged);
/**
* \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
* \param[in] privileged Privileged mode or unprivileged mode:
* \ref TFM_PARTITION_UNPRIVILEGED_MODE
* \ref TFM_PARTITION_PRIVILEGED_MODE
*
* \return TFM_SUCCESS if the partition has access to the memory range,
* TFM_ERROR_GENERIC otherwise.
*/
int32_t tfm_core_has_write_access_to_region(void *p, size_t s,
uint32_t ns_caller,
uint32_t privileged);
#ifdef TFM_PSA_API
/* The following macros are only valid if secure services can be called
* using veneer functions. This is not the case if IPC messaging is enabled
*/
#define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
do { \
ERROR_MSG("Invalid TF-M configuration detected"); \
tfm_secure_api_error_handler(); \
/* This point never reached */ \
return (int32_t)TFM_ERROR_GENERIC; \
} while (0)
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
do { \
ERROR_MSG("Invalid TF-M configuration detected"); \
tfm_secure_api_error_handler(); \
/* This point never reached */ \
return (int32_t)TFM_ERROR_GENERIC; \
} while (0)
#else
#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, 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 iovec_api,
int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
{
int32_t args[4] = {arg1, arg2, arg3, arg4};
struct tfm_sfn_req_s desc, *desc_ptr = &desc;
desc.sp_id = id;
desc.sfn = (sfn_t) fn;
desc.args = args;
/*
* This preprocessor condition checks if a version of GCC smaller than
* 7.3.1 is being used to compile the code.
* These versions are affected by a bug on the cmse_nonsecure_caller
* intrinsic which returns incorrect results.
* Please check Bug 85203 on GCC Bugzilla for more information.
*/
#if defined(__GNUC__) && !defined(__ARMCC_VERSION) && \
(__GNUC__ < 7 || \
(__GNUC__ == 7 && (__GNUC_MINOR__ < 3 || \
(__GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ < 1))))
/*
* Use the fact that, if called from Non-Secure, the LSB of the return
* address is set to 0.
*/
desc.ns_caller = (uint32_t)!(
(intptr_t)__builtin_extract_return_addr(__builtin_return_address(0U))
& 1);
#else
/*
* Convert the result of cmse_nonsecure_caller from an int to a uint32_t
* to prevent using an int in the tfm_sfn_req_s structure.
*/
desc.ns_caller = (cmse_nonsecure_caller() != 0) ? 1U : 0U;
#endif /* Check for GCC compiler version smaller than 7.3.1 */
desc.iovec_api = iovec_api;
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
/* FixMe: Error severity TBD */
return TFM_ERROR_GENERIC;
} else {
#if TFM_LVL == 1
if (desc.ns_caller) {
return tfm_core_sfn_request(desc_ptr);
} else {
return tfm_core_sfn_request_thread_mode(desc_ptr);
}
#else
return tfm_core_sfn_request(desc_ptr);
#endif
}
}
#endif
#endif /* __TFM_SECURE_API_H__ */

View File

@ -1,166 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <arm_cmse.h>
#include "tfm_svc.h"
#include "tfm_secure_api.h"
#include "tfm_internal.h"
#include "secure_fw/include/tfm_spm_services_api.h"
#include "spm_api.h"
uint8_t *tfm_scratch_area;
uint32_t tfm_scratch_area_size;
nsfptr_t ns_entry;
void jump_to_ns_code(void)
{
#if TFM_LVL == 3 || ((!defined(TFM_PSA_API)) && (TFM_LVL != 1))
/* Initialization is done, set thread mode to unprivileged. */
tfm_spm_partition_change_privilege(TFM_PARTITION_UNPRIVILEGED_MODE);
#endif
/* All changes made to memory will be effective after this point */
__DSB();
__ISB();
/* Calls the non-secure Reset_Handler to jump to the non-secure binary */
ns_entry();
}
#ifndef TFM_PSA_API
#if defined(__ARM_ARCH_8M_MAIN__)
__attribute__((naked)) int32_t tfm_core_sfn_request(
const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile(
"PUSH {r4-r12, lr}\n"
"SVC %[SVC_REQ]\n"
"MOV r4, #0\n"
"MOV r5, #0\n"
"MOV r6, #0\n"
"MOV r7, #0\n"
"MOV r8, #0\n"
"MOV r9, #0\n"
"MOV r10, #0\n"
"MOV r11, #0\n"
"BLX lr\n"
"SVC %[SVC_RET]\n"
"POP {r4-r12, pc}\n"
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
#elif defined(__ARM_ARCH_8M_BASE__)
__attribute__((naked)) int32_t tfm_core_sfn_request(
const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile(
".syntax unified\n"
"PUSH {lr}\n"
"PUSH {r4-r7}\n"
"MOV r4, r8\n"
"MOV r5, r9\n"
"MOV r6, r10\n"
"MOV r7, r11\n"
"PUSH {r4-r7}\n"
"MOV r4, r12\n"
"PUSH {r4}\n"
"SVC %[SVC_REQ]\n"
"MOVS r4, #0\n"
"MOV r5, r4\n"
"MOV r6, r4\n"
"MOV r7, r4\n"
"MOV r8, r4\n"
"MOV r9, r4\n"
"MOV r10, r4\n"
"MOV r11, r4\n"
"BLX lr\n"
"SVC %[SVC_RET]\n"
"POP {r4}\n"
"MOV r12, r4\n"
"POP {r4-r7}\n"
"MOV r8, r4\n"
"MOV r9, r5\n"
"MOV r10, r6\n"
"MOV r11, r7\n"
"POP {r4-r7}\n"
"POP {pc}\n"
: : [SVC_REQ] "I" (TFM_SVC_SFN_REQUEST)
, [SVC_RET] "I" (TFM_SVC_SFN_RETURN)
: "r0");
}
#else
#error "Unsupported ARM Architecture."
#endif
__attribute__((naked))
int32_t tfm_core_memory_permission_check(const void *ptr,
uint32_t len,
int32_t access)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_MEMORY_CHECK));
}
__attribute__((naked))
int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id)
{
__ASM volatile(
"SVC %0\n"
"BX LR\n"
: : "I" (TFM_SVC_GET_CALLER_CLIENT_ID));
}
__attribute__((naked))
int32_t tfm_spm_request_reset_vote(void)
{
__ASM volatile(
"MOVS R0, %0\n"
"B tfm_spm_request\n"
: : "I" (TFM_SPM_REQUEST_RESET_VOTE));
}
__attribute__((naked))
int32_t tfm_spm_request(void)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_SPM_REQUEST));
}
__attribute__((naked))
int32_t tfm_core_validate_secure_caller(void)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_VALIDATE_SECURE_CALLER));
}
__attribute__((naked))
int32_t tfm_core_set_buffer_area(enum tfm_buffer_share_region_e share)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_SET_SHARE_AREA));
}
#endif
__attribute__((naked))
int32_t tfm_core_get_boot_data(uint8_t major_type,
struct tfm_boot_data *boot_status,
uint32_t len)
{
__ASM volatile(
"SVC %0\n"
"BX lr\n"
: : "I" (TFM_SVC_GET_BOOT_DATA));
}

View File

@ -1,49 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SVC_H__
#define __TFM_SVC_H__
#include "cmsis.h"
typedef enum {
TFM_SVC_SFN_REQUEST = 0,
TFM_SVC_SFN_RETURN,
TFM_SVC_VALIDATE_SECURE_CALLER,
TFM_SVC_GET_CALLER_CLIENT_ID,
TFM_SVC_MEMORY_CHECK,
TFM_SVC_SET_SHARE_AREA,
TFM_SVC_SPM_REQUEST,
TFM_SVC_PRINT,
TFM_SVC_GET_BOOT_DATA,
#ifdef TFM_PSA_API
TFM_SVC_IPC_REQUEST,
TFM_SVC_SCHEDULE,
TFM_SVC_EXIT_THRD,
/* PSA Client SVC */
TFM_SVC_PSA_FRAMEWORK_VERSION,
TFM_SVC_PSA_VERSION,
TFM_SVC_PSA_CONNECT,
TFM_SVC_PSA_CALL,
TFM_SVC_PSA_CLOSE,
/* PSA Service SVC */
TFM_SVC_PSA_WAIT,
TFM_SVC_PSA_GET,
TFM_SVC_PSA_SET_RHANDLE,
TFM_SVC_PSA_READ,
TFM_SVC_PSA_SKIP,
TFM_SVC_PSA_WRITE,
TFM_SVC_PSA_REPLY,
TFM_SVC_PSA_NOTIFY,
TFM_SVC_PSA_CLEAR,
TFM_SVC_PSA_EOI,
#endif
} tfm_svc_number_t;
#define SVC(code) __ASM volatile("svc %0" : : "I" (code))
#endif /* __TFM_SVC_H__ */

View File

@ -1,17 +0,0 @@
/*
* 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.
*/

View File

@ -1,22 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_SPM_SERVICES_API_H__
#define __TFM_SPM_SERVICES_API_H__
enum tfm_spm_request_type_t {
TFM_SPM_REQUEST_RESET_VOTE,
};
/**
* \brief Request a vote from SPM on a system reset
*
* \return Returns 0 if request is accepted, any other value means reject
*/
int32_t tfm_spm_request_reset_vote(void);
#endif /* __TFM_SPM_SERVICES_API_H__ */

View File

@ -1,134 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdbool.h>
#include <stdio.h>
#include "psa_client.h"
#include "psa_service.h"
#include "secure_utilities.h"
#include "tfm_secure_api.h"
#include "tfm_api.h"
#include "tfm_svcalls.h"
/* FixMe: check if this is really needed */
extern int32_t tfm_secure_lock;
__attribute__ ((always_inline)) __STATIC_INLINE
int32_t tfm_psa_veneer_sanity_check(struct tfm_sfn_req_s *desc_ptr)
{
if (desc_ptr->ns_caller) {
if (tfm_secure_lock != 0) {
/* Secure domain is already locked!
* FixMe: Decide if this is a fault or permitted in case of PSA
* API usage
*/
return TFM_ERROR_SECURE_DOMAIN_LOCKED;
}
} else {
/* Secure partition should not call a different secure partition
* using TFM PSA veneers
*/
return TFM_ERROR_INVALID_EXC_MODE;
}
return TFM_SUCCESS;
}
/* Veneer implementation */
#define TFM_CORE_NS_IPC_REQUEST_VENEER(fn, a, b, c, d) \
return tfm_core_ns_ipc_request(fn, (int32_t)a, (int32_t)b, \
(int32_t)c, (int32_t)d)
__attribute__ ((naked, section("SFN")))
static int32_t tfm_core_ipc_request(const struct tfm_sfn_req_s *desc_ptr)
{
__ASM volatile("SVC %0 \n"
"BX LR \n"
: : "I" (TFM_SVC_IPC_REQUEST));
}
__attribute__ ((always_inline)) __STATIC_INLINE
int32_t tfm_core_ns_ipc_request(void *fn, int32_t arg1, int32_t arg2,
int32_t arg3, int32_t arg4)
{
int32_t args[4] = {arg1, arg2, arg3, arg4};
struct tfm_sfn_req_s desc = {0};
desc.sfn = fn;
desc.args = args;
desc.ns_caller = cmse_nonsecure_caller();
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE)
{
/* FIXME: Proper error handling to be implemented */
return TFM_ERROR_INVALID_EXC_MODE;
} else {
return tfm_core_ipc_request(&desc);
}
}
/* FixMe: these functions need to have different attributes compared to those
* legacy veneers which may be called by secure partitions.
* They won't call legacy SFN but instead will be handlers for TF-M
*/
__tfm_secure_gateway_attributes__
uint32_t tfm_psa_framework_version_veneer(void)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_framework_version, 0, 0,
0, 0);
}
__tfm_secure_gateway_attributes__
uint32_t tfm_psa_version_veneer(uint32_t sid)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_version, sid, 0, 0, 0);
}
__tfm_secure_gateway_attributes__
psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_connect, sid,
minor_version, 0, 0);
}
__tfm_secure_gateway_attributes__
psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
const psa_invec *in_vecs,
psa_outvec *out_vecs)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_call, handle, in_vecs,
out_vecs, 0);
}
__tfm_secure_gateway_attributes__
psa_status_t tfm_psa_close_veneer(psa_handle_t handle)
{
TFM_CORE_NS_IPC_REQUEST_VENEER(tfm_svcall_psa_close, handle, 0, 0, 0);
}
void tfm_psa_ipc_request_handler(uint32_t svc_ctx[])
{
uint32_t *r0_ptr = svc_ctx;
/* The only argument to the SVC call is stored in the stacked r0 */
struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *) *r0_ptr;
if(tfm_psa_veneer_sanity_check(desc_ptr) != TFM_SUCCESS) {
/* FixMe: consider error handling - this may be critical error */
*r0_ptr = TFM_ERROR_INVALID_PARAMETER;
return;
}
/* Store SVC return value in stacked r0 */
*r0_ptr = desc_ptr->sfn((int32_t)desc_ptr->args,
desc_ptr->ns_caller,
0,
0);
return;
}

View File

@ -1,16 +0,0 @@
/*
* 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.
*/

View File

@ -1,416 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
/* This file contains the APIs exported by the SPM to tfm core */
#include <stdio.h>
#include <string.h>
#include "spm_api.h"
#include "platform/include/tfm_spm_hal.h"
#include "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 "tfm_peripherals_def.h"
#include "spm_partition_defs.h"
struct spm_partition_db_t g_spm_partition_db = {0,};
typedef enum {
TFM_INIT_FAILURE,
} sp_error_type_t;
/*
* This function is called when a secure partition causes an error.
* In case of an error in the error handling, a non-zero value have to be
* returned.
*/
#ifndef TFM_PSA_API
static void tfm_spm_partition_err_handler(
const struct spm_partition_desc_t *partition,
sp_error_type_t err_type,
int32_t err_code)
{
#ifdef TFM_CORE_DEBUG
if (err_type == TFM_INIT_FAILURE) {
printf("Partition init failed for partition id 0x%08X\r\n",
partition->static_data.partition_id);
} else {
printf(
"Unknown partition error %d (code: %d) for partition id 0x%08X\r\n",
err_type, err_code, partition->static_data.partition_id);
}
#else
(void)err_type;
(void)err_code;
#endif
tfm_spm_partition_set_state(partition->static_data.partition_id,
SPM_PARTITION_STATE_CLOSED);
}
#endif /* !defined(TFM_PSA_API) */
/*
* This function prevents name clashes between the variable names accessibles in
* the scope of where tfm_partition_list.inc is included and the varaible names
* defined inside tfm_partition_list.inc file.
*/
static inline enum spm_err_t add_user_defined_partitions(void) {
#include "tfm_partition_list.inc"
return SPM_ERR_OK;
}
uint32_t get_partition_idx(uint32_t partition_id)
{
uint32_t i;
if (partition_id == INVALID_PARTITION_ID) {
return SPM_INVALID_PARTITION_IDX;
}
for (i = 0; i < g_spm_partition_db.partition_count; ++i) {
if (g_spm_partition_db.partitions[i].static_data.partition_id ==
partition_id) {
return i;
}
}
return SPM_INVALID_PARTITION_IDX;
}
enum spm_err_t tfm_spm_db_init(void)
{
struct spm_partition_desc_t *part_ptr;
enum spm_err_t err;
(void)tfm_memset (&g_spm_partition_db, 0, sizeof(g_spm_partition_db));
/* This function initialises partition db */
g_spm_partition_db.running_partition_idx = SPM_INVALID_PARTITION_IDX;
g_spm_partition_db.partition_count = 0;
/* There are a few partitions that are used by TF-M internally.
* These are explicitly added to the partition db here.
*/
/* For the non secure Execution environment */
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[];
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
uint32_t psp_stack_top = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Limit;
#endif
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
g_spm_partition_db.partition_count]);
part_ptr->static_data.partition_id = TFM_SP_NON_SECURE_ID;
#ifdef TFM_PSA_API
part_ptr->static_data.partition_flags = SPM_PART_FLAG_APP_ROT |
SPM_PART_FLAG_IPC;
part_ptr->static_data.partition_priority = TFM_PRIORITY_LOW;
part_ptr->static_data.partition_init = tfm_nspm_thread_entry;
#else
part_ptr->static_data.partition_flags = 0;
#endif
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
part_ptr->memory_data.stack_bottom = psp_stack_bottom;
part_ptr->memory_data.stack_top = psp_stack_top;
/* Since RW, ZI and stack are configured as one MPU region, configure
* RW start address to psp_stack_bottom to get RW access to stack
*/
part_ptr->memory_data.rw_start = psp_stack_bottom;
#endif
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
tfm_nspm_configure_clients();
++g_spm_partition_db.partition_count;
/* For the TF-M core environment itself */
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) {
return SPM_ERR_INVALID_CONFIG;
}
part_ptr = &(g_spm_partition_db.partitions[
g_spm_partition_db.partition_count]);
part_ptr->static_data.partition_id = TFM_SP_CORE_ID;
part_ptr->static_data.partition_flags =
SPM_PART_FLAG_APP_ROT | SPM_PART_FLAG_PSA_ROT;
part_ptr->runtime_data.partition_state = SPM_PARTITION_STATE_UNINIT;
++g_spm_partition_db.partition_count;
err = add_user_defined_partitions();
if (err != SPM_ERR_OK) {
return err;
}
g_spm_partition_db.is_init = 1;
return SPM_ERR_OK;
}
#ifndef TFM_PSA_API
enum spm_err_t tfm_spm_partition_init(void)
{
struct spm_partition_desc_t *part;
struct tfm_sfn_req_s desc;
int32_t args[4] = {0};
int32_t fail_cnt = 0;
uint32_t idx;
/* Call the init function for each partition */
for (idx = 0; idx < g_spm_partition_db.partition_count; ++idx) {
part = &g_spm_partition_db.partitions[idx];
tfm_spm_hal_configure_default_isolation(part->platform_data);
if (part->static_data.partition_init == NULL) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
tfm_spm_partition_set_caller_partition_idx(idx,
SPM_INVALID_PARTITION_IDX);
} else {
int32_t res;
desc.args = args;
desc.ns_caller = 0U;
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);
if (res == TFM_SUCCESS) {
tfm_spm_partition_set_state(idx, SPM_PARTITION_STATE_IDLE);
} else {
tfm_spm_partition_err_handler(part, TFM_INIT_FAILURE, res);
fail_cnt++;
}
}
}
tfm_secure_api_init_done();
if (fail_cnt == 0) {
return SPM_ERR_OK;
} else {
return SPM_ERR_PARTITION_NOT_AVAILABLE;
}
}
#endif /* !defined(TFM_PSA_API) */
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.stack_bottom;
}
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].memory_data.stack_top;
}
#endif
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx)
{
struct spm_partition_desc_t *part;
if (!g_spm_partition_db.is_init) {
return SPM_ERR_PARTITION_DB_NOT_INIT;
}
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_config(&(part->memory_data),
part->platform_data);
}
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx)
{
/* This function takes a partition id and disables the
* SPM partition for that partition
*/
struct spm_partition_desc_t *part;
part = &g_spm_partition_db.partitions[partition_idx];
return tfm_spm_hal_partition_sandbox_deconfig(&(part->memory_data),
part->platform_data);
}
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_start;
}
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.zi_limit;
}
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_start;
}
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].
memory_data.rw_limit;
}
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
}
#endif
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_id;
}
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx)
{
return g_spm_partition_db.partitions[partition_idx].static_data.
partition_flags;
}
#ifndef TFM_PSA_API
void tfm_spm_partition_store_context(uint32_t partition_idx,
uint32_t stack_ptr, uint32_t lr)
{
g_spm_partition_db.partitions[partition_idx].
runtime_data.stack_ptr = stack_ptr;
g_spm_partition_db.partitions[partition_idx].
runtime_data.lr = lr;
}
const struct spm_partition_runtime_data_t *
tfm_spm_partition_get_runtime_data(uint32_t partition_idx)
{
return &(g_spm_partition_db.partitions[partition_idx].runtime_data);
}
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.partition_state =
state;
if (state == SPM_PARTITION_STATE_RUNNING) {
g_spm_partition_db.running_partition_idx = partition_idx;
}
}
void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
uint32_t caller_partition_idx)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.
caller_partition_idx = caller_partition_idx;
}
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id)
{
g_spm_partition_db.partitions[partition_idx].runtime_data.
caller_client_id = caller_client_id;
}
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share)
{
enum spm_err_t ret = SPM_ERR_OK;
#if TFM_LVL != 1
/* Only need to set configuration on levels higher than 1 */
ret = tfm_spm_hal_set_share_region(share);
#endif
if (ret == SPM_ERR_OK) {
g_spm_partition_db.partitions[partition_idx].runtime_data.share = share;
}
return ret;
}
enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
const int32_t *args)
{
struct spm_partition_runtime_data_t *runtime_data =
&g_spm_partition_db.partitions[partition_idx].runtime_data;
size_t i;
if ((args[1] < 0) || (args[3] < 0)) {
return SPM_ERR_INVALID_PARAMETER;
}
runtime_data->iovec_args.in_len = (size_t)args[1];
for (i = 0U; 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 = (size_t)args[3];
for (i = 0U; 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;
return SPM_ERR_OK;
}
uint32_t tfm_spm_partition_get_running_partition_idx(void)
{
return g_spm_partition_db.running_partition_idx;
}
void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
{
struct spm_partition_desc_t *partition =
&(g_spm_partition_db.partitions[partition_idx]);
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;
}
#endif /* !defined(TFM_PSA_API) */
__attribute__((section("SFN")))
void tfm_spm_partition_change_privilege(uint32_t privileged)
{
CONTROL_Type ctrl;
ctrl.w = __get_CONTROL();
if (privileged == TFM_PARTITION_PRIVILEGED_MODE) {
ctrl.b.nPRIV = 0;
} else {
ctrl.b.nPRIV = 1;
}
__set_CONTROL(ctrl.w);
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_API_H__
#define __SPM_API_H__
/* This file contains the apis exported by the SPM to tfm core */
#include "tfm_api.h"
#include "spm_partition_defs.h"
#include "secure_fw/core/tfm_secure_api.h"
#define SPM_INVALID_PARTITION_IDX (~0U)
/* Privileged definitions for partition thread mode */
#define TFM_PARTITION_PRIVILEGED_MODE 1
#define TFM_PARTITION_UNPRIVILEGED_MODE 0
enum spm_err_t {
SPM_ERR_OK = 0,
SPM_ERR_PARTITION_DB_NOT_INIT,
SPM_ERR_PARTITION_ALREADY_ACTIVE,
SPM_ERR_PARTITION_NOT_AVAILABLE,
SPM_ERR_INVALID_PARAMETER,
SPM_ERR_INVALID_CONFIG,
};
enum spm_part_state_t {
SPM_PARTITION_STATE_UNINIT = 0,
SPM_PARTITION_STATE_IDLE,
SPM_PARTITION_STATE_RUNNING,
SPM_PARTITION_STATE_SUSPENDED,
SPM_PARTITION_STATE_BLOCKED,
SPM_PARTITION_STATE_CLOSED
};
enum spm_part_flag_mask_t {
SPM_PART_FLAG_APP_ROT = 0x01,
SPM_PART_FLAG_PSA_ROT = 0x02,
SPM_PART_FLAG_IPC = 0x04
};
/**
* \brief 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
*/
struct spm_partition_runtime_data_t {
uint32_t partition_state;
uint32_t caller_partition_idx;
int32_t caller_client_id;
uint32_t share;
uint32_t stack_ptr;
uint32_t lr;
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;
};
/**
* \brief Returns the index of the partition with the given partition ID.
*
* \param[in] partition_id Partition id
*
* \return the partition idx if partition_id is valid,
* \ref SPM_INVALID_PARTITION_IDX othervise
*/
uint32_t get_partition_idx(uint32_t partition_id);
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
/**
* \brief Get bottom of stack region for a partition
*
* \param[in] partition_idx Partition index
*
* \return Stack region bottom value
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx);
/**
* \brief Get top of stack region for a partition
*
* \param[in] partition_idx Partition index
*
* \return Stack region top value
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
#endif
#if (TFM_LVL != 1) && !defined(TFM_PSA_API)
/**
* \brief Configure isolated sandbox for a partition
*
* \param[in] partition_idx Partition index
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
*/
enum spm_err_t tfm_spm_partition_sandbox_config(uint32_t partition_idx);
/**
* \brief Deconfigure sandbox for a partition
*
* \param[in] partition_idx Partition index
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
*/
enum spm_err_t tfm_spm_partition_sandbox_deconfig(uint32_t partition_idx);
/**
* \brief Get the start of the zero-initialised region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Start of the zero-initialised region
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_zi_start(uint32_t partition_idx);
/**
* \brief Get the limit of the zero-initialised region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Limit of the zero-initialised region
*
* \note This function doesn't check if partition_idx is valid.
* \note The address returned is not part of the region.
*/
uint32_t tfm_spm_partition_get_zi_limit(uint32_t partition_idx);
/**
* \brief Get the start of the read-write region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Start of the read-write region
*
* \note This function doesn't check if partition_idx is valid.
*/
uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx);
/**
* \brief Get the limit of the read-write region for a partition
*
* \param[in] partition_idx Partition idx
*
* \return Limit of the read-write region
*
* \note This function doesn't check if partition_idx is valid.
* \note The address returned is not part of the region.
*/
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
/**
* \brief 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 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);
#ifndef TFM_PSA_API
/**
* \brief Get the current runtime data of a partition
*
* \param[in] partition_idx Partition index
*
* \return The runtime data of the specified partition
*
* \note This function doesn't check if partition_idx is valid.
*/
const struct spm_partition_runtime_data_t *
tfm_spm_partition_get_runtime_data(uint32_t partition_idx);
/**
* \brief Returns the index of the partition that has running state
*
* \return The index of the partition with the running state, if there is any
* set. 0 otherwise.
*/
uint32_t tfm_spm_partition_get_running_partition_idx(void);
/**
* \brief Save stack pointer and link register for partition in database
*
* \param[in] partition_idx Partition index
* \param[in] stack_ptr Stack pointer to be stored
* \param[in] lr Link register to be stored
*
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_store_context(uint32_t partition_idx,
uint32_t stack_ptr, uint32_t lr);
/**
* \brief Set the current state of a partition
*
* \param[in] partition_idx Partition index
* \param[in] state The state to be set
*
* \note This function doesn't check if partition_idx is valid.
* \note The state has to have the value set of \ref spm_part_state_t.
*/
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
/**
* \brief Set the caller partition index for a given partition
*
* \param[in] partition_idx Partition index
* \param[in] caller_partition_idx The index of the caller partition
*
* \note This function doesn't check if any of the partition_idxs are valid.
*/
void tfm_spm_partition_set_caller_partition_idx(uint32_t partition_idx,
uint32_t caller_partition_idx);
/**
* \brief Set the caller client ID for a given partition
*
* \param[in] partition_idx Partition index
* \param[in] caller_client_id The ID of the calling client
*
* \note This function doesn't check if any of the partition_idxs are valid.
*/
void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
int32_t caller_client_id);
/**
* \brief Set the buffer share region of the partition
*
* \param[in] partition_idx Partition index
* \param[in] share The buffer share region to be set
*
* \return Error code \ref spm_err_t
*
* \note This function doesn't check if partition_idx is valid.
* \note share has to have the value set of \ref tfm_buffer_share_region_e
*/
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
uint32_t share);
/**
* \brief 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
*
* \return Error code \ref spm_err_t
*
* \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.
*/
enum spm_err_t tfm_spm_partition_set_iovec(uint32_t partition_idx,
const int32_t *args);
/**
* \brief Execute partition init function
*
* \return Error code \ref spm_err_t
*/
enum spm_err_t tfm_spm_partition_init(void);
/**
* \brief Clears the context info from the database for a partition.
*
* \param[in] partition_idx Partition index
*
* \note This function doesn't check if partition_idx is valid.
*/
void tfm_spm_partition_cleanup_context(uint32_t partition_idx);
#endif /* !defined(TFM_PSA_API) */
/**
* \brief Initialize partition database
*
* \return Error code \ref spm_err_t
*/
enum spm_err_t tfm_spm_db_init(void);
/**
* \brief Change the privilege mode for partition thread mode.
*
* \param[in] privileged Privileged mode,
* \ref TFM_PARTITION_PRIVILEGED_MODE
* and \ref TFM_PARTITION_UNPRIVILEGED_MODE
*
* \note Barrier instructions are not called by this function, and if
* it is called in thread mode, it might be necessary to call
* them after this function returns (just like it is done in
* jump_to_ns_code()).
*/
void tfm_spm_partition_change_privilege(uint32_t privileged);
#endif /*__SPM_API_H__ */

View File

@ -1,83 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_DB_H__
#define __SPM_DB_H__
#ifdef TFM_PSA_API
#include "tfm_thread.h"
#endif
struct spm_partition_desc_t;
struct spm_partition_db_t;
typedef psa_status_t(*sp_init_function)(void);
#define TFM_PARTITION_TYPE_APP "APPLICATION-ROT"
#define TFM_PARTITION_TYPE_PSA "PSA-ROT"
#ifdef TFM_PSA_API
enum tfm_partition_priority {
TFM_PRIORITY_LOW = THRD_PRIOR_LOWEST,
TFM_PRIORITY_NORMAL = THRD_PRIOR_MEDIUM,
TFM_PRIORITY_HIGH = THRD_PRIOR_HIGHEST,
};
#else
enum tfm_partition_priority {
TFM_PRIORITY_LOW = 0xFF,
TFM_PRIORITY_NORMAL = 0x7F,
TFM_PRIORITY_HIGH = 0,
};
#endif
#define TFM_PRIORITY(LEVEL) TFM_PRIORITY_##LEVEL
/**
* Holds the fields of the partition DB used by the SPM code. The values of
* these fields are calculated at compile time, and set during initialisation
* phase.
*/
struct spm_partition_static_data_t {
uint32_t partition_id;
uint32_t partition_flags;
uint32_t partition_priority;
sp_init_function partition_init;
};
/**
* Holds the fields that define a partition for SPM. The fields are further
* divided to structures, to keep the related fields close to each other.
*/
struct spm_partition_desc_t {
struct spm_partition_static_data_t static_data;
struct spm_partition_runtime_data_t runtime_data;
struct tfm_spm_partition_platform_data_t *platform_data;
#if (TFM_LVL != 1) || defined(TFM_PSA_API)
struct tfm_spm_partition_memory_data_t memory_data;
#endif
#ifdef TFM_PSA_API
struct tfm_thrd_ctx sp_thrd;
#endif
};
/* Macros to pick linker symbols and allow to form the partition data base */
#define REGION(a, b, c) a##b##c
#define REGION_NAME(a, b, c) REGION(a, b, c)
/* Changed from #if (TFM_LVL == 1) && !defined(TFM_PSA_API) to #if (TFM_LVL == 1) to avoid linker error.
TF-M build autogenerates region details (code, ro, rw, zi and stack ) using linker scripts. We do not
hve that in mbed-os build yet.
*/
#if (TFM_LVL == 1)
#define REGION_DECLARE(a, b, c)
#else
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
#define PART_REGION_ADDR(partition, region) \
(uint32_t)&REGION_NAME(Image$$, partition, region)
#endif
#endif /* __SPM_DB_H__ */

View File

@ -1,138 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_DB_SETUP_H__
#define __SPM_DB_SETUP_H__
#include <stdint.h>
#include "spm_db.h"
/**
* \brief Get the index of a partition.
*
* Gets the index of a partition in the partition db based on the partition ID
* provided as a parameter.
*
* \param[in] partition_idx The index of the partition
*
* \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);
struct spm_partition_db_t {
uint32_t is_init;
uint32_t partition_count;
uint32_t running_partition_idx;
struct spm_partition_desc_t partitions[SPM_MAX_PARTITIONS];
};
#define PARTITION_INIT_STATIC_DATA(data, partition, flags, id, priority) \
do { \
data.partition_id = partition##_ID; \
data.partition_flags = flags; \
data.partition_priority = TFM_PRIORITY(priority); \
} while (0)
/* Changed from #if (TFM_LVL == 1) && !defined(TFM_PSA_API) to #if (TFM_LVL == 1) to avoid linker error.
TF-M build autogenerates region details (code, ro, rw, zi and stack ) using linker scripts. We do not
hve that in mbed-os build yet.
*/
#if (TFM_LVL == 1)
#define PARTITION_INIT_MEMORY_DATA(data, partition)
#else
#define PARTITION_INIT_MEMORY_DATA(data, partition) \
do { \
data.code_start = PART_REGION_ADDR(partition, $$Base); \
data.code_limit = PART_REGION_ADDR(partition, $$Limit); \
data.ro_start = PART_REGION_ADDR(partition, $$RO$$Base); \
data.ro_limit = PART_REGION_ADDR(partition, $$RO$$Limit); \
data.rw_start = PART_REGION_ADDR(partition, _DATA$$RW$$Base); \
data.rw_limit = PART_REGION_ADDR(partition, _DATA$$RW$$Limit); \
data.zi_start = PART_REGION_ADDR(partition, _DATA$$ZI$$Base); \
data.zi_limit = PART_REGION_ADDR(partition, _DATA$$ZI$$Limit); \
data.stack_bottom = PART_REGION_ADDR(partition, _STACK$$ZI$$Base); \
data.stack_top = PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
} while (0)
#endif
#if TFM_LVL == 1
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
do { \
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
} while (0)
#else
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
do { \
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
/* 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 - \
sizeof(struct iovec_args_t)); \
} while (0)
#endif
#define PARTITION_DECLARE(partition, flag, type, id, priority, part_stack_size) \
do { \
REGION_DECLARE(Image$$, partition, $$Base); \
REGION_DECLARE(Image$$, partition, $$Limit); \
REGION_DECLARE(Image$$, partition, $$RO$$Base); \
REGION_DECLARE(Image$$, partition, $$RO$$Limit); \
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Base); \
REGION_DECLARE(Image$$, partition, _DATA$$RW$$Limit); \
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Base); \
REGION_DECLARE(Image$$, partition, _DATA$$ZI$$Limit); \
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Base); \
REGION_DECLARE(Image$$, partition, _STACK$$ZI$$Limit); \
int32_t flags = flag; \
if (tfm_memcmp(type, TFM_PARTITION_TYPE_APP, \
strlen(TFM_PARTITION_TYPE_APP)) == 0) { \
flags |= SPM_PART_FLAG_APP_ROT; \
} else if (tfm_memcmp(type, TFM_PARTITION_TYPE_PSA, \
strlen(TFM_PARTITION_TYPE_PSA)) == 0) { \
flags |= SPM_PART_FLAG_PSA_ROT | SPM_PART_FLAG_APP_ROT; \
} else { \
return SPM_ERR_INVALID_CONFIG; \
} \
struct spm_partition_desc_t *part_ptr; \
if (g_spm_partition_db.partition_count >= SPM_MAX_PARTITIONS) { \
return SPM_ERR_INVALID_CONFIG; \
} \
__attribute__((section(".data.partitions_stacks"))) \
static uint8_t partition##_stack[part_stack_size] __attribute__((aligned(8))); \
part_ptr = &(g_spm_partition_db.partitions[ \
g_spm_partition_db.partition_count]); \
part_ptr->memory_data.stack_bottom = (uint32_t)partition##_stack; \
part_ptr->memory_data.stack_top = part_ptr->memory_data.stack_bottom + part_stack_size; \
PARTITION_INIT_STATIC_DATA(part_ptr->static_data, partition, flags, \
id, priority); \
PARTITION_INIT_RUNTIME_DATA(part_ptr->runtime_data, partition); \
PARTITION_INIT_MEMORY_DATA(part_ptr->memory_data, partition); \
++g_spm_partition_db.partition_count; \
} while (0)
#define PARTITION_ADD_INIT_FUNC(partition, init_func) \
do { \
extern int32_t init_func(void); \
uint32_t partition_idx = get_partition_idx(partition##_ID); \
struct spm_partition_desc_t *part_ptr = \
&(g_spm_partition_db.partitions[partition_idx]); \
part_ptr->static_data.partition_init = init_func; \
} while (0)
#define PARTITION_ADD_PERIPHERAL(partition, peripheral) \
do { \
uint32_t partition_idx = get_partition_idx(partition##_ID); \
struct spm_partition_desc_t *part_ptr = \
&(g_spm_partition_db.partitions[partition_idx]); \
part_ptr->platform_data = peripheral; \
} while (0)
#endif /* __SPM_DB_SETUP_H__ */

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __SPM_PARTITION_DEFS_H__
#define __SPM_PARTITION_DEFS_H__
/* FixMe: allocations to be settled.
* 8 bits reserved by TFM for secure partition Id in this prototype
*/
#define TFM_SP_BASE 256
/* A reserved partition ID that is used for uninitialised data */
#define INVALID_PARTITION_ID (~0U)
/* ***** partition ID-s internal to the TFM ***** */
#define TFM_INTERNAL_PARTITIONS (2)
/* From the SPM point of view the non secure processing environment is handled
* as a special secure partition. This simplifies the context switch
* operations.
*/
#define TFM_SP_NON_SECURE_ID (0)
/* A dummy partition for TFM_SP_CORE is created to handle secure partition
* calls done directly from the core, before NS execution started.
*/
#define TFM_SP_CORE_ID (1)
#include "tfm_partition_defs.inc"
/* This limit is only used to define the size of the database reserved for
* partitions. There's no requirement that it match the number of partitions
* that get registered in a specific build
*/
#define SPM_MAX_PARTITIONS (TFM_MAX_USER_PARTITIONS + TFM_INTERNAL_PARTITIONS)
#endif /* __SPM_PARTITION_DEFS_H__ */

View File

@ -1,2 +0,0 @@
Unless specifically indicated otherwise in a file, TF-M files in this directory are licensed under the BSD-3-Clause license,
as can be found in: LICENSE-bsd-3-clause.txt

View File

@ -1,26 +0,0 @@
Copyright 2019 Arm Limited and affiliates.
SPDX-License-Identifier: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,144 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __PSA_CLIENT_H__
#define __PSA_CLIENT_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
/*********************** PSA Client Macros and Types *************************/
#define PSA_FRAMEWORK_VERSION (0x0100)
#define PSA_VERSION_NONE (0)
/* PSA response types */
#define PSA_SUCCESS (0)
#define PSA_CONNECTION_REFUSED (INT32_MIN + 1)
#define PSA_CONNECTION_BUSY (INT32_MIN + 2)
#define PSA_DROP_CONNECTION (INT32_MIN)
/* PSA message handles */
#define PSA_NULL_HANDLE ((psa_handle_t)0)
typedef int32_t psa_status_t;
typedef int32_t psa_handle_t;
/**
* A read-only input memory region provided to an RoT Service.
*/
typedef struct psa_invec {
const void *base; /*!< the start address of the memory buffer */
size_t len; /*!< the size in bytes */
} psa_invec;
/**
* A writable output memory region provided to an RoT Service.
*/
typedef struct psa_outvec {
void *base; /*!< the start address of the memory buffer */
size_t len; /*!< the size in bytes */
} psa_outvec;
/*************************** PSA Client API **********************************/
/**
* \brief Retrieve the version of the PSA Framework API that is implemented.
*
* \return version The version of the PSA Framework implementation
* that is providing the runtime services to the
* caller. The major and minor version are encoded
* as follows:
* \arg version[15:8] -- major version number.
* \arg version[7:0] -- minor version number.
*/
uint32_t psa_framework_version(void);
/**
* \brief Retrieve the minor version of an RoT Service or indicate that it is
* not present on this system.
*
* \param[in] sid ID of the RoT Service to query.
*
* \retval PSA_VERSION_NONE The RoT Service is not implemented, or the
* caller is not permitted to access the service.
* \retval > 0 The minor version of the implemented RoT
* Service.
*/
uint32_t psa_version(uint32_t sid);
/**
* \brief Connect to an RoT Service by its SID.
*
* \param[in] sid ID of the RoT Service to connect to.
* \param[in] minor_version Requested version of the RoT Service.
*
* \retval > 0 A handle for the connection.
* \retval PSA_CONNECTION_REFUSED The SPM or RoT Service has refused the
* connection.
* \retval PSA_CONNECTION_BUSY The SPM or RoT Service cannot make the
* connection at the moment.
* \retval "Does not return" The RoT Service ID and version are not
* supported, or the caller is not permitted to
* access the service.
*/
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version);
/**
* \brief Call an RoT Service on an established connection.
*
* \param[in] handle A handle to an established connection.
* \param[in] in_vec Array of input \ref psa_invec structures.
* \param[in] in_len Number of input \ref psa_invec structures.
* \param[in/out] out_vec Array of output \ref psa_outvec structures.
* \param[in] out_len Number of output \ref psa_outvec structures.
*
* \retval >=0 RoT Service-specific status value.
* \retval <0 RoT Service-specific error code.
* \retval PSA_DROP_CONNECTION The connection has been dropped by the RoT
* Service. This indicates that either this or
* a previous message was invalid.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was passed.
* \arg The connection is already handling a request.
* \arg An invalid memory reference was provided.
* \arg in_len + out_len > PSA_MAX_IOVEC.
* \arg The message is unrecognized by the RoT
* Service or incorrectly formatted.
*/
psa_status_t psa_call(psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
psa_outvec *out_vec,
size_t out_len);
/**
* \brief Close a connection to an RoT Service.
*
* \param[in] handle A handle to an established connection, or the
* null handle.
*
* \retval void Success.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg An invalid handle was provided that is not
* the null handle.
* \arg The connection is handling a request.
*/
void psa_close(psa_handle_t handle);
#ifdef __cplusplus
}
#endif
#endif /* __PSA_CLIENT_H__ */

View File

@ -1,250 +0,0 @@
/*
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __PSA_SERVICE_H__
#define __PSA_SERVICE_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
/********************** PSA Secure Partition Macros and Types ****************/
/* PSA wait timeouts */
#define PSA_POLL (0x00000000u)
#define PSA_BLOCK (0x80000000u)
/* A mask value that includes all Secure Partition signals */
#define PSA_WAIT_ANY (~0u)
/* Doorbell signal */
#define PSA_DOORBELL (0x00000008u)
/* PSA message types */
#define PSA_IPC_CONNECT (1)
#define PSA_IPC_CALL (2)
#define PSA_IPC_DISCONNECT (3)
/* Maximum number of input and output vectors */
#define PSA_MAX_IOVEC (4)
/* Return code from psa_get() */
#define PSA_ERR_NOMSG (INT32_MIN + 3)
/* Store a set of one or more Secure Partition signals */
typedef uint32_t psa_signal_t;
/**
* Describe a message received by an RoT Service after calling \ref psa_get().
*/
typedef struct psa_msg_t {
uint32_t type; /* One of the following values:
* \ref PSA_IPC_CONNECT
* \ref PSA_IPC_CALL
* \ref PSA_IPC_DISCONNECT
*/
psa_handle_t handle; /* A reference generated by the SPM to the
* message returned by psa_get().
*/
int32_t client_id; /* Partition ID of the sender of the message */
void *rhandle; /* Be useful for binding a connection to some
* application-specific data or function
* pointer within the RoT Service
* implementation.
*/
size_t in_size[PSA_MAX_IOVEC]; /* Provide the size of each client input
* vector in bytes.
*/
size_t out_size[PSA_MAX_IOVEC];/* Provide the size of each client output
* vector in bytes.
*/
} psa_msg_t;
/************************* PSA Secure Partition API **************************/
/**
* \brief Return the Secure Partition interrupt signals that have been asserted
* from a subset of signals provided by the caller.
*
* \param[in] signal_mask A set of signals to query. Signals that are not
* in this set will be ignored.
* \param[in] timeout Specify either blocking \ref PSA_BLOCK or
* polling \ref PSA_POLL operation.
*
* \retval >0 At least one signal is asserted.
* \retval 0 No signals are asserted. This is only seen when
* a polling timeout is used.
*/
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
/**
* \brief Retrieve the message which corresponds to a given RoT Service signal
* and remove the message from the RoT Service queue.
*
* \param[in] signal The signal value for an asserted RoT Service.
* \param[out] msg Pointer to \ref psa_msg_t object for receiving
* the message.
*
* \retval PSA_SUCCESS Success, *msg will contain the delivered
* message.
* \retval PSA_ERR_NOMSG Message could not be delivered.
* \retval "Does not return" The call is invalid because one or more of the
* following are true:
* \arg signal has more than a single bit set.
* \arg signal does not correspond to an RoT Service.
* \arg The RoT Service signal is not currently
* asserted.
* \arg The msg pointer provided is not a valid memory
* reference.
*/
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
/**
* \brief Associate some RoT Service private data with a client connection.
*
* \param[in] msg_handle Handle for the client's message.
* \param[in] rhandle Reverse handle allocated by the RoT Service.
*
* \retval void Success, rhandle will be provided with all
* subsequent messages delivered on this
* connection.
* \retval "Does not return" msg_handle is invalid.
*/
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
/**
* \brief Read a message parameter or part of a message parameter from a client
* input vector.
*
* \param[in] msg_handle Handle for the client's message.
* \param[in] invec_idx Index of the input vector to read from. Must be
* less than \ref PSA_MAX_IOVEC.
* \param[out] buffer Buffer in the Secure Partition to copy the
* requested data to.
* \param[in] num_bytes Maximum number of bytes to be read from the
* client input vector.
*
* \retval >0 Number of bytes copied.
* \retval 0 There was no remaining data in this input
* vector.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg msg_handle is invalid.
* \arg msg_handle does not refer to a
* \ref PSA_IPC_CALL message.
* \arg invec_idx is equal to or greater than
* \ref PSA_MAX_IOVEC.
* \arg the memory reference for buffer is invalid or
* not writable.
*/
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
void *buffer, size_t num_bytes);
/**
* \brief Skip over part of a client input vector.
*
* \param[in] msg_handle Handle for the client's message.
* \param[in] invec_idx Index of input vector to skip from. Must be
* less than \ref PSA_MAX_IOVEC.
* \param[in] num_bytes Maximum number of bytes to skip in the client
* input vector.
*
* \retval >0 Number of bytes skipped.
* \retval 0 There was no remaining data in this input
* vector.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg msg_handle is invalid.
* \arg msg_handle does not refer to a
* \ref PSA_IPC_CALL message.
* \arg invec_idx is equal to or greater than
* \ref PSA_MAX_IOVEC.
*/
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
/**
* \brief Write a message response to a client output vector.
*
* \param[in] msg_handle Handle for the client's message.
* \param[out] outvec_idx Index of output vector in message to write to.
* Must be less than \ref PSA_MAX_IOVEC.
* \param[in] buffer Buffer with the data to write.
* \param[in] num_bytes Number of bytes to write to the client output
* vector.
*
* \retval void Success
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg msg_handle is invalid.
* \arg msg_handle does not refer to a
* \ref PSA_IPC_CALL message.
* \arg outvec_idx is equal to or greater than
* \ref PSA_MAX_IOVEC.
* \arg The memory reference for buffer is invalid.
* \arg The call attempts to write data past the end
* of the client output vector.
*/
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
const void *buffer, size_t num_bytes);
/**
* \brief Complete handling of a specific message and unblock the client.
*
* \param[in] msg_handle Handle for the client's message.
* \param[in] status Message result value to be reported to the
* client.
*
* \retval void Success.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg msg_handle is invalid.
* \arg An invalid status code is specified for the
* type of message.
*/
void psa_reply(psa_handle_t msg_handle, psa_status_t status);
/**
* \brief Send a PSA_DOORBELL signal to a specific Secure Partition.
*
* \param[in] partition_id Secure Partition ID of the target partition.
*
* \retval void Success.
* \retval "Does not return" partition_id does not correspond to a Secure
* Partition.
*/
void psa_notify(int32_t partition_id);
/**
* \brief Clear the PSA_DOORBELL signal.
*
* \retval void Success.
* \retval "Does not return" The Secure Partition's doorbell signal is not
* currently asserted.
*/
void psa_clear(void);
/**
* \brief Inform the SPM that an interrupt has been handled (end of interrupt).
*
* \param[in] irq_signal The interrupt signal that has been processed.
*
* \retval void Success.
* \retval "Does not return" The call is invalid, one or more of the
* following are true:
* \arg irq_signal is not an interrupt signal.
* \arg irq_signal indicates more than one signal.
* \arg irq_signal is not currently asserted.
*/
void psa_eoi(psa_signal_t irq_signal);
#ifdef __cplusplus
}
#endif
#endif /* __PSA_SERVICE_H__ */

View File

@ -1,136 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_API_H__
#define __TFM_API_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "psa_client.h"
#define TFM_INVALID_CLIENT_ID 0
/**
* \brief Checks if the provided client ID is a secure client ID.
*
* \param[in] client_id Client ID to check
*
* \return Returns 1 if the client Id is secure. Otherwise, returns 0.
*/
#define TFM_CLIENT_ID_IS_S(client_id) ((client_id)>0)
/**
* \brief Checks if the provided client ID is a non-secure client ID.
*
* \param[in] client_id Client ID to check
*
* \return Returns 1 if the client Id is non-secure. Otherwise, returns 0.
*/
#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0)
/* 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 */
/* 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
{
TFM_SUCCESS = 0,
TFM_PARTITION_BUSY,
TFM_ERROR_SECURE_DOMAIN_LOCKED,
TFM_ERROR_INVALID_PARAMETER,
TFM_ERROR_PARTITION_NON_REENTRANT,
TFM_ERROR_NS_THREAD_MODE_CALL,
TFM_ERROR_NOT_INITIALIZED,
TFM_ERROR_NO_ACTIVE_PARTITION,
TFM_ERROR_INVALID_EXC_MODE,
TFM_SECURE_LOCK_FAILED,
TFM_SECURE_UNLOCK_FAILED,
TFM_ERROR_GENERIC = 0x1F,
TFM_PARTITION_SPECIFIC_ERROR_MIN,
};
//==================== Secure function declarations ==========================//
/**
* \brief Assign client ID to the current TZ context
*
* \param[in] ns_client_id The client ID to be assigned to the current
* context
* \return TFM_SUCCESS if the client ID assigned successfully, an error code
* according to \ref tfm_status_e in case of error.
*
* \note This function have to be called from handler mode.
*/
enum tfm_status_e tfm_register_client_id (int32_t ns_client_id);
/**
* \brief Retrieve the version of the PSA Framework API that is implemented
*
* \return The version of the PSA Framework
*/
uint32_t tfm_psa_framework_version_veneer(void);
/**
* \brief Return version of secure function provided by secure binary
*
* \param[in] sid ID of secure service
*
* \return Version number of secure function
*/
uint32_t tfm_psa_version_veneer(uint32_t sid);
/**
* \brief Connect to secure function
*
* \param[in] sid ID of secure service
* \param[in] minor_version Minor version of SF requested by client
*
* \return Returns handle to connection
*/
psa_handle_t tfm_psa_connect_veneer(uint32_t sid, uint32_t minor_version);
/**
* \brief Call a secure function referenced by a connection handle
*
* \param[in] handle Handle to connection
* \param[in] in_vecs invec containing pointer/count of input vectors
* \param[in] out_vecs outvec containing pointer/count of output vectors
*
* \return Returns \ref psa_status_t status code
*/
psa_status_t tfm_psa_call_veneer(psa_handle_t handle,
const psa_invec *in_vecs,
psa_outvec *out_vecs);
/**
* \brief Close connection to secure function referenced by a connection handle
*
* \param[in] handle Handle to connection
*
* \return Returns \ref psa_status_t status code
*/
psa_status_t tfm_psa_close_veneer(psa_handle_t handle);
//================ End Secure function declarations ==========================//
#ifdef __cplusplus
}
#endif
#endif /* __TFM_API_H__ */

View File

@ -1,42 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_NS_LOCK_H__
#define __TFM_NS_LOCK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "tfm_api.h"
typedef int32_t (*veneer_fn) (uint32_t arg0, uint32_t arg1,
uint32_t arg2, uint32_t arg3);
/**
* \brief NS world, NS lock based dispatcher
*
* \details To be called from the wrapper API interface
*/
uint32_t tfm_ns_lock_dispatch(veneer_fn fn,
uint32_t arg0, uint32_t arg1,
uint32_t arg2, uint32_t arg3);
/**
* \brief NS world, Init NS lock
*
* \details Needs to be called during non-secure app init
* to initialize the TFM NS lock object
*/
enum tfm_status_e tfm_ns_lock_init();
#ifdef __cplusplus
}
#endif
#endif /* __TFM_NS_LOCK_H__ */

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <stdio.h>
#include <cmsis_compiler.h>
#ifndef __TFM_NS_SVC_H__
#define __TFM_NS_SVC_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Include all the SVC handler headers
*/
#include "tfm_nspm_svc_handler.h"
/**
* \brief Macro to encode an svc instruction
*
*/
#define SVC(code) __ASM volatile("svc %0" : : "I" (code))
/**
* \def LIST_SVC_NSPM
*
* \brief This is an X macro which lists
* the SVC interface exposed by TF-M
* for the NS OS.
*
*/
#define LIST_SVC_NSPM \
X(SVC_TFM_NSPM_REGISTER_CLIENT_ID, tfm_nspm_svc_register_client_id) \
/**
* \brief Numbers associated to each SVC available
*
* \details Start from 1 as 0 is reserved by RTX
*/
enum tfm_svc_num {
SVC_INVALID = 0,
#define X(SVC_ENUM, SVC_HANDLER) SVC_ENUM,
/* SVC API for Services */
#ifdef TFM_NS_CLIENT_IDENTIFICATION
LIST_SVC_NSPM
#endif
#undef X
/* add all the new entries above this line */
SVC_TFM_MAX,
};
/* number of user SVC functions */
#define USER_SVC_COUNT ((uint32_t)SVC_TFM_MAX - 1)
#ifdef __cplusplus
}
#endif
#endif /* __TFM_NS_SVC_H__ */

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __TFM_NSPM_SVC_HANDLER_H__
#define __TFM_NSPM_SVC_HANDLER_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Reports the client ID of this task to TF-M (SVC function)
*
* \param [in] client_id Client ID to register.
*
* \return Returns 1 if the client ID was successfully reported 0 otherwise
*/
uint32_t tfm_nspm_svc_register_client_id(uint32_t client_id);
#ifdef __cplusplus
}
#endif
#endif /* __TFM_NSPM_SVC_HANDLER_H__ */

View File

@ -1,29 +0,0 @@
{
"name": "tfm",
"macros": [
"TFM_PSA_API", "MBED_TZ_DEFAULT_ACCESS=1"
],
"config": {
"level": {
"help": "TFM security level",
"macro_name": "TFM_LVL",
"value": 1
},
"handle_pool_size": {
"help": "maximum number of handles that can be opened at the same time",
"macro_name": "TFM_CONN_HANDLE_MAX_NUM",
"value": 10
},
"rot_pool_size": {
"help": "maximum number of RoT services allowed",
"macro_name": "TFM_SPM_MAX_ROT_SERV_NUM",
"value": 32
},
"message_pool_size": {
"help": "maximum number of active messages allowed",
"macro_name": "TFM_MSG_QUEUE_MAX_MSG_NUM",
"value": 10
}
}
}

View File

@ -1,111 +0,0 @@
# TF-M integration to Mbed-OS
This document is an initial draft for TF-M for Mbed-OS porting guide .
## Audience
This guide is intended for developers wishing to port Mbed-OS with TF-M used as a secure kernel for ARMv8-M targets.
Prior knowledge with both TF-M & Mbed-OS concepts is assumed.
## Build system concepts:
Mbed-OS build system is based on [Mbed-CLI](https://github.com/ARMmbed/mbed-cli).
Mbed-CLI build system performs lookup for source and header files within project directory and adds them all to a build. All folders will be scanned for sources except for:
- folders starting with `TARGET_*`
- folders starting with `COMPONENT_*`
- folders starting with `FEATURE_*`
- folders starting with `TESTS_*` (not true for `mbed test` builds)
- files and folders listed in `.mbedignore`
The ignored folders listed above can be explicitly added to a compilation by adding following keys to a target description in `targets.json`:
- adding `extra_labels_add`, `inherits` and `sub_target` for adding `TARGET_*`
- adding `components_add` for adding `COMPONENT_*`
- `features_add` for adding `FEATURE_*`
TF-M is built as bare-metal in a secure target, in order to build a secure target with TF-M as its' kernel need to add `--app-config <MBED-OS-ROOT>/tools/psa/tfm/mbed_app.json` to the build command of the secure target.
## Build hooks
Mbed-OS testing tools are designed to work with a single image (`.bin` or `.hex`).
When building mbed-os for TF-M targets two images are created. One for normal world(NW) and one for TrustZone(TZ).
Mbed-OS build system provides `post_binary_hook` that allows executing arbitrary Python script for merging NW and TZ images. Typically `post_binary_hook` is added to NW target and assumes TZ target images as a prerequisite.
## Porting TF-M targets
Typically firmware for TF-M targets consist of 2 or more images: normal world and TrustZone image. More images can be present in case boot loaders are used.
Two images must be built and linked separately. TrustZone image must be built first.
There may be code and/or header files sharing between the two targets.
Nested folder layout typically provides more easy code reuse between two targets:
Example:
```txt
└── tragets
└── TARGET_<VENDOR>
└── TARGET_<BOARD>
├── common_files <-- files shared between NW and TZ images
├── TARGET_<BOARD>_NS
│   └── normal_world_files <-- files only to be included for NW build
└── TARGET_<BOARD>_S
└── trustzone_files <-- files only to be included for TZ build
```
The target should be represented in a following way in `target.json` (`MUSCA_A1` is taken for example and should be substituted):
```json
...
"ARM_MUSCA_A1": {
"public": false,
"inherits": ["Target"],
"supported_toolchains": ["ARMC6", "GCC_ARM"],
"default_toolchain": "ARMC6",
"extra_labels": ["ARM_SSG", "MUSCA_A1"],
},
"ARM_MUSCA_A1_NS": {
"inherits": ["NSPE_Target", "ARM_MUSCA_A1"],
"core": "Cortex-M33-NS",
"device_has_add": ["INTERRUPTIN", "LPTICKER", "SERIAL", "SLEEP", "USTICKER"],
"macros": [
"MBED_FAULT_HANDLER_DISABLED",
"MBEDTLS_PSA_CRYPTO_C"
],
"extra_labels_add": ["MUSCA_A1_NS", "PSA", "TFM"],
"post_binary_hook": {"function": "ArmMuscaA1Code.binary_hook"}
},
"ARM_MUSCA_A1_S": {
"inherits": ["SPE_Target", "ARM_MUSCA_A1"],
"core": "Cortex-M33",
"device_has_add": ["FLASH"],
"macros": [
"MBED_MPU_CUSTOM",
"MBEDTLS_PSA_CRYPTO_SPM",
"MBEDTLS_PSA_CRYPTO_C",
"MBEDTLS_ENTROPY_NV_SEED"
],
"components_add": ["FLASHIAP"],
"extra_labels_add": ["MUSCA_A1_S", "PSA", "TFM"]
},
```
Example details:
- Secure target:
- `"device_has_add": ["FLASH"]` and `"components_add": ["FLASHIAP"]` for enabling storage stack. Required by PSA Internal storage service.
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
- all the macros from the example above are required
- must inherit from `SPE_Target`
- Nonsecure target:
- must inherit from `NSPE_Target`
- `"extra_labels_add": ["PSA", "TFM"]` are required to add PSA services and TF-M SPM implementation sources to a compilation
- all the macros from the example above are required
- `post_binary_hook` is used to combine secure and non-secure images
### HAL
For porting Mbed-OS & TF-M both Mbed-OS and TF-M HAL layers should be created.
#### Mbed-OS HAL:
Follow instructions for [Mbed-OS HAL porting](https://os.mbed.com/docs/mbed-os/v5.11/porting/porting-hal-modules.html)
#### TF-M:
Mbed-OS contains customized TF-M version. TF-M services reference implementation was replaced by Mbed-OS version. Thus TF-M has different HAL layer comparing to vanilla [TF-M reference implementation](https://git.trustedfirmware.org/trusted-firmware-m.git/about/).
The porting layer consists of:
- All functions listed in: `components/TARGET_PSA/TARGET_TFM/COMPONENT_SPE/platform/include/tfm_spm_hal.h`
- Flash API `mbed-os/hal/flash_api.h` implementation is required for TZ image. It is used by PSA Internal trusted storage implementation.