1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2022-2024, Linaro Limited and Contributors. All rights
4 * reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 * Description:
9 * Handle the message coming from the OP-TEE invoke command transport
10 * layer. This module remplaces the hardware mailbox device driver.
11 */
12
13 #include <kernel/mutex.h>
14
15 #include <mod_msg_smt.h>
16 #include <mod_optee_mbx.h>
17 #include <mod_optee_smt.h>
18
19 #include <fwk_arch.h>
20 #include <fwk_id.h>
21 #include <fwk_log.h>
22 #include <fwk_mm.h>
23 #include <fwk_module.h>
24 #include <fwk_module_idx.h>
25 #include <fwk_status.h>
26
27 #include <stddef.h>
28 #include <stdint.h>
29
30 /* MBX device context */
31 struct mbx_device_ctx {
32 /* Channel configuration data */
33 struct mod_optee_mbx_channel_config *config;
34
35 fwk_id_t shmem_id;
36
37 union {
38 struct mod_optee_smt_driver_input_api *smt;
39 struct mod_msg_smt_driver_input_api *msg;
40 } shmem_api;
41
42 size_t *shm_out_size;
43
44 struct mutex lock;
45 };
46
47 /* MBX context */
48 struct mbx_ctx {
49 /* Table of device contexts */
50 struct mbx_device_ctx *device_ctx_table;
51
52 /* Number of devices in the device context table*/
53 unsigned int device_count;
54 };
55
56 static struct mbx_ctx mbx_ctx;
57
58 #ifdef BUILD_HAS_MOD_OPTEE_SMT
optee_mbx_signal_smt_message(fwk_id_t device_id)59 void optee_mbx_signal_smt_message(fwk_id_t device_id)
60 {
61 struct mbx_device_ctx *device_ctx;
62 unsigned int device_idx = fwk_id_get_element_idx(device_id);
63
64 if (device_idx < mbx_ctx.device_count) {
65 device_ctx = &mbx_ctx.device_ctx_table[device_idx];
66
67 fwk_assert(
68 fwk_id_get_module_idx(device_ctx->shmem_id) ==
69 FWK_MODULE_IDX_OPTEE_SMT);
70
71 /* Lock the channel until the message has been processed */
72 mutex_lock(&device_ctx->lock);
73
74 device_ctx->shmem_api.smt->signal_message(device_ctx->shmem_id);
75 } else {
76 fwk_unexpected();
77 }
78 }
79 #endif
80
81 #ifdef BUILD_HAS_MOD_MSG_SMT
optee_mbx_signal_msg_message(fwk_id_t device_id,void * in_buf,size_t in_size,void * out_buf,size_t * out_size)82 void optee_mbx_signal_msg_message(
83 fwk_id_t device_id,
84 void *in_buf,
85 size_t in_size,
86 void *out_buf,
87 size_t *out_size)
88 {
89 struct mbx_device_ctx *device_ctx;
90 unsigned int device_idx = fwk_id_get_element_idx(device_id);
91
92 if (device_idx < mbx_ctx.device_count) {
93 device_ctx = &mbx_ctx.device_ctx_table[device_idx];
94
95 fwk_assert(
96 fwk_id_get_module_idx(device_ctx->shmem_id) ==
97 FWK_MODULE_IDX_MSG_SMT);
98
99 /* Lock the channel until the message has been processed */
100 mutex_lock(&device_ctx->lock);
101
102 device_ctx->shm_out_size = out_size;
103 device_ctx->shmem_api.msg->signal_message(
104 device_ctx->shmem_id, in_buf, in_size, out_buf, *out_size);
105 } else {
106 fwk_unexpected();
107 }
108 }
109 #endif
110
optee_mbx_get_devices_count(void)111 int optee_mbx_get_devices_count(void)
112 {
113 return mbx_ctx.device_count;
114 }
115
optee_mbx_get_device(unsigned int id)116 fwk_id_t optee_mbx_get_device(unsigned int id)
117 {
118 if (id >= mbx_ctx.device_count)
119 return (fwk_id_t)FWK_ID_NONE_INIT;
120
121 return (fwk_id_t)FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_OPTEE_MBX, id);
122 }
123
124 /*
125 * Mailbox module driver API
126 */
127
128 /*
129 * Provide a raise interrupt interface to the Mailbox driver
130 */
raise_smt_interrupt(fwk_id_t channel_id)131 static int raise_smt_interrupt(fwk_id_t channel_id)
132 {
133 size_t idx = fwk_id_get_element_idx(channel_id);
134 struct mbx_device_ctx *channel_ctx = &mbx_ctx.device_ctx_table[idx];
135
136 /* Release the channel as the message has been processed */
137 mutex_unlock(&channel_ctx->lock);
138
139 /* There should be a message in the mailbox */
140 return FWK_SUCCESS;
141 }
142
143 const struct mod_optee_smt_driver_api mbx_smt_api = {
144 .raise_interrupt = raise_smt_interrupt,
145 };
146
raise_shm_notification(fwk_id_t channel_id,size_t size)147 static int raise_shm_notification(fwk_id_t channel_id, size_t size)
148 {
149 size_t idx = fwk_id_get_element_idx(channel_id);
150 struct mbx_device_ctx *channel_ctx = &mbx_ctx.device_ctx_table[idx];
151
152 *channel_ctx->shm_out_size = size;
153
154 /* Release the channel as the message has been processed */
155 mutex_unlock(&channel_ctx->lock);
156
157 return FWK_SUCCESS;
158 }
159
160 const struct mod_msg_smt_driver_ouput_api mbx_shm_api = {
161 .raise_notification = raise_shm_notification,
162 };
163
164 /*
165 * Framework handlers
166 */
167
mbx_init(fwk_id_t module_id,unsigned int device_count,const void * data)168 static int mbx_init(
169 fwk_id_t module_id,
170 unsigned int device_count,
171 const void *data)
172 {
173 if (device_count == 0)
174 return FWK_E_PARAM;
175
176 mbx_ctx.device_ctx_table =
177 fwk_mm_calloc(device_count, sizeof(*mbx_ctx.device_ctx_table));
178 if (mbx_ctx.device_ctx_table == NULL) {
179 return FWK_E_NOMEM;
180 }
181
182 mbx_ctx.device_count = device_count;
183
184 return FWK_SUCCESS;
185 }
186
mbx_device_init(fwk_id_t device_id,unsigned int slot_count,const void * data)187 static int mbx_device_init(
188 fwk_id_t device_id,
189 unsigned int slot_count,
190 const void *data)
191 {
192 size_t elt_idx = fwk_id_get_element_idx(device_id);
193 struct mbx_device_ctx *device_ctx = &mbx_ctx.device_ctx_table[elt_idx];
194
195 device_ctx->config = (struct mod_optee_mbx_channel_config *)data;
196
197 mutex_init(&device_ctx->lock);
198
199 return FWK_SUCCESS;
200 }
201
mbx_bind(fwk_id_t id,unsigned int round)202 static int mbx_bind(fwk_id_t id, unsigned int round)
203 {
204 int status;
205 struct mbx_device_ctx *device_ctx;
206
207 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
208 return FWK_SUCCESS;
209 }
210
211 if (round == 1) {
212 device_ctx = &mbx_ctx.device_ctx_table[fwk_id_get_element_idx(id)];
213
214 status = fwk_module_bind(
215 device_ctx->config->driver_id,
216 device_ctx->config->driver_api_id,
217 &device_ctx->shmem_api);
218 if (status != FWK_SUCCESS) {
219 return status;
220 }
221
222 device_ctx->shmem_id = device_ctx->config->driver_id;
223 }
224
225 return FWK_SUCCESS;
226 }
227
mbx_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)228 static int mbx_process_bind_request(
229 fwk_id_t source_id,
230 fwk_id_t target_id,
231 fwk_id_t api_id,
232 const void **api)
233 {
234 size_t elt_idx;
235
236 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
237 return FWK_E_ACCESS;
238 }
239
240 if (fwk_id_get_api_idx(api_id) != 0) {
241 return FWK_E_PARAM;
242 }
243
244 elt_idx = fwk_id_get_element_idx(target_id);
245 if (elt_idx >= mbx_ctx.device_count) {
246 return FWK_E_PARAM;
247 }
248
249 switch (fwk_id_get_module_idx(source_id)) {
250 #ifdef BUILD_HAS_MOD_OPTEE_SMT
251 case FWK_MODULE_IDX_OPTEE_SMT:
252 *api = &mbx_smt_api;
253 break;
254 #endif
255 #ifdef BUILD_HAS_MOD_MSG_SMT
256 case FWK_MODULE_IDX_MSG_SMT:
257 *api = &mbx_shm_api;
258 break;
259 #endif
260 default:
261 return FWK_E_PANIC;
262 }
263
264 return FWK_SUCCESS;
265 }
266
mbx_start(fwk_id_t id)267 static int mbx_start(fwk_id_t id)
268 {
269 return FWK_SUCCESS;
270 }
271
272 /* OPTEE_MBX module definition */
273 const struct fwk_module module_optee_mbx = {
274 .type = FWK_MODULE_TYPE_DRIVER,
275 .api_count = 1,
276 .init = mbx_init,
277 .element_init = mbx_device_init,
278 .bind = mbx_bind,
279 .start = mbx_start,
280 .process_bind_request = mbx_process_bind_request,
281 };
282