/* * Copyright (c) 2020-2021, Arm Limited. All rights reserved. * Copyright (c) 2021, Cypress Semiconductor Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * */ #include #include "psa/service.h" #include "psa_manifest/tfm_psa_proxy.h" #include "tfm_pools.h" #include "psa_manifest/sid.h" #include "tfm_multi_core_api.h" #include "tfm_ns_mailbox.h" #include "psa_proxy_shared_mem_mngr.h" #define NON_SECURE_CLIENT_ID (-1) /* Maximum number of connections supported, should be platform/configuration * specific */ #define SE_CONN_MAX_NUM (16) TFM_POOL_DECLARE(forward_handle_pool, sizeof(psa_handle_t), SE_CONN_MAX_NUM); static inline void init_forward_handle_pool(void) { tfm_pool_init(forward_handle_pool, POOL_BUFFER_SIZE(forward_handle_pool), sizeof(psa_handle_t), SE_CONN_MAX_NUM); } static inline psa_handle_t * allocate_forward_handle(void) { return (psa_handle_t *) tfm_pool_alloc(forward_handle_pool); } static inline void deallocate_forward_handle(psa_handle_t *h) { tfm_pool_free(forward_handle_pool, h); } static psa_status_t forward_message_to_secure_enclave(psa_signal_t signal, const psa_msg_t *msg) { psa_status_t status; struct psa_client_params_t params; int32_t ret; /* Use stateless handle for stateless services. */ switch (signal) { case TFM_CRYPTO_SIGNAL: params.psa_call_params.handle = TFM_CRYPTO_HANDLE; params.psa_call_params.type = msg->type; break; case TFM_PROTECTED_STORAGE_SERVICE_SIGNAL: params.psa_call_params.handle = TFM_PROTECTED_STORAGE_SERVICE_HANDLE; params.psa_call_params.type = msg->type; break; case TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_SIGNAL: params.psa_call_params.handle = TFM_INTERNAL_TRUSTED_STORAGE_SERVICE_HANDLE; params.psa_call_params.type = msg->type; break; case TFM_ATTESTATION_SERVICE_SIGNAL: params.psa_call_params.handle = TFM_ATTESTATION_SERVICE_HANDLE; params.psa_call_params.type = msg->type; break; default: params.psa_call_params.handle = *((psa_handle_t *)msg->rhandle); params.psa_call_params.type = PSA_IPC_CALL; break; } status = psa_proxy_put_msg_into_shared_mem(msg, ¶ms); if (status != PSA_SUCCESS) { return status; } ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_CALL, ¶ms, NON_SECURE_CLIENT_ID, (int32_t *)&status); if (ret != MAILBOX_SUCCESS) { status = PSA_ERROR_COMMUNICATION_FAILURE; } if (status == PSA_SUCCESS) { psa_proxy_write_back_results_from_shared_mem(msg); } return status; } static void psa_disconnect_from_secure_enclave(psa_msg_t *msg) { psa_handle_t *forward_handle_ptr = (psa_handle_t *)msg->rhandle; struct psa_client_params_t params; int32_t reply; params.psa_close_params.handle = *forward_handle_ptr; (void)tfm_ns_mailbox_client_call(MAILBOX_PSA_CLOSE, ¶ms, NON_SECURE_CLIENT_ID, &reply); deallocate_forward_handle(forward_handle_ptr); } static void get_sid_and_version_for_signal(psa_signal_t signal, uint32_t *sid, uint32_t *version) { switch (signal) { case TFM_SP_PLATFORM_SYSTEM_RESET_SIGNAL: *sid = TFM_SP_PLATFORM_SYSTEM_RESET_SID; *version = TFM_SP_PLATFORM_SYSTEM_RESET_VERSION; break; case TFM_SP_PLATFORM_IOCTL_SIGNAL: *sid = TFM_SP_PLATFORM_IOCTL_SID; *version = TFM_SP_PLATFORM_IOCTL_VERSION; break; case TFM_SP_PLATFORM_NV_COUNTER_SIGNAL: *sid = TFM_SP_PLATFORM_NV_COUNTER_SID; *version = TFM_SP_PLATFORM_NV_COUNTER_VERSION; break; default: psa_panic(); break; } } static psa_status_t psa_connect_to_secure_enclave(psa_signal_t signal, psa_msg_t *msg) { psa_handle_t *forward_handle_ptr; struct psa_client_params_t params; int32_t ret; forward_handle_ptr = allocate_forward_handle(); if (forward_handle_ptr != NULL) { get_sid_and_version_for_signal(signal, ¶ms.psa_connect_params.sid, ¶ms.psa_connect_params.version); /* Fixme: All messages sent with the same client id */ ret = tfm_ns_mailbox_client_call(MAILBOX_PSA_CONNECT, ¶ms, NON_SECURE_CLIENT_ID, (int32_t *)forward_handle_ptr); if (ret != MAILBOX_SUCCESS) { *forward_handle_ptr = PSA_NULL_HANDLE; } if ( *forward_handle_ptr > 0) { psa_set_rhandle(msg->handle, (void *)forward_handle_ptr); return PSA_SUCCESS; } else { deallocate_forward_handle(forward_handle_ptr); return *forward_handle_ptr; } } else { return PSA_ERROR_INSUFFICIENT_MEMORY; } } static void handle_signal(psa_signal_t signal) { psa_msg_t msg; psa_status_t status; status = psa_get(signal, &msg); switch (msg.type) { case PSA_IPC_CONNECT: status = psa_connect_to_secure_enclave(signal, &msg); psa_reply(msg.handle, status); break; case PSA_IPC_DISCONNECT: psa_disconnect_from_secure_enclave(&msg); psa_reply(msg.handle, PSA_SUCCESS); break; default: status = forward_message_to_secure_enclave(signal, &msg); psa_reply(msg.handle, status); break; } } static psa_status_t psa_proxy_init(void) { int32_t ret; if (tfm_platform_ns_wait_for_s_cpu_ready()) { return PSA_ERROR_HARDWARE_FAILURE; } ret = tfm_ns_mailbox_init(psa_proxy_get_ns_mailbox_queue()); if (ret != MAILBOX_SUCCESS) { return PSA_ERROR_GENERIC_ERROR; } init_forward_handle_pool(); return PSA_SUCCESS; } psa_status_t psa_proxy_sp_init(void) { psa_signal_t signal; psa_status_t err; err = psa_proxy_init(); if ( err != PSA_SUCCESS ) { psa_panic(); } while (1) { /* Control is given back to SPM */ signal = psa_wait(PSA_WAIT_ANY, PSA_BLOCK); handle_signal(signal); } return PSA_SUCCESS; }