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