1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company)
4  * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  *
8  */
9 
10 #include "async.h"
11 #include "config_impl.h"
12 #include "spm.h"
13 #include "ffm/agent_api.h"
14 #include "ffm/psa_api.h"
15 #include "tfm_rpc.h"
16 #include "utilities.h"
17 #include "load/partition_defs.h"
18 #include "tfm_psa_call_pack.h"
19 
default_handle_req(void)20 static void default_handle_req(void)
21 {
22 }
23 
default_mailbox_reply(const void * owner,int32_t ret)24 static void default_mailbox_reply(const void *owner, int32_t ret)
25 {
26     (void)owner;
27     (void)ret;
28 }
29 
default_get_caller_data(int32_t client_id)30 static const void *default_get_caller_data(int32_t client_id)
31 {
32     (void)client_id;
33 
34     return NULL;
35 }
36 
37 static struct tfm_rpc_ops_t rpc_ops = {
38     .handle_req = default_handle_req,
39     .reply      = default_mailbox_reply,
40     .get_caller_data = default_get_caller_data,
41 };
42 
tfm_rpc_psa_framework_version(void)43 uint32_t tfm_rpc_psa_framework_version(void)
44 {
45     return tfm_spm_client_psa_framework_version();
46 }
47 
tfm_rpc_psa_version(uint32_t sid)48 uint32_t tfm_rpc_psa_version(uint32_t sid)
49 {
50     return tfm_spm_client_psa_version(sid);
51 }
52 
tfm_rpc_psa_call(psa_handle_t handle,uint32_t control,const struct client_params_t * params,const void * client_data_stateless)53 psa_status_t tfm_rpc_psa_call(psa_handle_t handle, uint32_t control,
54                               const struct client_params_t *params,
55                               const void *client_data_stateless)
56 {
57     SPM_ASSERT(params != NULL);
58 
59     return agent_psa_call(handle, control, params, client_data_stateless);
60 }
61 
62 /* Following PSA APIs are only needed by connection-based services */
63 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
64 
tfm_rpc_psa_connect(uint32_t sid,uint32_t version,int32_t ns_client_id,const void * client_data)65 psa_status_t tfm_rpc_psa_connect(uint32_t sid,
66                                  uint32_t version,
67                                  int32_t ns_client_id,
68                                  const void *client_data)
69 {
70     return agent_psa_connect(sid, version, ns_client_id, client_data);
71 }
72 
tfm_rpc_psa_close(psa_handle_t handle)73 void tfm_rpc_psa_close(psa_handle_t handle)
74 {
75     psa_close(handle);
76 }
77 
78 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
79 
tfm_rpc_register_ops(const struct tfm_rpc_ops_t * ops_ptr)80 int32_t tfm_rpc_register_ops(const struct tfm_rpc_ops_t *ops_ptr)
81 {
82     if (!ops_ptr) {
83         return TFM_RPC_INVAL_PARAM;
84     }
85 
86     if (!ops_ptr->handle_req || !ops_ptr->reply || !ops_ptr->get_caller_data) {
87         return TFM_RPC_INVAL_PARAM;
88     }
89 
90     /* Currently, one and only one mailbox implementation is supported. */
91     if ((rpc_ops.handle_req != default_handle_req) ||
92         (rpc_ops.reply != default_mailbox_reply) ||
93         (rpc_ops.get_caller_data != default_get_caller_data)) {
94         return TFM_RPC_CONFLICT_CALLBACK;
95     }
96 
97     rpc_ops.handle_req = ops_ptr->handle_req;
98     rpc_ops.reply = ops_ptr->reply;
99     rpc_ops.get_caller_data = ops_ptr->get_caller_data;
100 
101     return TFM_RPC_SUCCESS;
102 }
103 
tfm_rpc_unregister_ops(void)104 void tfm_rpc_unregister_ops(void)
105 {
106     rpc_ops.handle_req = default_handle_req;
107     rpc_ops.reply = default_mailbox_reply;
108     rpc_ops.get_caller_data = default_get_caller_data;
109 }
110 
tfm_rpc_client_call_handler(void)111 void tfm_rpc_client_call_handler(void)
112 {
113     rpc_ops.handle_req();
114 }
115 
116 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
tfm_rpc_client_call_reply(void)117 void tfm_rpc_client_call_reply(void)
118 {
119     psa_msg_t msg;
120     psa_status_t status = psa_get(ASYNC_MSG_REPLY, &msg);
121     struct connection_t *handle = (struct connection_t *)msg.rhandle;
122 
123     rpc_ops.reply(handle->caller_data, status);
124 
125     if (handle->status == TFM_HANDLE_STATUS_TO_FREE) {
126         spm_free_connection(handle);
127     } else {
128         handle->status = TFM_HANDLE_STATUS_IDLE;
129     }
130 }
131 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */
132 
tfm_rpc_set_caller_data(struct connection_t * handle,int32_t client_id)133 void tfm_rpc_set_caller_data(struct connection_t *handle, int32_t client_id)
134 {
135     handle->caller_data = rpc_ops.get_caller_data(client_id);
136 }
137