psa: Remove MBED_SPM code

All MBED_SPM targets have been removed previously, via commits
5cc66282dd ("PSOC6: remove PSA targets") and 115b09aba43b ("psoc6:
Remove FUTURE_SEQUANA and FUTURE_SEQUANA_M0"). Remove all the dead
MBED_SPM code, as no targets use it.

Signed-off-by: Jaeden Amero <jaeden.amero@arm.com>
pull/12738/head
Jaeden Amero 2020-03-17 12:57:38 +00:00 committed by Jaeden Amero
parent 47b359974f
commit 07a84ec10a
34 changed files with 4 additions and 4558 deletions

View File

@ -467,9 +467,6 @@ Case cases[] = {
Case("Testing client psa_version() API on non-existing SID", psa_version_non_existing),
Case("Testing client psa_version() API to a service that is not NSPE callable", psa_version_secure_access_only),
Case("Testing client multiple calls on different channels to the same SID", multi_thread_diff_handles),
#if defined TARGET_MBED_SPM // TF-M issue: https://developer.trustedfirmware.org/T244
Case("Testing client exceed num of max channels allowed", exceed_num_of_max_channels),
#endif
};
utest::v1::status_t test_setup(const size_t number_of_cases)

View File

@ -262,9 +262,6 @@ Case cases[] = {
SPM_UTEST_CASE("Try to skip more bytes than left while reading", skip_more_than_left),
SPM_UTEST_CASE("Test rhandle implementation by calculating the factorial function", rhandle_factorial),
SPM_UTEST_CASE("Test a call flow between 2 secure partitions", cross_partition_call),
#if defined TARGET_MBED_SPM // TF-M issue: https://developer.trustedfirmware.org/T273
SPM_UTEST_CASE("Test a common DOORBELL scenario", doorbell_test),
#endif
};
//Declare your test specification with a custom setup handler

View File

@ -21,10 +21,6 @@
#include "psa/service.h"
#include "mbed_spm_partitions.h"
#if defined(TARGET_MBED_SPM)
#include "cmsis_os2.h"
#endif
void server_part2_main(void *ptr)
{
psa_signal_t signals = 0;
@ -88,10 +84,6 @@ void server_part2_main(void *ptr)
}
// In doorbell scenario the server first calls psa_reply()
psa_reply(msg.handle, PSA_SUCCESS);
#if defined(TARGET_MBED_SPM)
// Then the servers waits to some driver making long calculations - imitate using osDelay()
osDelay(20);
#endif
// After work is done, ring the doorbell
psa_notify(caller_part_id);
break;

View File

@ -698,8 +698,5 @@ psa_test_server_side_func test_list[] = {
PSA_TEST_SERVER_NAME(skip_more_than_left),
PSA_TEST_SERVER_NAME(rhandle_factorial),
PSA_TEST_SERVER_NAME(cross_partition_call),
#if defined TARGET_MBED_SPM // TF-M issue: https://developer.trustedfirmware.org/T273
PSA_TEST_SERVER_NAME(doorbell_test),
#endif
NULL
};

View File

@ -1,160 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* -------------------------------------- Includes ----------------------------------- */
#include "psa_defs.h"
#include "cmsis_os2.h"
#include "mbed_atomic.h"
#include "spm_internal.h"
#include "spm_panic.h"
#include "handles_manager.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
/* ------------------------------------ Definitions ---------------------------------- */
#define PSA_HANDLE_MGR_HANDLE_INDEX_POS 16
#define PSA_HANDLE_MGR_HANDLE_INDEX_MSK 0xFFFF
/* ------------------------------------- Functions ----------------------------------- */
psa_handle_t psa_hndl_mgr_handle_create(psa_handle_manager_t *handle_mgr, void *handle_mem, int32_t friend_pid)
{
// Make sanity checks on arguments
SPM_ASSERT(handle_mgr != NULL);
SPM_ASSERT(handle_mem != NULL);
// Get active partition id - Needed for requester identification
spm_partition_t *curr_part_ptr = get_active_partition();
int32_t current_pid = ((curr_part_ptr != NULL) ? curr_part_ptr->partition_id : PSA_NSPE_IDENTIFIER);
// Generate a new handle identifier
uint32_t tmp_handle;
do {
tmp_handle = core_util_atomic_incr_u16(&(handle_mgr->handle_generator), 1);
} while (tmp_handle == PSA_HANDLE_MGR_INVALID_HANDLE);
psa_handle_t new_handle = PSA_NULL_HANDLE;
// Look for a vacant space in handles pool for the generated handle
for (uint32_t pool_ix = 0; pool_ix < handle_mgr->pool_size; pool_ix++) {
psa_handle_t expected = PSA_NULL_HANDLE;
// Write the handles pool index in the upper 16 bits of the handle
psa_handle_t desired_handle = ((pool_ix << PSA_HANDLE_MGR_HANDLE_INDEX_POS) | tmp_handle);
// Store the generated handle in the handles pool
if (core_util_atomic_cas_s32(&(handle_mgr->handles_pool[pool_ix].handle),
&expected,
desired_handle
)) {
// Handle is successfully stored in handles pool
new_handle = desired_handle;
// Store the handle memory in the handles pool, "coupled" with the stored handle
handle_mgr->handles_pool[pool_ix].handle_mem = handle_mem;
handle_mgr->handles_pool[pool_ix].handle_owner = current_pid;
handle_mgr->handles_pool[pool_ix].handle_friend = friend_pid;
break;
}
// Occupied index in handles pool - continue looping
}
// Handle creation should only occur after a successful memory allocation
// and is not expected to fail.
SPM_ASSERT(new_handle != PSA_NULL_HANDLE);
return new_handle;
}
void psa_hndl_mgr_handle_destroy(psa_handle_manager_t *handle_mgr, psa_handle_t handle)
{
// Make sanity checks on arguments
SPM_ASSERT(handle_mgr != NULL);
SPM_ASSERT(handle != PSA_NULL_HANDLE);
// Get the handle's index in the handles pool
uint32_t pool_ix = ((handle >> PSA_HANDLE_MGR_HANDLE_INDEX_POS) & PSA_HANDLE_MGR_HANDLE_INDEX_MSK);
if (pool_ix >= handle_mgr->pool_size) {
SPM_PANIC("[ERROR] Handle's index [%lu] is bigger than handles pool size [%hu]! \n", pool_ix, handle_mgr->pool_size);
}
if (handle_mgr->handles_pool[pool_ix].handle != handle) {
SPM_PANIC("[ERROR] Handle %ld is not found in expected index! \n", handle);
}
// Get active partition id - Needed for requester identification
spm_partition_t *curr_part_ptr = get_active_partition();
int32_t current_pid = ((curr_part_ptr != NULL) ? curr_part_ptr->partition_id : PSA_NSPE_IDENTIFIER);
if ((handle_mgr->handles_pool[pool_ix].handle_owner != current_pid) &&
(handle_mgr->handles_pool[pool_ix].handle_friend != current_pid)
) {
SPM_PANIC("[ERROR] Request for destroy by non-owner or friend!\n");
}
handle_mgr->handles_pool[pool_ix].handle_owner = PSA_HANDLE_MGR_INVALID_FRIEND_OWNER;
handle_mgr->handles_pool[pool_ix].handle_friend = PSA_HANDLE_MGR_INVALID_FRIEND_OWNER;
core_util_atomic_store_s32(&(handle_mgr->handles_pool[pool_ix].handle), PSA_NULL_HANDLE);
}
void *psa_hndl_mgr_handle_get_mem(psa_handle_manager_t *handle_mgr, psa_handle_t handle)
{
SPM_ASSERT(handle_mgr != NULL);
if (handle == PSA_NULL_HANDLE) {
SPM_PANIC("[ERROR] Trying to get memory for an invalid handle! \n");
}
// Get the handle's index in the handles pool
uint32_t pool_ix = ((handle >> PSA_HANDLE_MGR_HANDLE_INDEX_POS) & PSA_HANDLE_MGR_HANDLE_INDEX_MSK);
if (pool_ix >= handle_mgr->pool_size) {
SPM_PANIC("[ERROR] Handle's index [%lu] is bigger than handles pool size [%hu]! \n", pool_ix, handle_mgr->pool_size);
}
if (handle_mgr->handles_pool[pool_ix].handle != handle) {
SPM_PANIC("[ERROR] Handle %ld is not found in expected index! \n", handle);
}
// Get active partition id - Needed for requester identification
spm_partition_t *curr_part_ptr = get_active_partition();
int32_t current_pid = ((curr_part_ptr != NULL) ? curr_part_ptr->partition_id : PSA_NSPE_IDENTIFIER);
if ((current_pid != handle_mgr->handles_pool[pool_ix].handle_owner) &&
(current_pid != handle_mgr->handles_pool[pool_ix].handle_friend)
) {
SPM_PANIC("[ERROR] Request for handle memory is not allowed for this partition! \n");
}
// If a valid handle is "coupled" with a NULL handle memory then
// it is an internal module error or memory was overwritten --> Assert
SPM_ASSERT(handle_mgr->handles_pool[pool_ix].handle_mem != NULL);
return handle_mgr->handles_pool[pool_ix].handle_mem;
}

View File

@ -1,160 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_HANDLE_MANAGER_H__
#define __MBED_HANDLE_MANAGER_H__
/* -------------------------------------- Includes ----------------------------------- */
#include "psa_defs.h"
#include <stdint.h>
/* -------------------------------- Handle Manager Module ---------------------------- */
/*
* The Handle Manager module generates and exposes a unique
* identifier (handle) per handle memory (handle_mem) it receives.
* You can use the exposed handle identifier to relate to the "registered"
* handle memory.
*
* You can:
* - Ask for a unique handle identifier for a given handle memory [`handle_create`].
* - Ask for a pointer to the handle memory corresponding to a
* handle identifier [`handle_get_mem`].
* - Remove a handle from the handle manager module [`handle_destroy`].
*
* Note:
* Handle generation is done exclusively.
* Once you have a handle, you can remove or get its memory non-exclusively.
* The assumption is that only one context is dealing with a handle after it is
* generated.
*/
/* --------------------------------- extern "C" wrapper ------------------------------ */
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------ Definitions ---------------------------------- */
#define PSA_HANDLE_MGR_INVALID_HANDLE ((uint16_t)PSA_NULL_HANDLE)
#define PSA_HANDLE_MGR_INVALID_FRIEND_OWNER 0 // Denoting invalid friend or invalid owner
// Handle manager pool indexes must be in range 0 - 0x7FFF.
// This is because the index is stored in the upper 16 bits of a handle,
// and the most significant bit must be zero to keep handles non-negative.
#define PSA_HANDLE_MGR_MAX_HANDLES_NUM 0x8000
/* -------------------------------------- Structs ------------------------------------ */
typedef struct psa_handle_item_t {
psa_handle_t handle; /* The user-exposed handle [unique identifier]. */
int32_t handle_owner; /* The partition ID of the handle creator. Allowed to get_mem() / destroy(). */
int32_t handle_friend; /* The partition ID of a "friend" partition. Allowed to get_mem(). */
void *handle_mem; /* Points to memory allocated by the use.r */
} psa_handle_item_t;
typedef struct psa_handle_manager_t {
// Handle generator uses only 16 bits, and wraps.
// The reason for this is that we use the 16 upper bits to store the handle's index in the handles pool (for performance reasons)
uint16_t handle_generator; /* A counter supplying handle numbers. */
uint16_t pool_size; /* The maximum number of handles that pool can contain. */
psa_handle_item_t *handles_pool; /* Holds couples of handles and their memory "blocks". */
} psa_handle_manager_t;
/*
handles_pool
|
|
|
--> *--------------------------------------------------------------------------*
| handle | handle | handle | | | ... |
*--------------------------------------------------------------------------*
| handle_owner | handle_owner | handle_owner | | | ... |
*--------------------------------------------------------------------------*
| handle_friend | handle_friend | handle_friend | | | ... |
*--------------------------------------------------------------------------*
| handle_mem | handle_mem | handle_mem | | | ... |
*--------------------------------------------------------------------------*
*/
/* ------------------------------------- Functions ----------------------------------- */
/*
* @brief Create unique handle identifier
*
* This function generates a unique handle identifier, and **couples** it with the received handle memory.
* If there is no vacant space for the new handle, the function fails.
*
* @note This function is expected to pass since it is always coupled with memory pool allocation of the same size.
* In case memory pool allocation fails, this function should not be called.
* This function will panic in the case of non-vacant space use.
*
* @param[in] handle_mgr A pointer to the handle manager object.
* @param[in] handle_mem A pointer to a pre-allocated handle memory for which to get a handle identifier.
* @param[in] friend_pid The partition ID allowed to `get_mem()` and `destroy()` in addition to the handle owner.
* Use `PSA_HANDLE_MGR_INVALID_FRIEND_OWNER` to denote that there is no friend partition.
* @return The created handle identifier
*/
psa_handle_t psa_hndl_mgr_handle_create(psa_handle_manager_t *handle_mgr, void *handle_mem, int32_t friend_pid);
/*
* @brief Remove a handle from the handle manager.
*
* @param handle_mgr A pointer to the handle manager object.
* @param handle The handle to be removed.
*/
void psa_hndl_mgr_handle_destroy(psa_handle_manager_t *handle_mgr, psa_handle_t handle);
/*
* @brief De-reference handle
*
* This function retrieves the pointer associated with the input <handle>.
*
* @note This function will panic if caller is not allowed to de-reference the memory,
* or handler does not correspond to a valid existing handle.
*
* @param handle_mgr A pointer to the handle manager object.
* @param handle The handle for which you request the corresponding memory handle.
* @return void* A pointer to the memory corresponding to the handle.
*/
void *psa_hndl_mgr_handle_get_mem(psa_handle_manager_t *handle_mgr, psa_handle_t handle);
#ifdef __cplusplus
}
#endif
#endif /* __MBED_HANDLE_MANAGER_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,353 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "mbed_toolchain.h"
#include "rtx_os.h"
#include "spm_client.h"
#include "spm_messages.h"
#include "spm_internal.h"
#include "spm_panic.h"
#include "handles_manager.h"
extern spm_db_t g_spm;
static inline spm_rot_service_t *rot_service_in_partition_get_by_sid(spm_partition_t *partition, uint32_t sid)
{
for (uint32_t i = 0; i < partition->rot_services_count; ++i) {
spm_rot_service_t *rot_service = &(partition->rot_services[i]);
if (rot_service->sid == sid) {
return rot_service;
}
}
return NULL;
}
static inline spm_rot_service_t *rot_service_get(uint32_t sid)
{
for (uint32_t i = 0; i < g_spm.partition_count; ++i) {
spm_rot_service_t *rot_service = rot_service_in_partition_get_by_sid(&(g_spm.partitions[i]), sid);
if (NULL != rot_service) {
return rot_service;
}
}
return NULL;
}
static inline void spm_validate_connection_allowed(spm_rot_service_t *target, spm_partition_t *source)
{
if ((NULL == source) && (false == target->allow_nspe)) {
SPM_PANIC("SID 0x%lx is not allowed to be called from NSPE\n", target->sid);
}
if (NULL != source) {
if (NULL == source->extern_sids) {
SPM_PANIC("Partition %ld did not declare extern functions\n", source->partition_id);
}
for (uint32_t i = 0; i < source->extern_sids_count; i++) {
if (source->extern_sids[i] == target->sid) {
return;
}
}
SPM_PANIC("SID 0x%lx is not in partition %ld extern functions list\n", target->sid, source->partition_id);
}
}
static inline psa_handle_t create_channel_handle(void *handle_mem, int32_t friend_pid)
{
return psa_hndl_mgr_handle_create(&(g_spm.channels_handle_mgr), handle_mem, friend_pid);
}
static inline spm_ipc_channel_t *get_channel_from_handle(psa_handle_t handle)
{
return (spm_ipc_channel_t *)psa_hndl_mgr_handle_get_mem(&(g_spm.channels_handle_mgr), handle);
}
static void spm_rot_service_queue_enqueue(spm_rot_service_t *rot_service, spm_ipc_channel_t *item)
{
osStatus_t os_status = osMutexAcquire(rot_service->partition->mutex, osWaitForever);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
if (rot_service->queue.tail == NULL) {
rot_service->queue.head = item;
} else {
rot_service->queue.tail->next = item;
}
rot_service->queue.tail = item;
uint32_t flags = osThreadFlagsSet(rot_service->partition->thread_id, rot_service->mask);
// osThreadFlagsSet() sets the msb on failure.
// flags is not allowed to be 0 since only dequeue operation can clear the flags,
// and both operations (enqueue and dequeue) are mutex protected.
SPM_ASSERT((flags & SPM_CMSIS_RTOS_ERROR_BIT_MSK) == 0);
SPM_ASSERT(flags & rot_service->mask);
PSA_UNUSED(flags);
os_status = osMutexRelease(rot_service->partition->mutex);
SPM_ASSERT(osOK == os_status);
}
void psa_connect_async(uint32_t sid, spm_pending_connect_msg_t *msg)
{
SPM_ASSERT(msg != NULL);
spm_rot_service_t *dst_rot_service = rot_service_get(sid);
if (NULL == dst_rot_service) {
SPM_PANIC("SID 0x%lx is invalid!\n", sid);
}
if (((dst_rot_service->min_version_policy == PSA_MINOR_VERSION_POLICY_RELAXED) && (msg->min_version > dst_rot_service->min_version)) ||
((dst_rot_service->min_version_policy == PSA_MINOR_VERSION_POLICY_STRICT) && (msg->min_version != dst_rot_service->min_version))) {
SPM_PANIC("minor version %lu does not comply with sid %lu minor version %lu and minor policy %lu",
msg->min_version, dst_rot_service->sid, dst_rot_service->min_version, dst_rot_service->min_version_policy);
}
spm_partition_t *origin_partition = get_active_partition();
spm_validate_connection_allowed(dst_rot_service, origin_partition);
if (!is_buffer_accessible(msg, sizeof(*msg), origin_partition)) {
SPM_PANIC("Pending connect message is inaccessible\n");
}
// Allocating from SPM-Core internal memory
spm_ipc_channel_t *channel = (spm_ipc_channel_t *)osMemoryPoolAlloc(g_spm.channel_mem_pool, PSA_POLL);
if (NULL == channel) {
msg->rc = PSA_CONNECTION_REFUSED;
if (origin_partition != NULL) {
osStatus_t os_status = osSemaphoreRelease(msg->completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
} else {
nspe_done(msg->completion_sem_id);
}
return;
}
// Create the handle in the user message so we could destroy it in case of failure.
msg->rc = (psa_status_t)create_channel_handle(channel, dst_rot_service->partition->partition_id);
// NOTE: all struct fields must be initialized as the allocated memory is not zeroed.
channel->state = SPM_CHANNEL_STATE_CONNECTING;
channel->src_partition = origin_partition;
channel->dst_rot_service = dst_rot_service;
channel->msg_ptr = msg;
channel->msg_type = PSA_IPC_CONNECT;
channel->rhandle = NULL;
channel->next = NULL;
channel->is_dropped = FALSE;
spm_rot_service_queue_enqueue(dst_rot_service, channel);
}
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
{
osRtxSemaphore_t msg_sem_storage = {0};
const osSemaphoreAttr_t msg_sem_attr = {
.name = NULL,
.attr_bits = 0,
.cb_mem = &msg_sem_storage,
.cb_size = sizeof(msg_sem_storage),
};
spm_pending_connect_msg_t msg = {
.min_version = minor_version,
.rc = PSA_NULL_HANDLE,
.completion_sem_id = osSemaphoreNew(
SPM_COMPLETION_SEM_MAX_COUNT,
SPM_COMPLETION_SEM_INITIAL_COUNT,
&msg_sem_attr)
};
if (NULL == msg.completion_sem_id) {
SPM_PANIC("could not create a semaphore for connect message");
}
psa_connect_async(sid, &msg);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
SPM_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
return (psa_handle_t)msg.rc;
}
void psa_call_async(psa_handle_t handle, spm_pending_call_msg_t *msg)
{
SPM_ASSERT(msg != NULL);
spm_ipc_channel_t *channel = get_channel_from_handle(handle);
SPM_ASSERT(channel != NULL);
if (!is_buffer_accessible(msg, sizeof(*msg), channel->src_partition)) {
SPM_PANIC("Pending call message is inaccessible\n");
}
if (channel->is_dropped == TRUE) {
msg->rc = PSA_DROP_CONNECTION;
if (channel->src_partition == NULL) {
nspe_done(msg->completion_sem_id);
} else {
osStatus_t os_status = osSemaphoreRelease(msg->completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
return;
}
channel_state_switch(&channel->state,
SPM_CHANNEL_STATE_IDLE, SPM_CHANNEL_STATE_PENDING);
channel->msg_ptr = msg;
channel->msg_type = PSA_IPC_CALL;
validate_iovec(msg->in_vec, msg->in_vec_size, msg->out_vec, msg->out_vec_size);
spm_rot_service_queue_enqueue(channel->dst_rot_service, channel);
}
psa_status_t psa_call(
psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
const psa_outvec *out_vec,
size_t out_len
)
{
osRtxSemaphore_t msg_sem_storage = {0};
const osSemaphoreAttr_t msg_sem_attr = {
.name = NULL,
.attr_bits = 0,
.cb_mem = &msg_sem_storage,
.cb_size = sizeof(msg_sem_storage),
};
spm_pending_call_msg_t msg = {
.in_vec = in_vec,
.in_vec_size = in_len,
.out_vec = out_vec,
.out_vec_size = out_len,
.rc = PSA_SUCCESS,
.completion_sem_id = osSemaphoreNew(
SPM_COMPLETION_SEM_MAX_COUNT,
SPM_COMPLETION_SEM_INITIAL_COUNT,
&msg_sem_attr)
};
if (NULL == msg.completion_sem_id) {
SPM_PANIC("could not create a semaphore for connect message");
}
psa_call_async(handle, &msg);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
SPM_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
return (psa_status_t)msg.rc;
}
void psa_close_async(psa_handle_t handle, spm_pending_close_msg_t *msg)
{
SPM_ASSERT(msg != NULL);
spm_ipc_channel_t *channel = get_channel_from_handle(handle);
SPM_ASSERT(channel != NULL);
if (!is_buffer_accessible(msg, sizeof(*msg), channel->src_partition)) {
SPM_PANIC("Pending close message is inaccessible\n");
}
channel_state_assert(&(channel->state), SPM_CHANNEL_STATE_IDLE);
channel->msg_ptr = msg;
channel->msg_type = PSA_IPC_DISCONNECT;
spm_rot_service_queue_enqueue(channel->dst_rot_service, channel);
}
void psa_close(psa_handle_t handle)
{
if (handle == PSA_NULL_HANDLE) {
// Invalid handles will fail inside handle manager [called from psa_close_async()]
return;
}
osRtxSemaphore_t msg_sem_storage = {0};
const osSemaphoreAttr_t msg_sem_attr = {
.name = NULL,
.attr_bits = 0,
.cb_mem = &msg_sem_storage,
.cb_size = sizeof(msg_sem_storage),
};
spm_pending_close_msg_t msg = {
.handle = handle,
.completion_sem_id = osSemaphoreNew(SPM_COMPLETION_SEM_MAX_COUNT,
SPM_COMPLETION_SEM_INITIAL_COUNT,
&msg_sem_attr
),
};
if (NULL == msg.completion_sem_id) {
SPM_PANIC("Could not create a semaphore for close message");
}
psa_close_async(handle, &msg);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
SPM_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
uint32_t psa_framework_version(void)
{
return (uint32_t)PSA_FRAMEWORK_VERSION;
}
uint32_t psa_version(uint32_t sid)
{
uint32_t version = PSA_VERSION_NONE;
spm_rot_service_t *service = rot_service_get(sid);
if (service != NULL) {
if ((get_active_partition() != NULL) || (service->allow_nspe)) {
version = service->min_version;
}
}
return version;
}

View File

@ -1,172 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cmsis_os2.h"
#include "mbed_atomic.h"
#include "psa_defs.h"
#include "spm_internal.h"
#include "spm_panic.h"
inline void validate_iovec(
const void *in_vec,
const uint32_t in_len,
const void *out_vec,
const uint32_t out_len
)
{
if (
!(
((in_vec != NULL) || (in_len == 0)) &&
((out_vec != NULL) || (out_len == 0)) &&
(in_len + out_len <= PSA_MAX_IOVEC)
)
) {
SPM_PANIC("Failed iovec Validation invec=(0X%p) inlen=(%lu) outvec=(0X%p) outlen=(%lu)\n", in_vec, in_len, out_vec, out_len);
}
}
inline void channel_state_switch(uint8_t *current_state, uint8_t expected_state, uint8_t new_state)
{
uint8_t actual_state = expected_state;
if (!core_util_atomic_cas_u8(current_state, &actual_state, new_state)) {
SPM_PANIC("channel in incorrect processing state: %hhu while %hhu is expected!\n",
actual_state, expected_state);
}
}
inline void channel_state_assert(const uint8_t *current_state, uint8_t expected_state)
{
uint8_t actual_state = core_util_atomic_load_u8(current_state);
if (actual_state != expected_state) {
SPM_PANIC("channel in incorrect processing state: %hhu while %hhu is expected!\n",
actual_state, expected_state);
}
}
extern const mem_region_t *mem_regions;
extern const uint32_t mem_region_count;
const mem_region_t *get_mem_regions(int32_t partition_id, uint32_t *region_count)
{
uint32_t i;
SPM_ASSERT(NULL != region_count);
*region_count = 0;
if (partition_id == MEM_PARTITIONS_ALL) {
*region_count = mem_region_count;
return mem_regions;
}
// The entries in the array of memory regions are grouped by partition id.
// This is ensured by the way this array is automatically generated from the manifest files.
for (i = 0; i < mem_region_count && mem_regions[i].partition_id != partition_id; i++);
if (i == mem_region_count) {
return NULL;
}
const mem_region_t *regions = &mem_regions[i];
for (; i < mem_region_count && mem_regions[i].partition_id == partition_id; i++, (*region_count)++);
return regions;
}
extern spm_db_t g_spm;
spm_partition_t *get_active_partition(void)
{
osThreadId_t active_thread_id = osThreadGetId();
SPM_ASSERT(NULL != active_thread_id);
for (uint32_t i = 0; i < g_spm.partition_count; ++i) {
if (g_spm.partitions[i].thread_id == active_thread_id) {
return &(g_spm.partitions[i]);
}
}
return NULL; // Valid in case of NSPE
}
bool is_buffer_accessible(const void *ptr, size_t size, spm_partition_t *accessing_partition)
{
if (NULL == ptr) {
return false;
}
if (size == 0) {
return true;
}
// Check wrap around of ptr + size
if (((uintptr_t)ptr + size - 1) < (uintptr_t)ptr) {
return false;
}
// Note: Sanity checks on platform addresses and sizes is done in psa_spm_init()
uint32_t secure_ram_base = PSA_SECURE_RAM_START;
size_t secure_ram_len = PSA_SECURE_RAM_SIZE;
uint32_t secure_rom_base = PSA_SECURE_ROM_START;
size_t secure_rom_len = PSA_SECURE_ROM_SIZE;
uint32_t non_secure_ram_base = PSA_NON_SECURE_RAM_START;
size_t non_secure_ram_len = PSA_NON_SECURE_RAM_SIZE;
uint32_t non_secure_rom_base = PSA_NON_SECURE_ROM_START;
size_t non_secure_rom_len = PSA_NON_SECURE_ROM_SIZE;
// Check NSPE case
if (accessing_partition == NULL) {
// Make sure the NSPE is accessing the non-secure ram range OR the non-secure flash range
// RAM
if (((uintptr_t)ptr >= (uintptr_t)non_secure_ram_base) && ((uintptr_t)ptr < ((uintptr_t)non_secure_ram_base + non_secure_ram_len)) &&
(((uintptr_t)ptr + size) <= ((uintptr_t)non_secure_ram_base + non_secure_ram_len))
) {
return true;
}
// FLASH
if (((uintptr_t)ptr >= (uintptr_t)non_secure_rom_base) && ((uintptr_t)ptr < ((uintptr_t)non_secure_rom_base + non_secure_rom_len)) &&
(((uintptr_t)ptr + size) <= ((uintptr_t)non_secure_rom_base + non_secure_rom_len))
) {
return true;
}
} else { // Check SPE case
// As we do not expect secure partitions to use SPE addresses for iovecs, we make sure here that the SPE is accessing
// the secure ram range OR the secure flash range
// RAM
if (((uintptr_t)ptr >= (uintptr_t)secure_ram_base) && ((uintptr_t)ptr < ((uintptr_t)secure_ram_base + secure_ram_len)) &&
(((uintptr_t)ptr + size) <= ((uintptr_t)secure_ram_base + secure_ram_len))
) {
return true;
}
// FLASH
if (((uintptr_t)ptr >= (uintptr_t)secure_rom_base) && ((uintptr_t)ptr < ((uintptr_t)secure_rom_base + secure_rom_len)) &&
(((uintptr_t)ptr + size) <= ((uintptr_t)secure_rom_base + secure_rom_len))
) {
return true;
}
}
return false;
}

View File

@ -1,167 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "rtx_os.h"
#include "spm_internal.h"
#include "handles_manager.h"
#include "spm_api.h"
MBED_STATIC_ASSERT(
MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS <= PSA_HANDLE_MGR_MAX_HANDLES_NUM,
"Number of channels exceeds maximum number of handles allowed in handles manager!"
);
MBED_STATIC_ASSERT(
MBED_CONF_SPM_IPC_MAX_NUM_OF_MESSAGES <= PSA_HANDLE_MGR_MAX_HANDLES_NUM,
"Number of active messages exceeds maximum number of handles allowed in handles manager!"
);
// Sanity check - memory ranges are well formed
MBED_STATIC_ASSERT(
(PSA_SECURE_RAM_START + PSA_SECURE_RAM_SIZE - 1) > PSA_SECURE_RAM_START,
"Illegal secure ram region!"
);
MBED_STATIC_ASSERT(
(PSA_SECURE_ROM_START + PSA_SECURE_ROM_SIZE - 1) > PSA_SECURE_ROM_START,
"Illegal secure flash region!"
);
MBED_STATIC_ASSERT(
(PSA_NON_SECURE_RAM_START + PSA_NON_SECURE_RAM_SIZE - 1) > PSA_NON_SECURE_RAM_START,
"Illegal non-secure ram region!"
);
MBED_STATIC_ASSERT(
(PSA_NON_SECURE_ROM_START + PSA_NON_SECURE_ROM_SIZE - 1) > PSA_NON_SECURE_ROM_START,
"Illegal non-secure flash region!"
);
MBED_STATIC_ASSERT(
(PSA_SHARED_RAM_START + PSA_SHARED_RAM_SIZE - 1) > PSA_SHARED_RAM_START,
"Illegal shared ram region!"
);
// Sanity check - memory ranges are not overlapping
#ifndef MIN
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
#endif
#ifndef MAX
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
#endif
#define OVERLAP_CHECK( name1, start1, size1, name2, start2, size2) \
MBED_STATIC_ASSERT( \
MAX(start1, start2) >= MIN((start1 + size1), (start2 + size2)), \
name1 " and " name2 " are overlapping!!!" \
)
OVERLAP_CHECK(
"PSA_SECURE_RAM", PSA_SECURE_RAM_START, PSA_SECURE_RAM_SIZE,
"PSA_NON_SECURE_RAM", PSA_NON_SECURE_RAM_START, PSA_NON_SECURE_RAM_SIZE
);
OVERLAP_CHECK(
"PSA_SECURE_RAM", PSA_SECURE_RAM_START, PSA_SECURE_RAM_SIZE,
"PSA_SHARED_RAM", PSA_SHARED_RAM_START, PSA_SHARED_RAM_SIZE
);
OVERLAP_CHECK(
"PSA_SHARED_RAM", PSA_SHARED_RAM_START, PSA_SHARED_RAM_SIZE,
"PSA_NON_SECURE_RAM", PSA_NON_SECURE_RAM_START, PSA_NON_SECURE_RAM_SIZE
);
OVERLAP_CHECK(
"PSA_SECURE_FLASH", PSA_SECURE_ROM_START, PSA_SECURE_ROM_SIZE,
"PSA_NON_SECURE_FLASH", PSA_NON_SECURE_ROM_START, PSA_NON_SECURE_ROM_SIZE
);
psa_handle_item_t g_channels_handle_storage[MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS] = {0};
spm_ipc_channel_t g_channel_data[MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS] = {0};
osRtxMemoryPool_t g_channel_mem_pool_storage = {0};
osMemoryPoolAttr_t g_channel_mem_pool_attr = {
.name = "SPM_channel_pool",
.attr_bits = 0,
.cb_mem = &g_channel_mem_pool_storage,
.cb_size = sizeof(g_channel_mem_pool_storage),
.mp_mem = g_channel_data,
.mp_size = sizeof(g_channel_data)
};
psa_handle_item_t g_messages_handle_storage[MBED_CONF_SPM_IPC_MAX_NUM_OF_MESSAGES] = {0};
spm_active_msg_t g_active_messages_data[MBED_CONF_SPM_IPC_MAX_NUM_OF_MESSAGES] = {0};
osRtxMemoryPool_t g_active_messages_mem_pool_storage = {0};
osMemoryPoolAttr_t g_active_messages_mem_pool_attr = {
.name = "SPM_active_messages_pool",
.attr_bits = 0,
.cb_mem = &g_active_messages_mem_pool_storage,
.cb_size = sizeof(g_active_messages_mem_pool_storage),
.mp_mem = g_active_messages_data,
.mp_size = sizeof(g_active_messages_data)
};
spm_db_t g_spm = {
.partitions = NULL,
.partition_count = 0,
.channels_handle_mgr = {
.handle_generator = PSA_HANDLE_MGR_INVALID_HANDLE,
.pool_size = MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS,
.handles_pool = g_channels_handle_storage
},
.messages_handle_mgr = {
.handle_generator = PSA_HANDLE_MGR_INVALID_HANDLE,
.pool_size = MBED_CONF_SPM_IPC_MAX_NUM_OF_MESSAGES,
.handles_pool = g_messages_handle_storage
},
.channel_mem_pool = NULL,
.active_messages_mem_pool = NULL
};
// forward declaration
uint32_t init_partitions(spm_partition_t **partitions);
void psa_spm_init(void)
{
spm_hal_memory_protection_init();
g_spm.channel_mem_pool = osMemoryPoolNew(
MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS,
sizeof(spm_ipc_channel_t),
&g_channel_mem_pool_attr
);
if (NULL == g_spm.channel_mem_pool) {
error("%s - Failed to create channel memory pool!\n", __func__);
}
g_spm.active_messages_mem_pool = osMemoryPoolNew(
MBED_CONF_SPM_IPC_MAX_NUM_OF_MESSAGES,
sizeof(spm_active_msg_t),
&g_active_messages_mem_pool_attr
);
if (NULL == g_spm.active_messages_mem_pool) {
error("%s - Failed to create active messages memory pool!\n", __func__);
}
g_spm.partition_count = init_partitions(&(g_spm.partitions));
}

View File

@ -1,250 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SPM_INTERNAL_H
#define SPM_INTERNAL_H
#include <stdbool.h>
#include "cmsis_os2.h"
#include "cmsis.h"
#include "psa_defs.h"
#include "spm_messages.h"
#include "spm_panic.h"
#include "handles_manager.h"
#include "cmsis_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SPM_COMPLETION_SEM_MAX_COUNT (1UL) /* Maximum number of available tokens for a completion semaphore. */
#define SPM_COMPLETION_SEM_INITIAL_COUNT (0UL) /* Initial number of available tokens for a completion semaphore. */
#define PSA_MMIO_PERM_READ_ONLY (0x000000001)
#define PSA_MMIO_PERM_READ_WRITE (0x000000003)
#define PSA_RESERVED_ERROR_MIN (INT32_MIN + 1)
#define PSA_RESERVED_ERROR_MAX (INT32_MIN + 127)
#define SPM_CHANNEL_STATE_INVALID (0x01)
#define SPM_CHANNEL_STATE_CONNECTING (0x02)
#define SPM_CHANNEL_STATE_IDLE (0x03)
#define SPM_CHANNEL_STATE_PENDING (0x04)
#define SPM_CHANNEL_STATE_ACTIVE (0x05)
#define MEM_PARTITIONS_ALL (0) /* A constant to use to retrieve the memory regions for all the partitions at once. */
#define SPM_CMSIS_RTOS_ERROR_BIT_MSK (0x80000000)
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
struct spm_partition;
struct spm_ipc_channel;
/*
* Structure to describe MMIO region along with owning partition.
*/
typedef struct mem_region {
const uint32_t base;
const uint32_t size;
const uint32_t permission;
const int32_t partition_id;
} mem_region_t;
typedef union spm_iovec {
psa_invec in;
psa_outvec out;
} spm_iovec_t;
/*
* IRQ signal mapper definition.
* The function will not return on invalid signal.
*/
typedef IRQn_Type(*spm_signal_to_irq_mapper_t)(uint32_t);
/*
* Structure to aggregate channels queue in a Root of Trust Service.
*/
typedef struct spm_channel_linked_list {
struct spm_ipc_channel *head; /* List's first object*/
struct spm_ipc_channel *tail; /* List's last object*/
} spm_channel_linked_list_t;
/*
* Structure containing resources and attributes of a Root of Trust Service.
*/
typedef struct spm_rot_service {
const uint32_t sid; /* The Root of Trust Service ID.*/
const uint32_t mask; /* The signal for this Root of Trust Service*/
struct spm_partition *partition; /* Pointer to the Partition which the Root of Trust Service belongs to.*/
const uint32_t min_version; /* Minor version of the Root of Trust Service interface.*/
const uint32_t min_version_policy; /* Minor version policy of the Root of Trust Service.*/
const bool allow_nspe; /* Whether to allow non-secure clients to connect to the Root of Trust Service.*/
spm_channel_linked_list_t queue; /* Queue of channels holding ROT_SRV operations waiting to be served. */
} spm_rot_service_t;
/*
* Structure containing Partition->RoT-Service channel information.
*/
typedef struct spm_ipc_channel {
struct spm_partition *src_partition; /* Pointer to the Partition which connects to the Root of Trust Service.*/
spm_rot_service_t *dst_rot_service; /* Pointer to the connected Root of Trust Service.*/
void *rhandle; /* Reverse handle to be used for this channel.*/
void *msg_ptr; /* Message data sent from user. */
struct spm_ipc_channel *next; /* Next channel in the chain.*/
uint8_t msg_type; /* The message type.*/
uint8_t state; /* The current processing state of the channel.*/
uint8_t is_dropped; /* Indicates whether the channel has been dropped by the partition.*/
} spm_ipc_channel_t;
/*
* Structure containing the currently active message for a Root of Trust Service.
*/
typedef struct spm_active_msg {
spm_ipc_channel_t *channel; /* Pointer to the channel delivering this message.*/
spm_iovec_t iovecs[PSA_MAX_IOVEC]; /* IOvecs sent for message and response.*/
uint8_t out_index; /* First index of outvecs in iovecs*/
} spm_active_msg_t;
/*
* Structure containing resources and attributes of a secure partition.
*/
typedef struct spm_partition {
const int32_t partition_id; /* The Partition ID.*/
osThreadId_t thread_id; /* Thread ID of the Partition thread.*/
const uint32_t flags; /* Mask of all the signals the partition supports.*/
spm_rot_service_t *rot_services; /* Array of the Partition's Root of Trust Services.*/
const uint32_t rot_services_count; /* Number of the Partition's Root of Trust Services.*/
const uint32_t *extern_sids; /* Array of Root of Trust Service IDs that the partition can connect to.*/
const uint32_t extern_sids_count; /* Number of Root of Trust Services which the partition can connect to.*/
osMutexId_t mutex; /* Mutex for all rot_service's queues operations. */
spm_signal_to_irq_mapper_t irq_mapper; /* a function which maps signal to irq number*/
} spm_partition_t;
/*
* Structure containing the SPM internal data.
*/
typedef struct spm_db {
spm_partition_t *partitions; /* Array of all the Secure Partitions in the system.*/
uint32_t partition_count; /* Number of Secure Partitions in the system.*/
psa_handle_manager_t channels_handle_mgr;
psa_handle_manager_t messages_handle_mgr;
osMemoryPoolId_t channel_mem_pool; /* Channel memory pool identifier.*/
osMemoryPoolId_t active_messages_mem_pool; /* Channel memory pool identifier.*/
} spm_db_t;
/*
* Returns a pointer to the currently active secure partition or NULL in case called from NSPE.
*/
spm_partition_t *get_active_partition(void);
/*
* Return an array of memory regions used by a given partition.
*
* @param[in] partition_id - a partition ID to find memory regions for, if MEM_PARTITIONS_ALL then
* memory regions for all the partitions are returned
* @param[out] region_count - will be set to the number of memory regions returned
*/
const mem_region_t *get_mem_regions(int32_t partition_id, uint32_t *region_count);
// Platform dependent APIs
/*
* Validates that a memory block accessible from a specific partition
*
* @param[in] ptr - Pointer to the beggining of the memory block.
* @param[in] size - Size of the memory block in bytes.
* @param[in] accessing_partition - Which partition is trying to access the memory.
* @return `true` if the entire memory block is accessable from given partition.
*/
bool is_buffer_accessible(const void *ptr, size_t size, spm_partition_t *accessing_partition);
/**
* Alerts NSPE that a proccess (connect or call) has ended.
*
* @param[in] completion_sem_id - semaphore id in NSPE.
*/
void nspe_done(osSemaphoreId_t completion_sem_id);
/*
* Validates parameters sent from caller and queues a connect message on the correct ROT_SRV.
*
* @param[in] sid - desired RoT service ID
* @param[in] msg - pointer to connect message struct
*/
void psa_connect_async(uint32_t sid, spm_pending_connect_msg_t *msg);
/*
* Validates parameters sent from caller and queues a call message on the correct ROT_SRV.
*
* @param[in] handle - channel handle for the connection
* @param[in] msg - pointer to call message struct
*/
void psa_call_async(psa_handle_t handle, spm_pending_call_msg_t *msg);
/*
* Validates parameters sent from caller and queues a disconnect message on the correct ROT_SRV.
*
* @param[in] handle - handle of channel to close
* @param[in] msg - pointer to close message struct
*/
void psa_close_async(psa_handle_t handle, spm_pending_close_msg_t *msg);
/*
* Validates IOvecs.
*
* @param[in] in_vec - psa_invec array
* @param[in] in_len - number of elements in in_vec
* @param[in] out_vec - psa_outvec array
* @param[in] out_len - number of elements in out_vec
*/
void validate_iovec(
const void *in_vec,
const uint32_t in_len,
const void *out_vec,
const uint32_t out_len
);
/*
* Assert and modify PSA IPC channel state machine state
*
* @param[in,out] current_state - current state
* @param[in] expected_state - expected state
* @param[in] new_state - new state
*/
void channel_state_switch(uint8_t *current_state, uint8_t expected_state, uint8_t new_state);
/*
* Assert PSA IPC channel state machine state
*
* @param[in] current_state - current state
* @param[in] expected_state - expected state
*/
void channel_state_assert(const uint8_t *current_state, uint8_t expected_state);
#ifdef __cplusplus
}
#endif
#endif // SPM_INTERNAL_H

View File

@ -1,34 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(COMPONENT_SPM_MAILBOX)
#include "ipc_queue.h"
extern ipc_consumer_queue_t *cons_queue;
// this is the dispatcher thread for dual-chip systems
int main(void)
{
while (true) {
ipc_queue_drain(cons_queue);
}
}
#else
#error "Non dual-chip platforms are not yet supported"
#endif // defined(COMPONENT_SPM_MAILBOX)

View File

@ -1,66 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_SPM_PANIC_H__
#define __MBED_SPM_PANIC_H__
/** @addtogroup SPM
* @{
*/
#include "mbed_toolchain.h"
#include "mbed_assert.h"
#include "mbed_error.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef SPM_SPE_BUILD
#error "Trying to build for SPE with SPM_SPE_BUILD flag - Not supported"
#else
/**
* Generate a system panic
*
* @param[in] format The format string to output on panic
* @param[in] ... (Additional arguments) Depending on the format string
*/
#define SPM_PANIC(format, ...) error("%s %u: " format, __func__, __LINE__, ##__VA_ARGS__)
/**
* Assert on condition (debug build only)
*
* @param[in] expr Condition to be asserted
*/
#define SPM_ASSERT(expr) MBED_ASSERT(expr)
#endif
#ifdef __cplusplus
}
#endif
/** @}*/ // end of SPM group
#endif // __MBED_SPM_PANIC_H__

View File

@ -1,564 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include "mbed_toolchain.h"
#include "spm_server.h"
#include "spm_messages.h"
#include "spm_internal.h"
#include "spm_panic.h"
#include "handles_manager.h"
#include "cmsis.h"
extern spm_db_t g_spm;
static inline spm_partition_t *get_partition_by_pid(int32_t partition_id)
{
for (uint32_t i = 0; i < g_spm.partition_count; ++i) {
if (g_spm.partitions[i].partition_id == partition_id) {
return &(g_spm.partitions[i]);
}
}
return NULL;
}
static inline psa_handle_t create_msg_handle(void *handle_mem, int32_t friend_pid)
{
return psa_hndl_mgr_handle_create(&(g_spm.messages_handle_mgr), handle_mem, friend_pid);
}
static inline spm_active_msg_t *get_msg_from_handle(psa_handle_t handle)
{
return (spm_active_msg_t *)psa_hndl_mgr_handle_get_mem(&(g_spm.messages_handle_mgr), handle);
}
static inline void destroy_msg_handle(psa_handle_t handle)
{
psa_hndl_mgr_handle_destroy(&(g_spm.messages_handle_mgr), handle);
}
static inline void destroy_channel_handle(psa_handle_t handle)
{
psa_hndl_mgr_handle_destroy(&(g_spm.channels_handle_mgr), handle);
}
static inline spm_rot_service_t *get_rot_service(spm_partition_t *prt, psa_signal_t signal)
{
for (size_t i = 0; i < prt->rot_services_count; i++) {
if (prt->rot_services[i].mask == signal) {
return &prt->rot_services[i];
}
}
return NULL;
}
/*
* This function validates the parameters sent from the user and copies it to an active message
*
* Function assumptions:
* * channel is allocated from SPM Core memory
* * channel->msg_ptr potentially allocated from nonsecure memory
* * user_msg allocated from secure partition memory - not trusted by SPM Core
*/
static void copy_message_to_spm(spm_ipc_channel_t *channel, psa_msg_t *user_msg)
{
// Memory allocated from MemoryPool isn't zeroed - thus a temporary variable will make sure we will start from a clear state.
spm_active_msg_t temp_active_message = {
.channel = channel,
.iovecs = {{.in = {0}}},
.out_index = 0,
};
if (channel->msg_type == PSA_IPC_CALL) {
if (!is_buffer_accessible(channel->msg_ptr, sizeof(spm_pending_call_msg_t), channel->src_partition)) {
SPM_PANIC("message data is inaccessible\n");
}
spm_pending_call_msg_t *call_msg_data = (spm_pending_call_msg_t *)channel->msg_ptr;
// Copy pointers and sizes to secure memory to prevent TOCTOU
const psa_invec *temp_invec = call_msg_data->in_vec;
const uint32_t temp_invec_size = call_msg_data->in_vec_size;
const psa_outvec *temp_outvec = call_msg_data->out_vec;
const uint32_t temp_outvec_size = call_msg_data->out_vec_size;
validate_iovec(temp_invec, temp_invec_size, temp_outvec, temp_outvec_size);
temp_active_message.out_index = (uint8_t)temp_invec_size;
if (temp_invec_size > 0) {
if (!is_buffer_accessible(temp_invec, temp_invec_size * sizeof(*temp_invec), channel->src_partition)) {
SPM_PANIC("in_vec is inaccessible\n");
}
for (uint32_t i = 0; i < temp_invec_size; ++i) {
if (temp_invec[i].len == 0) {
continue;
}
// Copy struct
temp_active_message.iovecs[i].in = temp_invec[i];
user_msg->in_size[i] = temp_invec[i].len;
// Copy then check to prevent TOCTOU
if (!is_buffer_accessible(
temp_active_message.iovecs[i].in.base,
temp_active_message.iovecs[i].in.len,
channel->src_partition)) {
SPM_PANIC("in_vec[%ld] is inaccessible\n", i);
}
}
}
if (temp_outvec_size > 0) {
if (!is_buffer_accessible(temp_outvec, temp_outvec_size * sizeof(*temp_outvec), channel->src_partition)) {
SPM_PANIC("out_vec is inaccessible\n");
}
for (uint32_t i = 0; i < temp_outvec_size; ++i) {
if (temp_outvec[i].len == 0) {
continue;
}
// Copy struct
temp_active_message.iovecs[temp_invec_size + i].out = temp_outvec[i];
user_msg->out_size[i] = temp_outvec[i].len;
// Copy then check to prevent TOCTOU
if (!is_buffer_accessible(
temp_active_message.iovecs[temp_invec_size + i].out.base,
temp_active_message.iovecs[temp_invec_size + i].out.len,
channel->src_partition)) {
SPM_PANIC("out_vec[%lu] is inaccessible\n", i);
}
}
}
}
// Allocating from SPM-Core internal memory
spm_active_msg_t *active_msg = (spm_active_msg_t *)osMemoryPoolAlloc(g_spm.active_messages_mem_pool, osWaitForever);
if (NULL == active_msg) {
SPM_PANIC("Could not allocate active message");
}
// Copy struct
*active_msg = temp_active_message;
psa_handle_t handle = create_msg_handle(active_msg, PSA_HANDLE_MGR_INVALID_FRIEND_OWNER);
user_msg->type = channel->msg_type;
user_msg->rhandle = channel->rhandle;
user_msg->handle = handle;
if (channel->src_partition == NULL) {
user_msg->client_id = PSA_NSPE_IDENTIFIER;
} else {
user_msg->client_id = channel->src_partition->partition_id;
}
}
static spm_ipc_channel_t *spm_rot_service_queue_dequeue(spm_rot_service_t *rot_service)
{
osStatus_t os_status = osMutexAcquire(rot_service->partition->mutex, osWaitForever);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
spm_ipc_channel_t *ret = rot_service->queue.head;
if (ret == NULL) {
SPM_PANIC("Dequeue from empty queue");
}
rot_service->queue.head = ret->next;
ret->next = NULL;
if (rot_service->queue.head == NULL) {
rot_service->queue.tail = NULL;
uint32_t flags = osThreadFlagsClear(rot_service->mask);
// osThreadFlagsClear() sets the msb on failure
SPM_ASSERT((flags & SPM_CMSIS_RTOS_ERROR_BIT_MSK) == 0);
SPM_ASSERT(flags & rot_service->mask);
PSA_UNUSED(flags);
}
os_status = osMutexRelease(rot_service->partition->mutex);
SPM_ASSERT(osOK == os_status);
return ret;
}
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout)
{
spm_partition_t *curr_partition = get_active_partition();
SPM_ASSERT(NULL != curr_partition); // active thread in SPM must be in partition DB
psa_signal_t flags_all = curr_partition->flags | PSA_DOORBELL;
if (signal_mask == PSA_WAIT_ANY) {
signal_mask = flags_all;
} else {
if ((~flags_all) & signal_mask) {
SPM_PANIC("signal mask 0x%lx must have only bits from 0x%lx!\n",
signal_mask, flags_all);
}
}
psa_signal_t asserted_signals = osThreadFlagsWait(
signal_mask,
osFlagsWaitAny | osFlagsNoClear,
(PSA_BLOCK & timeout) ? osWaitForever : 0
);
// Asserted_signals must be a subset of the supported ROT_SRV and interrupt signals.
SPM_ASSERT((asserted_signals == (asserted_signals & flags_all)) ||
((PSA_BLOCK != timeout) && (osFlagsErrorTimeout == asserted_signals)));
return (osFlagsErrorTimeout == asserted_signals) ? 0 : asserted_signals;
}
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg)
{
spm_partition_t *curr_partition = get_active_partition();
SPM_ASSERT(NULL != curr_partition); // active thread in SPM must be in partition DB
if (!is_buffer_accessible(msg, sizeof(*msg), curr_partition)) {
SPM_PANIC("msg is inaccessible\n");
}
memset(msg, 0, sizeof(*msg));
// signal must be ONLY ONE of the bits of curr_partition->flags_rot_srv
bool is_one_bit = ((signal != 0) && !(signal & (signal - 1)));
if (!is_one_bit || !(signal & curr_partition->flags)) {
SPM_PANIC(
"signal 0x%lx must have only 1 bit ON and must be a subset of 0x%lx!\n",
signal,
curr_partition->flags
);
}
uint32_t active_flags = osThreadFlagsGet();
if (0 == (signal & active_flags)) {
SPM_PANIC("flag is not active!\n");
}
spm_rot_service_t *curr_rot_service = get_rot_service(curr_partition, signal);
if (curr_rot_service == NULL) {
SPM_PANIC("Received signal (0x%08lx) that does not match any root of trust service", signal);
}
spm_ipc_channel_t *curr_channel = spm_rot_service_queue_dequeue(curr_rot_service);
switch (curr_channel->msg_type) {
case PSA_IPC_CONNECT:
channel_state_assert(
&curr_channel->state,
SPM_CHANNEL_STATE_CONNECTING
);
break;
case PSA_IPC_CALL:
channel_state_switch(
&curr_channel->state,
SPM_CHANNEL_STATE_PENDING,
SPM_CHANNEL_STATE_ACTIVE
);
break;
case PSA_IPC_DISCONNECT: {
channel_state_assert(
&curr_channel->state,
SPM_CHANNEL_STATE_IDLE
);
break;
}
default:
SPM_PANIC("psa_get - unexpected message type=0x%08hhX", curr_channel->msg_type);
break;
}
copy_message_to_spm(curr_channel, msg);
return PSA_SUCCESS;
}
static size_t read_or_skip(psa_handle_t msg_handle, uint32_t invec_idx, void *buf, size_t num_bytes)
{
spm_active_msg_t *active_msg = get_msg_from_handle(msg_handle);
channel_state_assert(&active_msg->channel->state, SPM_CHANNEL_STATE_ACTIVE);
if (invec_idx >= PSA_MAX_IOVEC) {
SPM_PANIC("Invalid invec_idx\n");
}
if (invec_idx >= active_msg->out_index) {
return 0;
}
psa_invec *active_iovec = &active_msg->iovecs[invec_idx].in;
if (num_bytes > active_iovec->len) {
num_bytes = active_iovec->len;
}
if (num_bytes > 0) {
if (buf) {
memcpy(buf, active_iovec->base, num_bytes);
}
active_iovec->base = (void *)((uint8_t *)active_iovec->base + num_bytes);
active_iovec->len -= num_bytes;
}
return num_bytes;
}
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, void *buf, size_t num_bytes)
{
spm_partition_t *curr_partition = get_active_partition();
SPM_ASSERT(NULL != curr_partition); // active thread in SPM must be in partition DB
if (!is_buffer_accessible(buf, num_bytes, curr_partition)) {
SPM_PANIC("buffer is inaccessible\n");
}
return read_or_skip(msg_handle, invec_idx, buf, num_bytes);
}
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes)
{
return read_or_skip(msg_handle, invec_idx, NULL, num_bytes);
}
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, const void *buffer, size_t num_bytes)
{
if (0 == num_bytes) {
return;
}
spm_partition_t *curr_partition = get_active_partition();
SPM_ASSERT(NULL != curr_partition); // active thread in S
if (!is_buffer_accessible(buffer, num_bytes, curr_partition)) {
SPM_PANIC("buffer is inaccessible\n");
}
spm_active_msg_t *active_msg = get_msg_from_handle(msg_handle);
channel_state_assert(&active_msg->channel->state, SPM_CHANNEL_STATE_ACTIVE);
outvec_idx += active_msg->out_index;
if (outvec_idx >= PSA_MAX_IOVEC) {
SPM_PANIC("Invalid outvec_idx\n");
}
psa_outvec *active_iovec = &active_msg->iovecs[outvec_idx].out;
if (num_bytes > active_iovec->len) {
SPM_PANIC("Invalid write operation (Requested %zu, Avialable %zu)\n", num_bytes, active_iovec->len);
}
memcpy((uint8_t *)(active_iovec->base), buffer, num_bytes);
active_iovec->base = (void *)((uint8_t *)active_iovec->base + num_bytes);
active_iovec->len -= num_bytes;
return;
}
void psa_reply(psa_handle_t msg_handle, psa_status_t status)
{
spm_active_msg_t *active_msg = get_msg_from_handle(msg_handle);
spm_ipc_channel_t *active_channel = active_msg->channel;
SPM_ASSERT(active_channel != NULL);
SPM_ASSERT(active_channel->msg_ptr != NULL);
// !!!!!NOTE!!!!! handles must be destroyed before osMemoryPoolFree().
// Message creation blocked on resource exhaustion and handle will be created
// only after a successful memory allocation and is not expected to fail.
{
destroy_msg_handle(msg_handle);
memset(active_msg, 0, sizeof(*active_msg));
osStatus_t os_status = osMemoryPoolFree(g_spm.active_messages_mem_pool, active_msg);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
osSemaphoreId_t completion_sem_id = NULL;
bool nspe_call = (active_channel->src_partition == NULL);
switch (active_channel->msg_type) {
case PSA_IPC_CONNECT: {
if ((status != PSA_SUCCESS) && (status != PSA_CONNECTION_REFUSED)) {
SPM_PANIC("status (0X%08lx) is not allowed for PSA_IPC_CONNECT", status);
}
spm_pending_connect_msg_t *connect_msg_data = (spm_pending_connect_msg_t *)(active_channel->msg_ptr);
completion_sem_id = connect_msg_data->completion_sem_id;
if (status == PSA_CONNECTION_REFUSED) {
channel_state_assert(&active_channel->state, SPM_CHANNEL_STATE_CONNECTING);
// !!!!!NOTE!!!!! handles must be destroyed before osMemoryPoolFree().
// Channel creation fails on resource exhaustion and handle will be created
// only after a successful memory allocation and is not expected to fail.
{
// In psa_connect the handle was written to user's memory before
// the connection was established.
// Channel state machine and ACL will prevent attacker from
// doing bad stuff before we overwrite it with a negative return code.
destroy_channel_handle((psa_handle_t)connect_msg_data->rc);
memset(active_channel, 0, sizeof(*active_channel));
osStatus_t os_status = osMemoryPoolFree(g_spm.channel_mem_pool, active_channel);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
// Replace the handle we created in the user's memory with the error code
connect_msg_data->rc = status;
active_channel = NULL;
} else {
channel_state_switch(&active_channel->state,
SPM_CHANNEL_STATE_CONNECTING, SPM_CHANNEL_STATE_IDLE);
}
break;
}
case PSA_IPC_CALL: {
if ((status >= PSA_RESERVED_ERROR_MIN) && (status <= PSA_RESERVED_ERROR_MAX)) {
SPM_PANIC("status (0X%08lx) is not allowed for PSA_IPC_CALL", status);
}
channel_state_switch(&active_channel->state,
SPM_CHANNEL_STATE_ACTIVE, SPM_CHANNEL_STATE_IDLE);
if (status == PSA_DROP_CONNECTION) {
active_channel->is_dropped = TRUE;
}
spm_pending_call_msg_t *call_msg_data = (spm_pending_call_msg_t *)(active_channel->msg_ptr);
call_msg_data->rc = status;
completion_sem_id = call_msg_data->completion_sem_id;
break;
}
case PSA_IPC_DISCONNECT: {
spm_pending_close_msg_t *close_msg_data = (spm_pending_close_msg_t *)(active_channel->msg_ptr);
completion_sem_id = close_msg_data->completion_sem_id;
channel_state_switch(&(active_channel->state),
SPM_CHANNEL_STATE_IDLE,
SPM_CHANNEL_STATE_INVALID
);
// !!!!!NOTE!!!!! handles must be destroyed before osMemoryPoolFree().
// Channel creation fails on resource exhaustion and handle will be created
// only after a successful memory allocation and is not expected to fail.
{
destroy_channel_handle(close_msg_data->handle);
memset(active_channel, 0, sizeof(*active_channel));
osStatus_t os_status = osMemoryPoolFree(g_spm.channel_mem_pool, active_channel);
active_channel = NULL;
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
break;
// Note: The status code is ignored for PSA_IPC_DISCONNECT message type
}
default:
SPM_PANIC("psa_reply() - Unexpected message type=0x%08hhX", active_channel->msg_type);
break;
}
if (active_channel != NULL) {
active_channel->msg_ptr = NULL;
active_channel->msg_type = 0; // uninitialized
}
if (nspe_call) {
nspe_done(completion_sem_id);
} else {
osStatus_t os_status = osSemaphoreRelease(completion_sem_id);
SPM_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
return;
}
void psa_notify(int32_t partition_id)
{
spm_partition_t *target_partition = get_partition_by_pid(partition_id);
if (NULL == target_partition) {
SPM_PANIC("Could not find partition (partition_id = %ld)\n",
partition_id
);
}
uint32_t flags = osThreadFlagsSet(target_partition->thread_id, PSA_DOORBELL);
// osThreadFlagsSet() sets the msb on failure
// flags is allowed to be 0 since by the time osThreadFlagsSet() returns
// the flag could have been cleared by another thread
SPM_ASSERT((flags & SPM_CMSIS_RTOS_ERROR_BIT_MSK) == 0);
PSA_UNUSED(flags);
}
void psa_clear(void)
{
uint32_t flags = osThreadFlagsClear(PSA_DOORBELL);
// osThreadFlagsClear() sets the msb on failure
SPM_ASSERT((flags & SPM_CMSIS_RTOS_ERROR_BIT_MSK) == 0);
// psa_clear() must not be called when doorbell signal is not currently asserted
if ((flags & PSA_DOORBELL) != PSA_DOORBELL) {
SPM_PANIC("psa_call() called without signaled doorbell\n");
}
}
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
{
spm_active_msg_t *active_msg = get_msg_from_handle(msg_handle);
active_msg->channel->rhandle = rhandle;
}
void psa_eoi(uint32_t irq_signal)
{
spm_partition_t *curr_partition = get_active_partition();
SPM_ASSERT(NULL != curr_partition);
if (curr_partition->irq_mapper == NULL) {
SPM_PANIC("Try to clear an interrupt flag without declaring IRQ");
}
if (0 == (curr_partition->flags & irq_signal)) {
SPM_PANIC("Signal %lu not in irq range\n", irq_signal);
}
bool is_one_bit = ((irq_signal != 0) && !(irq_signal & (irq_signal - 1)));
if (!is_one_bit) {
SPM_PANIC("signal 0x%lx must have only 1 bit ON!\n", irq_signal);
}
IRQn_Type irq_line = curr_partition->irq_mapper(irq_signal);
uint32_t flags = osThreadFlagsClear(irq_signal);
// osThreadFlagsClear() sets the msb on failure
SPM_ASSERT((flags & SPM_CMSIS_RTOS_ERROR_BIT_MSK) == 0);
// psa_eoi() must not be called with an unasserted flag.
if ((flags & irq_signal) != irq_signal) {
SPM_PANIC("psa_eoi() called without signaled IRQ\n");
}
NVIC_EnableIRQ(irq_line);
}

View File

@ -1,152 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_SPM_SERVER_H__
#define __MBED_SPM_SERVER_H__
/** @addtogroup SPM
* The Secure Partition Manager (SPM) is responsible for isolating software in partitions,@n
* managing the execution of software within partitions and providing IPC between partitions.
* @{
*/
/* -------------------------------------- Includes ----------------------------------- */
#include "psa_defs.h"
/* --------------------------------- extern "C" wrapper ------------------------------ */
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup RoT-Service-API
* The C interface for a root of trust (RoT) Service in a partition.
* @{
*/
/**
* Return the signals that have been asserted.@n
*
* @param[in] signal_mask A set of signals to query.
* @param[in] timeout timeout value:@n
* @a PSA_BLOCK block the caller until any signal is asserted.@n
* @a PSA_POLL Returns immediately.
* @return asserted signals.
*/
psa_signal_t psa_wait(psa_signal_t signal_mask, uint32_t timeout);
/**
* Get the message that corresponds to a given signal.
*
* @param[in] signal An asserted signal returned from psa_wait().
* @param[out] msg Pointer to a psa_msg structure.
* @return 0 for success or@n
* @a PSA_ERR_NOMSG if the message could not be delivered.
*/
psa_status_t psa_get(psa_signal_t signal, psa_msg_t *msg);
/**
* Associate the caller-provided private data with a specified handle.
*
* @param[in] msg_handle Handle for the caller's message.
* @param[in] rhandle Reverse handle allocated by the Root of Trust Service.
*/
void psa_set_rhandle(psa_handle_t msg_handle, void *rhandle);
/**
* Copy up to @a len bytes from position @a offset within the client message
* payload into the Secure Partition buffer @a buffer.@n
*
* @note Callers should know how much data is available to read based on the@n
* @a size attribute of the psa_msg structure returned from psa_get().@n
* The copy is truncated if the requested range extends beyond the end of the payload.@n
* In such a case, the remaining space in @a buffer is not modified.
*
* @param[in] msg_handle Handle for the client's message.
* @param[in] invec_idx ::psa_invec index to be read.
* @param[out] buf Buffer to copy the requested data to.
* @param[in] num_bytes Number of bytes to read from the client's message payload.
* @return Number of bytes copied or 0 if offset is greater than the size attribute of psa_msg.
*/
size_t psa_read(psa_handle_t msg_handle, uint32_t invec_idx, void *buf, size_t num_bytes);
/**
* Advance the current read offset by skipping @a num_bytes bytes for input vector
* indexed by @а invec_idx.@n
* If @a num_bytes is greater than the remaining number of bytes in the vector, then
* all the remaining bytes are skipped.
*
* @param[in] msg_handle Handle for the client's message.
* @param[in] invec_idx ::psa_invec index to be skipped.
* @param[in] num_bytes Number of bytes to skip.
* @return Number of bytes skipped or 0 if offset is greater than the size attribute of psa_msg.
*/
size_t psa_skip(psa_handle_t msg_handle, uint32_t invec_idx, size_t num_bytes);
/**
* Write a response payload of @a bytes bytes starting at position @a offset in the client's response buffer.
*
* @note If the caller writes data beyond the client's response buffer size
* (@a response_size attribute of the psa_msg structure returned from psa_get()) a fatal error occurs.
*
* @param[in] msg_handle Handle for the client's message.
* @param[in] outvec_idx ::psa_outvec index to be written to.
* @param[in] buffer Buffer with the data to write.
* @param[in] num_bytes Number of bytes to write.
*/
void psa_write(psa_handle_t msg_handle, uint32_t outvec_idx, const void *buffer, size_t num_bytes);
/**
* Complete handling of specific message and unblocks the client.
*
* A return code must be specified, which is sent to the client.@n
* Negative return code represent errors; positive integers are application-specific.
*
* @param[in] msg_handle Handle for the client's message.
* @param[in] status Message result value to be reported to the client.
*/
void psa_reply(psa_handle_t msg_handle, psa_status_t status);
/**
* Send a doorbell signal to a specific partition that is listening for that signal type.
*
* @param[in] partition_id partition ID of the target partition.
*/
void psa_notify(int32_t partition_id);
/**
* Clear the doorbell signal.
*/
void psa_clear(void);
/**
* Inform the SPM that an interrupt has been handled (end of interrupt).
*
* @param[in] irq_signal The interrupt signal that has been processed.
*/
void psa_eoi(uint32_t irq_signal);
/** @}*/ // end of RoT-Service-API group
#ifdef __cplusplus
}
#endif
/** @}*/ // end of SPM group
#endif /* __MBED_SPM_SERVER_H__ */

View File

@ -1,229 +0,0 @@
/* Copyright (c) 2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Includes
// --------
#include <stdio.h>
#include "ipc_defs.h"
#include "ipc_queue.h"
#include "spm_client.h"
#include "spm_messages.h"
#include "mbed_assert.h"
#include "cmsis_os2.h"
// Globals
// -------
extern ipc_producer_queue_t *prod_queue;
// API Functions Implementation
// ----------------------------
uint32_t psa_framework_version(void)
{
return (uint32_t)PSA_FRAMEWORK_VERSION;
}
uint32_t psa_version(uint32_t sid)
{
osRtxSemaphore_t res_sem_storage = {0, 0, 0, 0, 0, 0, 0, 0};
const osSemaphoreAttr_t res_sem_attr = {
.name = "VER_RES_SEM",
.attr_bits = 0,
.cb_mem = &res_sem_storage,
.cb_size = sizeof(res_sem_storage),
};
const spm_pending_version_msg_t msg = {
.rc = PSA_VERSION_NONE,
.completion_sem_id = osSemaphoreNew(IPC_RES_SEM_MAX_COUNT,
IPC_RES_SEM_INITIAL_COUNT,
&res_sem_attr
)
};
MBED_ASSERT(msg.completion_sem_id != NULL);
ipc_queue_item_t queue_item = {
.a = PSA_IPC_VERSION,
.b = (uint32_t)(&msg),
.c = sid
};
ipc_queue_enqueue(prod_queue, queue_item);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
MBED_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
return msg.rc;
}
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
{
osRtxSemaphore_t res_sem_storage = {0, 0, 0, 0, 0, 0, 0, 0};
const osSemaphoreAttr_t res_sem_attr = {
.name = "CONN_RES_SEM",
.attr_bits = 0,
.cb_mem = &res_sem_storage,
.cb_size = sizeof(res_sem_storage),
};
const spm_pending_connect_msg_t msg = {
.min_version = minor_version,
.rc = PSA_SUCCESS,
.completion_sem_id = osSemaphoreNew(IPC_RES_SEM_MAX_COUNT,
IPC_RES_SEM_INITIAL_COUNT,
&res_sem_attr
)
};
MBED_ASSERT(msg.completion_sem_id != NULL);
ipc_queue_item_t queue_item = {
.a = PSA_IPC_CONNECT,
.b = (uint32_t)(&msg),
.c = sid
};
ipc_queue_enqueue(prod_queue, queue_item);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
MBED_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
return (psa_handle_t)(msg.rc);
}
psa_status_t psa_call(psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
const psa_outvec *out_vec,
size_t out_len
)
{
// - Immediate errors are checked here.
// - Other errors are checked on the SPM core code
// TODO: Panic instead
MBED_ASSERT(handle > 0);
// TODO: Panic instead
MBED_ASSERT((in_vec != NULL) || (in_len == 0));
// TODO: Panic instead
MBED_ASSERT((out_vec != NULL) || (out_len == 0));
// TODO: Panic instead
MBED_ASSERT(in_len + out_len <= PSA_MAX_IOVEC);
osRtxSemaphore_t res_sem_storage = {0, 0, 0, 0, 0, 0, 0, 0};
const osSemaphoreAttr_t res_sem_attr = {
.name = "CALL_RES_SEM",
.attr_bits = 0,
.cb_mem = &res_sem_storage,
.cb_size = sizeof(res_sem_storage),
};
const spm_pending_call_msg_t msg = {
.in_vec = in_vec,
.in_vec_size = in_len,
.out_vec = out_vec,
.out_vec_size = out_len,
.rc = PSA_SUCCESS,
.completion_sem_id = osSemaphoreNew(IPC_RES_SEM_MAX_COUNT,
IPC_RES_SEM_INITIAL_COUNT,
&res_sem_attr
)
};
MBED_ASSERT(msg.completion_sem_id != NULL);
ipc_queue_item_t queue_item = {
.a = PSA_IPC_CALL,
.b = (uint32_t)(&msg),
.c = (uint32_t)handle
};
ipc_queue_enqueue(prod_queue, queue_item);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
MBED_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
return msg.rc;
}
void psa_close(psa_handle_t handle)
{
if (handle == PSA_NULL_HANDLE) {
return;
}
// - Immediate errors are checked here.
// - Other errors are checked on the SPM core code
// TODO: Panic instead
MBED_ASSERT(handle >= 0);
osRtxSemaphore_t res_sem_storage = {0, 0, 0, 0, 0, 0, 0, 0};
const osSemaphoreAttr_t res_sem_attr = {
.name = "CLOSE_RES_SEM",
.attr_bits = 0,
.cb_mem = &res_sem_storage,
.cb_size = sizeof(res_sem_storage),
};
spm_pending_close_msg_t msg = {
.handle = handle,
.completion_sem_id = osSemaphoreNew(IPC_RES_SEM_MAX_COUNT,
IPC_RES_SEM_INITIAL_COUNT,
&res_sem_attr
)
};
MBED_ASSERT(msg.completion_sem_id != NULL);
ipc_queue_item_t queue_item = {
.a = PSA_IPC_DISCONNECT,
.b = (uint32_t)(&msg),
.c = (uint32_t)handle
};
ipc_queue_enqueue(prod_queue, queue_item);
osStatus_t os_status = osSemaphoreAcquire(msg.completion_sem_id, osWaitForever);
MBED_ASSERT(osOK == os_status);
os_status = osSemaphoreDelete(msg.completion_sem_id);
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}

View File

@ -1,123 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cmsis_os2.h"
#include "psa_defs.h"
#include "mbed_assert.h"
#include "ipc_queue.h"
#include "ipc_defs.h"
#include "spm_api.h"
static os_mutex_t queue_mutex_storage;
static os_semaphore_t full_sema;
static os_semaphore_t read_sema;
static const osMutexAttr_t queue_mutex_attr = {
.name = "Q_MUT",
.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust,
.cb_mem = &queue_mutex_storage,
.cb_size = sizeof(queue_mutex_storage)
};
// Full queue semaphore attributes for the consumer queue
static const osSemaphoreAttr_t full_sem_attr = {
.name = "Q_W_SEM",
.attr_bits = 0,
.cb_mem = &full_sema,
.cb_size = sizeof(full_sema)
};
// Read semaphore attributes for the consumer queue
static const osSemaphoreAttr_t read_sem_attr = {
.name = "Q_R_SEM",
.attr_bits = 0,
.cb_mem = &read_sema,
.cb_size = sizeof(read_sema)
};
static ipc_producer_queue_t _prod_queue;
ipc_producer_queue_t *prod_queue = &_prod_queue;
static ipc_consumer_queue_t _cons_queue;
ipc_consumer_queue_t *cons_queue = &_cons_queue;
void on_new_item(void)
{
spm_hal_mailbox_notify();
}
void on_vacancy(void)
{
spm_hal_mailbox_notify();
}
void on_popped_item(ipc_queue_item_t item)
{
osStatus_t os_status = osSemaphoreRelease((osSemaphoreId_t)(item.b));
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
void spm_ipc_mailbox_init(void)
{
// Initialization by data from shared memory
// -----------------------------------------
// This table is holding addresses of the platform's shared memory.
addr_table_t *shared_addr_table_ptr = (addr_table_t *)PSA_SHARED_RAM_START;
MBED_ASSERT(shared_addr_table_ptr->magic == ADDR_TABLE_MAGIC);
ipc_base_queue_t *tx_queue_mem_ptr = (ipc_base_queue_t *)(shared_addr_table_ptr->tx_queue_ptr);
MBED_ASSERT(tx_queue_mem_ptr->magic == IPC_QUEUE_BASE_MAGIC);
ipc_base_queue_t *rx_queue_mem_ptr = (ipc_base_queue_t *)(shared_addr_table_ptr->rx_queue_ptr);
MBED_ASSERT(rx_queue_mem_ptr->magic == IPC_QUEUE_BASE_MAGIC);
osMutexId_t queue_mutex = osMutexNew(&queue_mutex_attr);
MBED_ASSERT(queue_mutex != NULL); // TODO: Panic instead
osSemaphoreId_t full_queue_sem = osSemaphoreNew(IPC_QUEUE_SEM_MAX_COUNT, IPC_QUEUE_SEM_INITIAL_COUNT, &full_sem_attr);
MBED_ASSERT(full_queue_sem != NULL); // TODO: Panic instead
osSemaphoreId_t queue_read_sem = osSemaphoreNew(IPC_QUEUE_SEM_MAX_COUNT, IPC_QUEUE_SEM_INITIAL_COUNT, &read_sem_attr);
MBED_ASSERT(queue_read_sem != NULL); // TODO: Panic instead
ipc_producer_queue_init(prod_queue, tx_queue_mem_ptr, queue_mutex, full_queue_sem);
ipc_consumer_queue_init(cons_queue, rx_queue_mem_ptr, queue_read_sem);
}
void spm_mailbox_irq_callback(void)
{
osStatus_t os_status = osSemaphoreRelease(prod_queue->full_queue_sem);
MBED_ASSERT((osOK == os_status) || (osErrorResource == os_status));
os_status = osSemaphoreRelease(cons_queue->read_sem);
MBED_ASSERT((osOK == os_status) || (osErrorResource == os_status));
PSA_UNUSED(os_status);
}
/*******************************************************************************
* Function Name: psa_spm_mailbox_dispatcher
*******************************************************************************/
void psa_spm_mailbox_dispatcher(void *arg)
{
while (true) {
ipc_queue_drain(cons_queue);
}
}

View File

@ -1,178 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "psa_defs.h"
#include "spm_client.h"
#include "spm_messages.h"
#include "spm_internal.h"
#include "mbed_assert.h"
#include "ipc_queue.h"
#include "ipc_defs.h"
#include "spm_api.h"
static os_mutex_t queue_mutex_storage;
static os_semaphore_t full_sema;
static os_semaphore_t read_sema;
static const osMutexAttr_t queue_mutex_attr = {
.name = "Q_MUT",
.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust,
.cb_mem = &queue_mutex_storage,
.cb_size = sizeof(queue_mutex_storage)
};
// Full queue semaphore attributes for the consumer queue
static const osSemaphoreAttr_t full_sem_attr = {
.name = "Q_W_SEM",
.attr_bits = 0,
.cb_mem = &full_sema,
.cb_size = sizeof(full_sema)
};
// Read semaphore attributes for the consumer queue
static const osSemaphoreAttr_t read_sem_attr = {
.name = "Q_R_SEM",
.attr_bits = 0,
.cb_mem = &read_sema,
.cb_size = sizeof(read_sema)
};
static ipc_producer_queue_t _prod_queue;
ipc_producer_queue_t *prod_queue = &_prod_queue;
static ipc_consumer_queue_t _cons_queue;
ipc_consumer_queue_t *cons_queue = &_cons_queue;
MBED_STATIC_ASSERT(
(sizeof(addr_table_t) + sizeof(ipc_base_queue_t) + sizeof(ipc_base_queue_t)) <= PSA_SHARED_RAM_SIZE,
"shared memory size is too small!"
);
void spm_mailbox_irq_callback(void)
{
osStatus_t os_status = osSemaphoreRelease(prod_queue->full_queue_sem);
MBED_ASSERT((osOK == os_status) || (osErrorResource == os_status));
os_status = osSemaphoreRelease(cons_queue->read_sem);
MBED_ASSERT((osOK == os_status) || (osErrorResource == os_status));
PSA_UNUSED(os_status);
}
void on_new_item(void)
{
spm_hal_mailbox_notify();
}
void on_vacancy(void)
{
spm_hal_mailbox_notify();
}
void on_popped_item(ipc_queue_item_t item)
{
// item.a hold the message type (connect / call /close)
switch (item.a) {
case PSA_IPC_CONNECT: {
psa_connect_async(item.c, (spm_pending_connect_msg_t *)(item.b));
break;
}
case PSA_IPC_CALL: {
psa_call_async((psa_handle_t)(item.c), (spm_pending_call_msg_t *)(item.b));
break;
}
case PSA_IPC_DISCONNECT: {
psa_close_async((psa_handle_t)(item.c), (spm_pending_close_msg_t *)(item.b));
break;
}
case PSA_IPC_VERSION: {
spm_pending_version_msg_t *msg = (spm_pending_version_msg_t *)(item.b);
if (!is_buffer_accessible(msg, sizeof(*msg), NULL)) {
SPM_PANIC("message data is inaccessible\n");
}
msg->rc = psa_version(item.c);
nspe_done(msg->completion_sem_id);
break;
}
default: {
MBED_ASSERT(false);
}
}
}
void spm_ipc_mailbox_init(void)
{
uint32_t *shared_memory_start = (uint32_t *)PSA_SHARED_RAM_START;
// This struct is set with initial values for the address table (addresses of CM0+ / CM4 shared memory)
const addr_table_t shared_addr_table = {
.magic = ADDR_TABLE_MAGIC,
.tx_queue_ptr = (uintptr_t)(shared_memory_start +
(sizeof(addr_table_t) / sizeof(uint32_t))
),
.rx_queue_ptr = (uintptr_t)(shared_memory_start +
((sizeof(addr_table_t) + sizeof(ipc_base_queue_t)) / sizeof(uint32_t))
)
};
// This struct is set with initial values to be used for IPC queues initialization.
// Same values are used to initial both tx and rx queues.
const ipc_base_queue_t queue_mem = {
.magic = IPC_QUEUE_BASE_MAGIC,
.read_idx = 0,
.write_idx = 0,
.data = {{0, 0}}
};
ipc_base_queue_t *tx_queue_mem_ptr = (ipc_base_queue_t *)(shared_addr_table.tx_queue_ptr);
ipc_base_queue_t *rx_queue_mem_ptr = (ipc_base_queue_t *)(shared_addr_table.rx_queue_ptr);
// Copy initial queue values for tx & tx queues to the right location in the CM0+ / CM4 shared memory
memcpy(tx_queue_mem_ptr, &queue_mem, sizeof(ipc_base_queue_t));
memcpy(rx_queue_mem_ptr, &queue_mem, sizeof(ipc_base_queue_t));
// Copy the content of shared_addr_table to the start address of CM0+ / CM4 shared memory.
memcpy(shared_memory_start, &shared_addr_table, sizeof(shared_addr_table));
// Init producer queue and consumer queue
osMutexId_t queue_mutex = osMutexNew(&queue_mutex_attr);
MBED_ASSERT(queue_mutex != NULL); // TODO: Panic instead
osSemaphoreId_t full_queue_sem = osSemaphoreNew(IPC_QUEUE_SEM_MAX_COUNT, IPC_QUEUE_SEM_INITIAL_COUNT, &full_sem_attr);
MBED_ASSERT(full_queue_sem != NULL); // TODO: Panic instead
osSemaphoreId_t queue_read_sem = osSemaphoreNew(IPC_QUEUE_SEM_MAX_COUNT, IPC_QUEUE_SEM_INITIAL_COUNT, &read_sem_attr);
MBED_ASSERT(queue_read_sem != NULL); // TODO: Panic instead
ipc_producer_queue_init(prod_queue, rx_queue_mem_ptr, queue_mutex, full_queue_sem);
ipc_consumer_queue_init(cons_queue, tx_queue_mem_ptr, queue_read_sem);
}
void nspe_done(osSemaphoreId_t completion_sem_id)
{
ipc_queue_item_t item_to_enqueue = {
.b = (uint32_t)(completion_sem_id)
};
ipc_queue_enqueue(prod_queue, item_to_enqueue);
}

View File

@ -1,50 +0,0 @@
/* Copyright (c) 2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PSA_MBED_IPC_DEFS_H__
#define __PSA_MBED_IPC_DEFS_H__
// Includes
// --------
#include <stdint.h>
#include "mbed_assert.h"
// Definitions
// -----------
#define IPC_RES_SEM_MAX_COUNT (1UL) // Maximum number of available tokens for an IPC result semaphore
#define IPC_RES_SEM_INITIAL_COUNT (0UL) // Initial number of available tokens for an IPC result semaphore
#define ADDR_TABLE_MAGIC 0x3d339a77
// NOTE: STRUCT SIZE MUST BE 4 BYTES ALIGNED !!
typedef struct addr_table_t {
uint32_t magic;
uintptr_t tx_queue_ptr;
uintptr_t rx_queue_ptr;
} addr_table_t;
MBED_STATIC_ASSERT((sizeof(addr_table_t) % sizeof(uint32_t) == 0), "addr_table_t: Struct size must be 4 bytes aligned!");
#endif // __PSA_MBED_IPC_DEFS_H__

View File

@ -1,121 +0,0 @@
/* Copyright (c) 2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Includes
// --------
#include "mbed_assert.h"
#include "ipc_queue.h"
#include "psa_defs.h"
// API Implmentation
// -----------------
void ipc_producer_queue_init(ipc_producer_queue_t *queue,
ipc_base_queue_t *base_queue_mem,
osMutexId_t mutex,
osSemaphoreId_t full_queue_sem
)
{
MBED_ASSERT(queue != NULL);
MBED_ASSERT(base_queue_mem != NULL);
MBED_ASSERT(base_queue_mem->magic == IPC_QUEUE_BASE_MAGIC);
MBED_ASSERT(mutex != NULL);
MBED_ASSERT(full_queue_sem != NULL);
queue->magic = IPC_QUEUE_PRODUCER_MAGIC;
queue->read_idx = &(base_queue_mem->read_idx);
queue->write_idx = &(base_queue_mem->write_idx);
queue->data = base_queue_mem->data;
queue->mutex = mutex;
queue->full_queue_sem = full_queue_sem;
}
void ipc_consumer_queue_init(ipc_consumer_queue_t *queue,
ipc_base_queue_t *base_queue_mem,
osSemaphoreId_t read_sem
)
{
MBED_ASSERT(queue != NULL);
MBED_ASSERT(base_queue_mem != NULL);
MBED_ASSERT(base_queue_mem->magic == IPC_QUEUE_BASE_MAGIC);
MBED_ASSERT(read_sem != NULL);
queue->magic = IPC_QUEUE_CONSUMER_MAGIC;
queue->read_idx = &(base_queue_mem->read_idx);
queue->write_idx = &(base_queue_mem->write_idx);
queue->data = base_queue_mem->data;
queue->read_sem = read_sem;
}
void ipc_queue_enqueue(ipc_producer_queue_t *queue,
ipc_queue_item_t queue_item
)
{
MBED_ASSERT(queue != NULL);
MBED_ASSERT(queue->magic == IPC_QUEUE_PRODUCER_MAGIC);
osStatus_t os_status = osMutexAcquire(queue->mutex, osWaitForever);
MBED_ASSERT(osOK == os_status);
// While queue is full, wait on full_queue_sem
while (((*(queue->write_idx) + 1) % IPC_QUEUE_SLOTS) == *(queue->read_idx)) {
os_status = osSemaphoreAcquire(queue->full_queue_sem, IPC_QUEUE_WAIT_ON_FULL_MS);
MBED_ASSERT((osOK == os_status) || (osErrorTimeout == os_status));
}
// Write data to queue (shallow copy)
(queue->data)[*(queue->write_idx)] = queue_item;
*(queue->write_idx) = ((*(queue->write_idx) + 1) % IPC_QUEUE_SLOTS);
// If the queue was empty before the push, call the supplied CB function
if (((*(queue->read_idx) + 1) % IPC_QUEUE_SLOTS) == *(queue->write_idx)) {
on_new_item();
}
os_status = osMutexRelease(queue->mutex);
MBED_ASSERT(osOK == os_status);
PSA_UNUSED(os_status);
}
void ipc_queue_drain(ipc_consumer_queue_t *queue)
{
MBED_ASSERT(queue != NULL);
MBED_ASSERT(queue->magic == IPC_QUEUE_CONSUMER_MAGIC);
// queue->read_sem is released when the queue becomes non empty
osStatus_t os_status = osSemaphoreAcquire(queue->read_sem, IPC_QUEUE_WAIT_ON_EMPTY_MS);
MBED_ASSERT((osOK == os_status) || (osErrorTimeout == os_status));
PSA_UNUSED(os_status);
// While queue is not empty, keep on popping queue items
while (*(queue->read_idx) != *(queue->write_idx)) {
// Pop an item from the queue (shallow copy)
ipc_queue_item_t popped_item = (queue->data)[*(queue->read_idx)];
*(queue->read_idx) = ((*(queue->read_idx) + 1) % IPC_QUEUE_SLOTS);
// If queue was full before this pop, call the corresponding CB function
if (((*(queue->write_idx) + 2) % IPC_QUEUE_SLOTS) == *(queue->read_idx)) {
on_vacancy();
}
on_popped_item(popped_item);
}
}

View File

@ -1,126 +0,0 @@
/* Copyright (c) 2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PSA_MBED_IPC_QUEUE_H__
#define __PSA_MBED_IPC_QUEUE_H__
// Includes
// --------
#include "mbed_assert.h"
#include "cmsis_os2.h"
#include "cmsis_compiler.h"
#include "rtx_lib.h"
// IPC Queue Definitions
// ---------------------
#ifndef IPC_QUEUE_SLOTS
#define IPC_QUEUE_SLOTS 4
#endif
// Maximum number of queue items equals (IPC_QUEUE_SLOTS - 1).
// Therefore we enforce a minimum of 2 IPC_QUEUE_SLOTS
#if IPC_QUEUE_SLOTS <= 1
#undef IPC_QUEUE_SLOTS
#define IPC_QUEUE_SLOTS 2
#endif
#define IPC_QUEUE_BASE_MAGIC 0x63284A0C
#define IPC_QUEUE_PRODUCER_MAGIC 0XA248D9FF
#define IPC_QUEUE_CONSUMER_MAGIC 0XA68B6542
#define IPC_QUEUE_WAIT_ON_FULL_MS 500
#define IPC_QUEUE_WAIT_ON_EMPTY_MS 500
#define IPC_QUEUE_SEM_MAX_COUNT (1UL) // Maximum number of available tokens for an IPC Queue semaphore
#define IPC_QUEUE_SEM_INITIAL_COUNT (0UL) // Initial number of available tokens for an IPC Queue semaphore
// NOTE: STRUCT SIZE MUST BE 4 BYTES ALIGNED !!
typedef __PACKED_STRUCT ipc_queue_item_t {
uint32_t a;
uint32_t b;
uint32_t c;
} __ALIGNED(4) ipc_queue_item_t;
MBED_STATIC_ASSERT((sizeof(ipc_queue_item_t) % sizeof(uint32_t) == 0), "ipc_queue_item_t: Struct size must be 4 bytes aligned!");
// NOTE: STRUCT SIZE MUST BE 4 BYTES ALIGNED !!
typedef __PACKED_STRUCT ipc_base_queue_t {
uint32_t magic;
volatile uint32_t read_idx;
volatile uint32_t write_idx;
ipc_queue_item_t data[IPC_QUEUE_SLOTS];
} __ALIGNED(4) ipc_base_queue_t;
MBED_STATIC_ASSERT((sizeof(ipc_base_queue_t) % sizeof(uint32_t) == 0), "ipc_base_queue_t: Struct size must be 4 bytes aligned!");
typedef struct ipc_producer_queue_t {
uint32_t magic;
volatile __PACKED uint32_t *read_idx;
volatile __PACKED uint32_t *write_idx;
__PACKED ipc_queue_item_t *data;
osMutexId_t mutex;
osSemaphoreId_t full_queue_sem;
} ipc_producer_queue_t;
typedef struct ipc_consumer_queue_t {
uint32_t magic;
volatile __PACKED uint32_t *read_idx;
volatile __PACKED uint32_t *write_idx;
__PACKED ipc_queue_item_t *data;
osSemaphoreId_t read_sem;
} ipc_consumer_queue_t;
// Event handling functions
// ------------------------
void on_new_item(void);
void on_vacancy(void);
void on_popped_item(ipc_queue_item_t item);
// IPC Queue API
// -------------
void ipc_producer_queue_init(ipc_producer_queue_t *queue,
ipc_base_queue_t *base_queue_mem,
osMutexId_t mutex,
osSemaphoreId_t full_queue_sem
);
void ipc_consumer_queue_init(ipc_consumer_queue_t *queue,
ipc_base_queue_t *base_queue_mem,
osSemaphoreId_t read_sem
);
void ipc_queue_enqueue(ipc_producer_queue_t *queue,
ipc_queue_item_t item_ptr
);
void ipc_queue_drain(ipc_consumer_queue_t *queue);
#endif // __PSA_MBED_IPC_QUEUE_H__

View File

@ -1,13 +0,0 @@
{
"name": "spm",
"config": {
"ipc_max_num_of_channels": {
"help": "maximum number of PSA channels that can be opened at the same time",
"value": 10
},
"ipc_max_num_of_messages": {
"help": "maximum number of messages SPM Core can handle at a time",
"value": 10
}
}
}

View File

@ -1,117 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_PSA_DEFS_H__
#define __MBED_PSA_DEFS_H__
/** @addtogroup SPM
* @{
*/
/* -------------------------------------- Includes ----------------------------------- */
#include <stdint.h>
#include <stdlib.h>
#include "psa/error.h"
/* --------------------------------- extern "C" wrapper ------------------------------ */
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------ Definitions ---------------------------------- */
#if !defined(UINT32_MAX)
#define UINT32_MAX ((uint32_t)-1)
#endif
#if !defined(INT32_MIN)
#define INT32_MIN (-0x7fffffff - 1)
#endif
#define PSA_FRAMEWORK_VERSION (0x0100) /**< Version of the PSA Framework API. */
#define PSA_VERSION_NONE (0L) /**< Identifier for an unimplemented Root of Trust (RoT) Service. */
#define PSA_NSPE_IDENTIFIER (-1L) /**< "Partition" identifier of the NSPE.*/
#define PSA_NULL_HANDLE ((psa_handle_t)0) /**< Denotes an invalid handle.*/
#define PSA_MAX_IOVEC (4UL) /**< Maximum number of psa_invec and psa_outvec structures allowed for psa_call().*/
#define PSA_POLL (0x00000000UL) /**< Returns immediately even if none of the requested signals is asserted.*/
#define PSA_BLOCK (0x80000000UL) /**< Block the caller until one of the requested signals is asserted.*/
#define PSA_WAIT_ANY (0xFFFFFFFFUL) /**< A mask value that includes all Secure Partition signals.*/
#define PSA_MINOR_VERSION_POLICY_RELAXED (0UL) /**< Don't perform minor version check during psa_connect().*/
#define PSA_MINOR_VERSION_POLICY_STRICT (1UL) /**< Force minor version check during psa_connect().*/
#define PSA_DOORBELL (0x00000008UL) /**< Mask for PSA_DOORBELL signal.*/
#define PSA_IPC_CONNECT (1) /**< The IPC message type that indicates a new connection.*/
#define PSA_IPC_CALL (2) /**< The IPC message type that indicates a client request.*/
#define PSA_IPC_DISCONNECT (3) /**< The IPC message type that indicates the end of a connection.*/
#define PSA_IPC_VERSION (4) /**< The IPC message type that indicates a client query for a specific sid.*/
/* Error codes */
#define PSA_DROP_CONNECTION (INT32_MIN) /**< The result code in a call to psa_reply() to indicate a nonrecoverable error in the client.*/
#define PSA_CONNECTION_REFUSED (INT32_MIN + 1) /**< The return value from psa_connect() if the RoT Service or SPM was unable to establish a connection.*/
#define PSA_CONNECTION_BUSY (INT32_MIN + 2) /**< The return value from psa_connect() if the RoT Service rejects the connection for a transient reason.*/
#define PSA_UNUSED(var) ((void)(var))
/* -------------------------------------- Typedefs ----------------------------------- */
typedef uint32_t psa_signal_t;
typedef int32_t psa_handle_t;
/* -------------------------------------- Structs ------------------------------------ */
/**
* Structure containing the PSA IPC message sent from a client partition to an RoT Service.
*/
typedef struct psa_msg {
uint32_t type; /**< The message type.*/
psa_handle_t handle; /**< Handle for the internal message structure.*/
int32_t client_id; /**< Message origin.*/
void *rhandle; /**< Reverse handle.*/
size_t in_size[PSA_MAX_IOVEC]; /**< Array of sizes in bytes of the message payloads.*/
size_t out_size[PSA_MAX_IOVEC]; /**< Array of sizes in bytes of the response buffers.*/
} psa_msg_t;
/**
* Structure that describes a scatter-gather input buffer.
*/
typedef struct psa_invec {
const void *base; /**< Starting address of the buffer.*/
size_t len; /**< Length in bytes of the buffer.*/
} psa_invec;
/**
* Structure which describes a scatter-gather output buffer.
*/
typedef struct psa_outvec {
void *base; /**< Starting address of the buffer.*/
size_t len; /**< Length in bytes of the buffer.*/
} psa_outvec;
#ifdef __cplusplus
}
#endif
/** @}*/ // end of SPM group
#endif /* __MBED_PSA_DEFS_H__ */

View File

@ -1,112 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_SPM_CLIENT_H__
#define __MBED_SPM_CLIENT_H__
/** @addtogroup SPM
* The Secure Partition Manager (SPM) is responsible for isolating software in partitions,@n
* managing the execution of software within partitions and providing IPC between partitions.
* @{
*/
/* -------------------------------------- Includes ----------------------------------- */
#include "psa_defs.h"
/* --------------------------------- extern "C" wrapper ------------------------------ */
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup Client-API
* The C interface for connecting to a Root of Trust Service and calling it.@n
* All functions are blocking.
* @{
*/
/**
* Retrieve the version of the PSA Framework API that is implemented.
*
* @note The PSA Framework API version is made of the major and minor versions as follows:
* @code
* ((major_version << 8) | minor_version)
* @endcode
* @return The PSA Framework API version
*/
uint32_t psa_framework_version(void);
/**
* Retrieve the minor version of a Root of Trust Service by its SID.
*
* @param[in] sid The Root of Trust Service ID
* @return Minor version of Root of Trust Service or PSA_VERSION_NONE if Root of Trust Service is not present on the system.
*/
uint32_t psa_version(uint32_t sid);
/**
* Connect to a Root of Trust Service by its SID.
*
* @note A minor version number must be provided to allow the Root of Trust Service to handle minor variations of the protocol.
*
* @param[in] sid The Root of Trust Service ID.
* @param[in] minor_version The minor version to be used for this connection.
* @return A handle for the connection if greater than 0, else:@n
* @a PSA_CONNECTION_REFUSED if the Root of Trust Service cannot handle any more connections.@n
*/
psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version);
/**
* Call a connected Root of Trust Service.@n
* The caller must provide an array of ::psa_invec structures as the input payload.
*
* @param[in] handle Handle for the connection.
* @param[in] in_vec Array of ::psa_invec structures.
* @param[in] in_len Number of ::psa_invec structures in in_vec. (At most ::PSA_MAX_IOVEC - out_len)
* @param[out] out_vec Array of ::psa_outvec structures for optional Root of Trust Service response.
* @param[in] out_len Number of ::psa_outvec structures in out_vec. (At most ::PSA_MAX_IOVEC - in_len)
* @return 0 for success or@n
* @a positive numbers for application-specific return code.
* @a negative numbers for application-specific error code.
* @a PSA_DROP_CONNECTION if the connection has been dropped by the RoT Service.
*/
psa_status_t psa_call(
psa_handle_t handle,
const psa_invec *in_vec,
size_t in_len,
const psa_outvec *out_vec,
size_t out_len
);
/**
* Close a connection to a Root of Trust Service.
* Sends the ::PSA_IPC_DISCONNECT message to the Root of Trust Service, so it can clean up resources.
*
* @param[in] handle Handle for the connection.
*/
void psa_close(psa_handle_t handle);
/** @}*/ // end of Client-API group
#ifdef __cplusplus
}
#endif
/** @}*/ // end of SPM group
#endif /* __MBED_SPM_CLIENT_H__ */

View File

@ -1,51 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MBED_SPM_INIT_H__
#define __MBED_SPM_INIT_H__
#if defined(COMPONENT_SPE)
/*
* Initialize SPM
*/
void psa_spm_init(void);
#endif // defined(COMPONENT_SPE)
#if defined(COMPONENT_SPM_MAILBOX)
/*
* Initialize SPM mailbox driver
*/
void spm_ipc_mailbox_init(void);
#if defined(COMPONENT_NSPE)
/*
* PSA mailbox dispatcher
*
* Dispatcher thread never returns and expected to be called
* from startup code as a detached thread entry point
*/
void psa_spm_mailbox_dispatcher(void);
#endif // defined(COMPONENT_NSPE)
#endif // defined(COMPONENT_SPM_MAILBOX)
#endif // __MBED_SPM_INIT_H__

View File

@ -1,66 +0,0 @@
/* Copyright (c) 2017-2018 ARM Limited
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SPM_MESSAGES_H
#define SPM_MESSAGES_H
#include "cmsis_compiler.h"
#include "cmsis_os2.h"
#include "psa_defs.h"
// All spm_pending_*_msg structs below are packed since in a dual processor
// solution they are used in both processors
/*
* Structure containing data sent from NSPE for ROT_SRV call.
*/
typedef __PACKED_STRUCT spm_pending_call_msg {
const psa_invec *in_vec; /* Invecs sent.*/
uint32_t in_vec_size; /* Number of Invecs sent.*/
const psa_outvec *out_vec; /* Outvecs for response.*/
uint32_t out_vec_size; /* Number of Outvecs for response.*/
psa_status_t rc; /* Return code to be filled by the Root of Trust Service.*/
osSemaphoreId_t completion_sem_id; /* Semaphore to be released at the end of execution */
} __ALIGNED(4) spm_pending_call_msg_t;
/*
* Structure containing data sent from NSPE for connection.
*/
typedef __PACKED_STRUCT spm_pending_connect_msg {
uint32_t min_version; /* Minor version of the Root of Trust Service interface.*/
psa_status_t rc; /* Return code to be filled by the Root of Trust Service.*/
osSemaphoreId_t completion_sem_id; /* Semaphore to be released at the end of execution */
} __ALIGNED(4) spm_pending_connect_msg_t;
/*
* Structure containing data sent from NSPE for RoT-Service version query.
*/
typedef __PACKED_STRUCT spm_pending_version_msg {
uint32_t rc; /* Return code to be filled by the Root of Trust Service.*/
osSemaphoreId_t completion_sem_id; /* Semaphore to be released at the end of execution */
} __ALIGNED(4) spm_pending_version_msg_t;
/*
* Structure containing data sent from NSPE for closing a connection.
*/
typedef __PACKED_STRUCT spm_pending_close_msg {
psa_handle_t handle; /* Handle of channel to be closed */
osSemaphoreId_t completion_sem_id; /* Semaphore to be released at the end of execution */
} __ALIGNED(4) spm_pending_close_msg_t;
#endif // SPM_MESSAGES_H

View File

@ -17,9 +17,6 @@
#if defined(TARGET_TFM)
#include "interface/include/psa_client.h"
#elif defined(TARGET_MBED_SPM)
#include "TARGET_MBED_SPM/psa_defs.h"
#include "TARGET_MBED_SPM/spm_client.h"
#else
#ifndef __MBED_OS_DEFAULT_PSA_CLIENT_API_H__

View File

@ -21,12 +21,6 @@
#include "secure_fw/core/ipc/include/tfm_utils.h"
#define SPM_PANIC(format, ...) tfm_panic()
#elif defined(TARGET_MBED_SPM)
#include "TARGET_MBED_SPM/psa_defs.h"
#include "TARGET_MBED_SPM/COMPONENT_SPE/spm_server.h"
#include "TARGET_MBED_SPM/COMPONENT_SPE/spm_panic.h"
#else
#error "Compiling psa service header on non-secure target is not allowed"

View File

@ -24,11 +24,7 @@
#include "pits_impl.h"
#include "mbed_error.h"
#if defined(TARGET_MBED_SPM)
#include "kv_config.h"
#else
int kv_init_storage_config();
#endif
#ifdef __cplusplus
extern "C"

View File

@ -2103,7 +2103,6 @@ PREDEFINED = DOXYGEN_ONLY \
DEVICE_STORAGE \
DEVICE_WATCHDOG \
COMPONENT_SPE \
COMPONENT_SPM_MAILBOX \
"TFM_LVL=1" \
"MBED_DEPRECATED_SINCE(d, m)=" \
"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=" \

View File

@ -6,7 +6,7 @@
"SEARCH_INCLUDES": "YES",
"INCLUDE_PATH": "",
"INCLUDE_FILE_PATTERNS": "",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG DEVICE_RESET_REASON COMPONENT_SPE COMPONENT_SPM_MAILBOX \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
"PREDEFINED": "DOXYGEN_ONLY DEVICE_ANALOGIN DEVICE_ANALOGOUT DEVICE_CAN DEVICE_CRC DEVICE_ETHERNET DEVICE_EMAC DEVICE_FLASH DEVICE_I2C DEVICE_I2CSLAVE DEVICE_I2C_ASYNCH DEVICE_INTERRUPTIN DEVICE_ITM DEVICE_LPTICKER DEVICE_MPU DEVICE_PORTIN DEVICE_PORTINOUT DEVICE_PORTOUT DEVICE_PWMOUT DEVICE_RTC DEVICE_TRNG DEVICE_SERIAL DEVICE_SERIAL_ASYNCH DEVICE_SERIAL_FC DEVICE_SLEEP DEVICE_SPI DEVICE_SPI_ASYNCH DEVICE_SPISLAVE DEVICE_QSPI DEVICE_STORAGE DEVICE_WATCHDOG DEVICE_RESET_REASON COMPONENT_SPE \"TFM_LVL=1\" \"MBED_DEPRECATED_SINCE(f, g)=\" \"MBED_ENABLE_IF_CALLBACK_COMPATIBLE(F, M)=\" \"MBED_DEPRECATED(s)=\" \"BLE_ROLE_OBSERVER=1\" \"BLE_ROLE_BROADCASTER=1\" \"BLE_ROLE_PERIPHERAL=1\" \"BLE_ROLE_CENTRAL=1\" \"BLE_FEATURE_GATT_CLIENT=1\" \"BLE_FEATURE_GATT_SERVER=1\" \"BLE_FEATURE_SECURITY=1\" \"BLE_FEATURE_SECURE_CONNECTIONS=1\" \"BLE_FEATURE_SIGNING=1\" \"BLE_FEATURE_PHY_MANAGEMENT=1\" \"BLE_FEATURE_WHITELIST=1\" \"BLE_FEATURE_PRIVACY=1\" \"BLE_FEATURE_PERIODIC_ADVERTISING=1\" \"BLE_FEATURE_EXTENDED_ADVERTISING=1\"",
"EXPAND_AS_DEFINED": "",
"SKIP_FUNCTION_MACROS": "NO",
"STRIP_CODE_COMMENTS": "NO",

View File

@ -64,31 +64,6 @@ void spm_hal_memory_protection_init(void);
#endif // defined(COMPONENT_SPE)
/* ---------------------------------- HAL-Mailbox API ----------------------- */
#if defined(COMPONENT_SPM_MAILBOX)
/**
* @brief Wakeup mailbox dispatcher thread
*
* Arm implements this function, which is expected to be called by target-
* specific Inter-Processor-Communication logic on mailbox interrupt handler.
*
*/
void spm_mailbox_irq_callback(void);
/**
* @brief Notify the peer processor about a general event occurrence.
*
* Wake up the peer processor waiting on the mailbox driver event.
*
* @note Implement the functions below with target-specific code.
*/
void spm_hal_mailbox_notify(void);
#endif // defined(COMPONENT_SPM_MAILBOX)
/** @}*/
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
* Copyright (c) 2018-2020 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -24,29 +24,10 @@
#include "mbed_critical.h"
#include "mbed_boot.h"
#if defined(TARGET_MBED_SPM)
#include "spm_init.h"
#include "spm_api.h"
#endif
#if defined(TARGET_TFM) && defined(COMPONENT_NSPE)
#include "TARGET_TFM/interface/include/tfm_ns_lock.h"
#endif
#if defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
MBED_ALIGN(8) char psa_spm_dispatcher_th_stack[0x100];
mbed_rtos_storage_thread_t psa_spm_dispatcher_th_tcb;
const osThreadAttr_t psa_spm_dispatcher_th_attr = {
.name = "SPM_DISP",
.priority = osPriorityNormal,
.stack_mem = psa_spm_dispatcher_th_stack,
.stack_size = sizeof(psa_spm_dispatcher_th_stack),
.cb_mem = &psa_spm_dispatcher_th_tcb,
.cb_size = sizeof(psa_spm_dispatcher_th_tcb)
};
#endif // defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
osThreadAttr_t _main_thread_attr;
#ifndef MBED_CONF_APP_MAIN_STACK_SIZE
@ -83,26 +64,6 @@ MBED_NORETURN void mbed_rtos_start()
_main_thread_attr.tz_module = 1U;
#endif
#if defined(COMPONENT_SPM_MAILBOX)
spm_ipc_mailbox_init();
#endif // defined(COMPONENT_SPM_MAILBOX)
#if defined(TARGET_MBED_SPM)
#if defined(COMPONENT_SPE)
// At this point, the mailbox is already initialized
psa_spm_init();
spm_hal_start_nspe();
#endif // defined(COMPONENT_SPE)
#if defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
osThreadId_t spm_result = osThreadNew((osThreadFunc_t)psa_spm_mailbox_dispatcher, NULL, &psa_spm_dispatcher_th_attr);
if ((void *)spm_result == NULL) {
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Dispatcher thread not created", &psa_spm_dispatcher_th_attr);
}
#endif // defined(COMPONENT_NSPE) && defined(COMPONENT_SPM_MAILBOX)
#endif // defined(TARGET_MBED_SPM)
#if defined(TARGET_TFM) && defined(COMPONENT_NSPE)
tfm_ns_lock_init();
#endif // defined(TARGET_TFM) && defined(COMPONENT_NSPE)

View File

@ -33,10 +33,6 @@
#include "cy_serial_flash_qspi.h"
#endif /* defined(MBED_CONF_TARGET_XIP_ENABLE) */
#if defined(COMPONENT_SPM_MAILBOX)
void mailbox_init(void);
#endif
#if (defined(CY_CFG_PWR_SYS_IDLE_MODE) && (CY_CFG_PWR_SYS_IDLE_MODE == CY_CFG_PWR_MODE_ACTIVE))
/*******************************************************************************
@ -63,7 +59,7 @@ static void active_idle_hook(void)
*******************************************************************************/
void mbed_sdk_init(void)
{
#if (CY_CPU_CORTEX_M0P && !defined(COMPONENT_SPM_MAILBOX))
#if CY_CPU_CORTEX_M0P
/* Disable global interrupts */
__disable_irq();
#endif
@ -72,18 +68,12 @@ void mbed_sdk_init(void)
/* Placed here as it must be done after proper LIBC initialization. */
SystemInit();
#if defined(COMPONENT_SPM_MAILBOX)
mailbox_init();
#endif
/* Set up the device based on configurator selections */
cybsp_init();
#if (CY_CPU_CORTEX_M0P)
#if !defined(COMPONENT_SPM_MAILBOX)
#if CY_CPU_CORTEX_M0P
/* Enable global interrupts */
__enable_irq();
#endif
#else
/*
* Init the us Ticker here to avoid imposing on the limited stack space of the idle thread.