mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
5624ad123a
commit
da5b641ed7
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -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__ */
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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 .");
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 *)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
|
||||||
tfm_scratch_area_size =
|
|
||||||
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit) -
|
|
||||||
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
|
||||||
#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
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
|
||||||
uint32_t scratch_limit =
|
|
||||||
(uint32_t)®ION_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) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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__ */
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -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__ */
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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__ */
|
|
|
@ -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)®ION_NAME(Image$$, partition, region)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __SPM_DB_H__ */
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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
|
|
|
@ -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.
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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__ */
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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.
|
|
Loading…
Reference in New Issue