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