mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
47b359974f
commit
07a84ec10a
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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__
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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__
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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__
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__
|
|
@ -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
|
|
@ -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__
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)=" \
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue