1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4  */
5 
6 #include <stdbool.h>
7 
8 #include "async.h"
9 #include "config_impl.h"
10 #include "ns_agent_mailbox_rpc.h"
11 #include "spm.h"
12 #include "tfm_log_unpriv.h"
13 #include "tfm_rpc.h"
14 
default_handle_req(void)15 static void default_handle_req(void)
16 {
17     psa_panic();
18 }
19 
default_mailbox_reply(const void * owner,int32_t ret)20 static void default_mailbox_reply(const void *owner, int32_t ret)
21 {
22     (void)owner;
23     (void)ret;
24 
25     psa_panic();
26 }
27 
default_handle_req_irq_src(uint32_t irq_src)28 static void default_handle_req_irq_src(uint32_t irq_src)
29 {
30     (void)irq_src;
31 
32     psa_panic();
33 }
34 
default_process_new_msg(uint32_t * nr_msg)35 static int32_t default_process_new_msg(uint32_t *nr_msg)
36 {
37     return PSA_SUCCESS;
38 }
39 
40 static struct tfm_rpc_ops_t rpc_ops = {
41     .handle_req = default_handle_req,
42     .reply      = default_mailbox_reply,
43     .handle_req_irq_src = default_handle_req_irq_src,
44     .process_new_msg = default_process_new_msg,
45 };
46 
tfm_rpc_register_ops(const struct tfm_rpc_ops_t * ops_ptr)47 int32_t tfm_rpc_register_ops(const struct tfm_rpc_ops_t *ops_ptr)
48 {
49     if (ops_ptr == NULL) {
50         return TFM_RPC_INVAL_PARAM;
51     }
52 
53     if ((ops_ptr->handle_req == NULL) || (ops_ptr->reply == NULL)) {
54         return TFM_RPC_INVAL_PARAM;
55     }
56 
57     /* Currently, one and only one RPC callback instance is supported. */
58     if ((rpc_ops.handle_req != default_handle_req) ||
59         (rpc_ops.reply != default_mailbox_reply)) {
60         return TFM_RPC_CONFLICT_CALLBACK;
61     }
62 
63     rpc_ops.handle_req = ops_ptr->handle_req;
64     rpc_ops.reply = ops_ptr->reply;
65     rpc_ops.handle_req_irq_src = default_handle_req_irq_src;
66     if (ops_ptr->process_new_msg != NULL) {
67         rpc_ops.process_new_msg = ops_ptr->process_new_msg;
68     }
69 
70     return TFM_RPC_SUCCESS;
71 }
72 
tfm_rpc_register_ops_multi_srcs(const struct tfm_rpc_ops_t * ops_ptr)73 int32_t tfm_rpc_register_ops_multi_srcs(const struct tfm_rpc_ops_t *ops_ptr)
74 {
75     if (ops_ptr == NULL) {
76         return TFM_RPC_INVAL_PARAM;
77     }
78 
79     if ((ops_ptr->handle_req_irq_src == NULL) || (ops_ptr->reply == NULL)) {
80         return TFM_RPC_INVAL_PARAM;
81     }
82 
83     /* Currently, one and only one RPC callback instance is supported. */
84     if ((rpc_ops.handle_req_irq_src != default_handle_req_irq_src) ||
85         (rpc_ops.reply != default_mailbox_reply)) {
86         return TFM_RPC_CONFLICT_CALLBACK;
87     }
88 
89     rpc_ops.handle_req = default_handle_req;
90     rpc_ops.reply = ops_ptr->reply;
91     rpc_ops.handle_req_irq_src = ops_ptr->handle_req_irq_src;
92     if (ops_ptr->process_new_msg != NULL) {
93         rpc_ops.process_new_msg = ops_ptr->process_new_msg;
94     }
95 
96     return TFM_RPC_SUCCESS;
97 }
98 
tfm_rpc_unregister_ops(void)99 void tfm_rpc_unregister_ops(void)
100 {
101     rpc_ops.handle_req = default_handle_req;
102     rpc_ops.reply = default_mailbox_reply;
103     rpc_ops.handle_req_irq_src = default_handle_req_irq_src;
104     rpc_ops.process_new_msg = default_process_new_msg;
105 }
106 
tfm_rpc_client_call_handler(psa_signal_t signal)107 void tfm_rpc_client_call_handler(psa_signal_t signal)
108 {
109     uint32_t irq_src;
110 
111     if (rpc_ops.handle_req_irq_src != default_handle_req_irq_src) {
112         irq_src = rpc_map_signal_to_irq(signal);
113         if (irq_src == INVALID_MAILBOX_IRQ) {
114             psa_panic();
115         }
116 
117         rpc_ops.handle_req_irq_src(irq_src);
118         return;
119     }
120 
121     rpc_ops.handle_req();
122 }
123 
124 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
tfm_rpc_client_call_reply(void)125 void tfm_rpc_client_call_reply(void)
126 {
127     psa_msg_t msg;
128     struct connection_t *handle;
129     psa_status_t status;
130 
131     status = psa_get(ASYNC_MSG_REPLY, &msg);
132     if (status != PSA_SUCCESS) {
133         ERROR_UNPRIV("psa_get(ASYNC_MSG_REPLY) call returned %d\n", status);
134         return;
135     }
136 
137     handle = (struct connection_t *)msg.rhandle;
138 
139     rpc_ops.reply(handle->client_data, handle->replied_value);
140 
141     if (handle->status == TFM_HANDLE_STATUS_TO_FREE) {
142         spm_free_connection(handle);
143     } else {
144         handle->status = TFM_HANDLE_STATUS_IDLE;
145     }
146 }
147 #endif /* CONFIG_TFM_SPM_BACKEND_IPC == 1 */
148 
tfm_rpc_client_process_new_msg(uint32_t * nr_msg)149 int32_t tfm_rpc_client_process_new_msg(uint32_t *nr_msg)
150 {
151     return rpc_ops.process_new_msg(nr_msg);
152 }
153