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