1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2022, Linaro Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Parse the messages pushed on the OP-TEE static memory.
9  */
10 
11 #include <internal/optee_smt.h>
12 #include <optee_scmi.h>
13 
14 #include <mod_scmi.h>
15 #include <mod_optee_smt.h>
16 
17 #include <fwk_assert.h>
18 #include <fwk_interrupt.h>
19 #include <fwk_log.h>
20 #include <fwk_mm.h>
21 #include <fwk_macros.h>
22 #include <fwk_module.h>
23 #include <fwk_module_idx.h>
24 #include <fwk_status.h>
25 #include <fwk_string.h>
26 
27 #include <stdbool.h>
28 
29 struct smt_channel_ctx {
30     /* Channel identifier */
31     fwk_id_t id;
32 
33     /* Channel configuration data */
34     struct mod_optee_smt_channel_config *config;
35 
36     /* Channel mailbox virtual address */
37     uintptr_t mailbox_va;
38 
39     /* Channel read and write cache memory areas */
40     struct mod_optee_smt_memory *in, *out;
41 
42     /* Message processing in progrees flag */
43     volatile bool locked;
44 
45     /* Maximum payload size of the channel */
46     size_t max_payload_size;
47 
48     /* Driver entity identifier */
49     fwk_id_t driver_id;
50 
51     /* SCMI module service bound to the channel */
52     fwk_id_t scmi_service_id;
53 
54     /* Driver API */
55     struct mod_optee_smt_driver_api *driver_api;
56 
57     /* SCMI service API */
58     struct mod_scmi_from_transport_api *scmi_api;
59 
60     /* Flag indicating the mailbox is ready */
61     bool optee_smt_mailbox_ready;
62 };
63 
64 struct mod_smt_ctx {
65     /* Table of channel contexts */
66     struct smt_channel_ctx *channel_ctx_table;
67 
68     /* Number of channels */
69     unsigned int channel_count;
70 };
71 
72 static struct mod_smt_ctx smt_ctx;
73 
74 /*
75  * SCMI Transport API
76  */
smt_get_secure(fwk_id_t channel_id,bool * secure)77 static int smt_get_secure(fwk_id_t channel_id, bool *secure)
78 {
79     struct smt_channel_ctx *channel_ctx;
80 
81     if (secure == NULL) {
82         fwk_unexpected();
83         return FWK_E_PARAM;
84     }
85 
86     channel_ctx =
87         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
88 
89     *secure =
90         ((channel_ctx->config->policies & MOD_SMT_POLICY_SECURE) !=
91          (uint32_t)0);
92 
93     return FWK_SUCCESS;
94 }
95 
smt_get_max_payload_size(fwk_id_t channel_id,size_t * size)96 static int smt_get_max_payload_size(fwk_id_t channel_id, size_t *size)
97 {
98     struct smt_channel_ctx *channel_ctx;
99 
100     if (size == NULL) {
101         fwk_unexpected();
102         return FWK_E_PARAM;
103     }
104 
105     channel_ctx =
106         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
107 
108     *size = channel_ctx->max_payload_size;
109 
110     return FWK_SUCCESS;
111 }
112 
smt_get_message_header(fwk_id_t channel_id,uint32_t * header)113 static int smt_get_message_header(fwk_id_t channel_id, uint32_t *header)
114 {
115     struct smt_channel_ctx *channel_ctx;
116 
117     if (header == NULL) {
118         fwk_unexpected();
119         return FWK_E_PARAM;
120     }
121 
122     channel_ctx =
123         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
124 
125     if (!channel_ctx->locked) {
126         return FWK_E_ACCESS;
127     }
128 
129     *header = channel_ctx->in->message_header;
130 
131     return FWK_SUCCESS;
132 }
133 
smt_get_payload(fwk_id_t channel_id,const void ** payload,size_t * size)134 static int smt_get_payload(fwk_id_t channel_id,
135                            const void **payload,
136                            size_t *size)
137 {
138     struct smt_channel_ctx *channel_ctx;
139 
140     if (payload == NULL) {
141         fwk_unexpected();
142         return FWK_E_PARAM;
143     }
144 
145     channel_ctx =
146         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
147 
148     if (!channel_ctx->locked) {
149         return FWK_E_ACCESS;
150     }
151 
152     *payload = channel_ctx->in->payload;
153 
154     if (size != NULL) {
155         *size = channel_ctx->in->length -
156             sizeof(channel_ctx->in->message_header);
157     }
158 
159     return FWK_SUCCESS;
160 }
161 
smt_write_payload(fwk_id_t channel_id,size_t offset,const void * payload,size_t size)162 static int smt_write_payload(fwk_id_t channel_id,
163                              size_t offset,
164                              const void *payload,
165                              size_t size)
166 {
167     struct smt_channel_ctx *channel_ctx;
168 
169     channel_ctx =
170         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
171 
172     if ((payload == NULL)                         ||
173         (offset  > channel_ctx->max_payload_size) ||
174         (size > channel_ctx->max_payload_size)    ||
175         ((offset + size) > channel_ctx->max_payload_size)) {
176         fwk_unexpected();
177         return FWK_E_PARAM;
178     }
179 
180     if (!channel_ctx->locked) {
181         return FWK_E_ACCESS;
182     }
183 
184     fwk_str_memcpy(
185         ((uint8_t *)channel_ctx->out->payload) + offset, payload, size);
186 
187     return FWK_SUCCESS;
188 }
189 
smt_respond(fwk_id_t channel_id,const void * payload,size_t size)190 static int smt_respond(fwk_id_t channel_id, const void *payload, size_t size)
191 {
192     struct smt_channel_ctx *channel_ctx;
193     struct mod_optee_smt_memory *memory;
194 
195     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
196     memory = (struct mod_optee_smt_memory *)channel_ctx->mailbox_va;
197 
198     /* Copy the header from the write buffer */
199     *memory = *channel_ctx->out;
200 
201     /* Copy the payload from either the write buffer or the payload parameter */
202     fwk_str_memcpy(
203         memory->payload,
204         (payload == NULL ? channel_ctx->out->payload : payload),
205         size);
206 
207     channel_ctx->locked = false;
208 
209     memory->length = sizeof(memory->message_header) + size;
210     memory->status |= MOD_OPTEE_SMT_MAILBOX_STATUS_FREE_MASK;
211 
212     channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id);
213 
214     return FWK_SUCCESS;
215 }
216 
smt_transmit(fwk_id_t channel_id,uint32_t message_header,const void * payload,size_t size,bool request_ack_by_interrupt)217 static int smt_transmit(fwk_id_t channel_id, uint32_t message_header,
218     const void *payload, size_t size, bool request_ack_by_interrupt)
219 {
220     struct smt_channel_ctx *channel_ctx;
221     struct mod_optee_smt_memory *memory;
222 
223     if (payload == NULL) {
224         return FWK_E_DATA;
225     }
226 
227     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
228     memory = (struct mod_optee_smt_memory *)channel_ctx->mailbox_va;
229 
230     if (!channel_ctx->locked) {
231         return FWK_SUCCESS;
232     }
233 
234     memory->message_header = message_header;
235 
236     /*
237      * we do not want the agent to send an interrupt when it receives
238      * the message.
239      */
240     memory->flags = 0;
241 
242     /* Copy the payload */
243     fwk_str_memcpy(memory->payload, payload, size);
244 
245     memory->length = sizeof(memory->message_header) + size;
246     memory->status &= ~MOD_OPTEE_SMT_MAILBOX_STATUS_FREE_MASK;
247 
248     /* Release the channel */
249     channel_ctx->locked = false;
250 
251     /* Notify the agent */
252     channel_ctx->driver_api->raise_interrupt(channel_ctx->driver_id);
253 
254     return FWK_SUCCESS;
255 }
256 
257 static const struct mod_scmi_to_transport_api smt_mod_scmi_to_transport_api = {
258     .get_secure = smt_get_secure,
259     .get_max_payload_size = smt_get_max_payload_size,
260     .get_message_header = smt_get_message_header,
261     .get_payload = smt_get_payload,
262     .write_payload = smt_write_payload,
263     .respond = smt_respond,
264     .transmit = smt_transmit,
265 };
266 
267 /*
268  * Driver handler API
269  */
smt_requester_handler(struct smt_channel_ctx * channel_ctx)270 static int smt_requester_handler(struct smt_channel_ctx *channel_ctx)
271 {
272     struct mod_optee_smt_memory *memory;
273     struct mod_optee_smt_memory *in;
274     struct mod_optee_smt_memory *out;
275     size_t payload_size;
276     int status;
277 
278     /* Commit to sending a response */
279     channel_ctx->locked = true;
280 
281     memory = (struct mod_optee_smt_memory *)channel_ctx->mailbox_va;
282 
283     in = channel_ctx->in;
284     out = channel_ctx->out;
285 
286     /* Mirror mailbox contents in read and write buffers (Payload not copied) */
287     *in  = *memory;
288     *out = *memory;
289 
290     /* Ensure error bit is not set */
291     out->status &= ~MOD_OPTEE_SMT_MAILBOX_STATUS_ERROR_MASK;
292 
293     /*
294      * Verify:
295      * 1. The length is at least as large as the message header
296      * 2. The length, minus the size of the message header, is less than or
297      *         equal to the maximum payload size
298      *
299      * Note: the payload size is permitted to be of size zero.
300      */
301     if ((in->length < sizeof(in->message_header)) ||
302         ((in->length - sizeof(in->message_header))
303          > channel_ctx->max_payload_size)) {
304 
305         out->status |= MOD_OPTEE_SMT_MAILBOX_STATUS_ERROR_MASK;
306         return smt_respond(channel_ctx->id,
307                            &(int32_t){ SCMI_PROTOCOL_ERROR },
308                            sizeof(int32_t));
309     }
310 
311     /* Copy payload from shared memory to read buffer */
312     payload_size = in->length - sizeof(in->message_header);
313     fwk_str_memcpy(in->payload, memory->payload, payload_size);
314 
315     /* Let SCMI handle the message */
316     status =
317         channel_ctx->scmi_api->signal_message(channel_ctx->scmi_service_id);
318     if (status != FWK_SUCCESS) {
319         return FWK_E_HANDLER;
320     }
321 
322     return FWK_SUCCESS;
323 }
324 
smt_completer_handler(struct smt_channel_ctx * channel_ctx)325 static int smt_completer_handler(struct smt_channel_ctx *channel_ctx)
326 {
327     /* Commit to sending a response */
328     channel_ctx->locked = true;
329 
330     return FWK_SUCCESS;
331 }
332 
smt_signal_message(fwk_id_t channel_id)333 static int smt_signal_message(fwk_id_t channel_id)
334 {
335     struct smt_channel_ctx *channel_ctx;
336 
337     channel_ctx =
338         &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(channel_id)];
339 
340     if (!channel_ctx->optee_smt_mailbox_ready) {
341         /* Discard any message in the mailbox when not ready */
342         FWK_LOG_ERR("[OPTEE_SMT] Message not valid\n");
343 
344         return FWK_SUCCESS;
345     }
346 
347     /* Check if we are already processing */
348     if (channel_ctx->locked) {
349         return FWK_E_STATE;
350     }
351 
352     switch (channel_ctx->config->type) {
353     case MOD_OPTEE_SMT_CHANNEL_TYPE_COMPLETER:
354         return smt_completer_handler(channel_ctx);
355     case MOD_OPTEE_SMT_CHANNEL_TYPE_REQUESTER:
356         return smt_requester_handler(channel_ctx);
357     default:
358         /* Invalid config */
359         fwk_unexpected();
360         break;
361     }
362 
363     return FWK_SUCCESS;
364 }
365 
366 static const struct mod_optee_smt_driver_input_api driver_input_api = {
367     .signal_message = smt_signal_message,
368 };
369 
370 /*
371  * Framework API
372  */
mailbox_init(fwk_id_t module_id,unsigned int element_count,const void * data)373 static int mailbox_init(fwk_id_t module_id, unsigned int element_count,
374                         const void *data)
375 {
376 
377     if (element_count == 0) {
378         return FWK_E_PARAM;
379     }
380 
381     smt_ctx.channel_ctx_table =
382         fwk_mm_calloc(element_count, sizeof(*smt_ctx.channel_ctx_table));
383 
384     if (smt_ctx.channel_ctx_table == NULL) {
385         return FWK_E_NOMEM;
386     }
387 
388     smt_ctx.channel_count = element_count;
389 
390     return FWK_SUCCESS;
391 }
392 
mailbox_channel_init(fwk_id_t channel_id,unsigned int slot_count,const void * data)393 static int mailbox_channel_init(fwk_id_t channel_id, unsigned int slot_count,
394                             const void *data)
395 {
396     size_t elt_idx = fwk_id_get_element_idx(channel_id);
397     struct smt_channel_ctx *channel_ctx = &smt_ctx.channel_ctx_table[elt_idx];
398     struct mod_optee_smt_channel_config *config;
399     struct mod_optee_smt_memory *memory;
400 
401     config = (struct mod_optee_smt_channel_config*)data;
402 
403     /* Validate channel config */
404     if ((config->type >= MOD_OPTEE_SMT_CHANNEL_TYPE_COUNT) ||
405         (config->mailbox_address == 0) || (config->mailbox_size == 0)) {
406         fwk_unexpected();
407         return FWK_E_DATA;
408     }
409 
410     channel_ctx->mailbox_va = smt_phys_to_virt(config->mailbox_address,
411                                                config->mailbox_size,
412                                                config->policies &
413                                                MOD_SMT_POLICY_SECURE);
414     if (channel_ctx->mailbox_va == 0) {
415         fwk_unexpected();
416         return FWK_E_DATA;
417     }
418 
419     channel_ctx->id = channel_id;
420     channel_ctx->in = fwk_mm_alloc(1, config->mailbox_size);
421     channel_ctx->out = fwk_mm_alloc(1, config->mailbox_size);
422 
423     channel_ctx->max_payload_size = config->mailbox_size -
424                                     sizeof(struct mod_optee_smt_memory);
425 
426     memory = (struct mod_optee_smt_memory *)channel_ctx->mailbox_va;
427     memory->status = MOD_OPTEE_SMT_MAILBOX_STATUS_FREE_MASK;
428 
429     channel_ctx->config = config;
430     channel_ctx->optee_smt_mailbox_ready = true;
431 
432     return FWK_SUCCESS;
433 }
434 
mailbox_smt_bind(fwk_id_t id,unsigned int round)435 static int mailbox_smt_bind(fwk_id_t id, unsigned int round)
436 {
437     int status;
438     struct smt_channel_ctx *channel_ctx;
439 
440     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
441         return FWK_SUCCESS;
442     }
443 
444     channel_ctx = &smt_ctx.channel_ctx_table[fwk_id_get_element_idx(id)];
445 
446     if (round == 0) {
447 
448         status = fwk_module_bind(channel_ctx->config->driver_id,
449                                  channel_ctx->config->driver_api_id,
450                                  &channel_ctx->driver_api);
451         if (status != FWK_SUCCESS) {
452             return status;
453         }
454 
455         channel_ctx->driver_id = channel_ctx->config->driver_id;
456 
457     } else if (round == 1) {
458 
459         status = fwk_module_bind(channel_ctx->scmi_service_id,
460                                  FWK_ID_API(FWK_MODULE_IDX_SCMI,
461                                             MOD_SCMI_API_IDX_TRANSPORT),
462                                  &channel_ctx->scmi_api);
463         if (status != FWK_SUCCESS) {
464             return status;
465         }
466     }
467 
468     return FWK_SUCCESS;
469 }
470 
mailbox_smt_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)471 static int mailbox_smt_process_bind_request(fwk_id_t source_id,
472                                           fwk_id_t target_id,
473                                           fwk_id_t api_id,
474                                           const void **api)
475 {
476     struct smt_channel_ctx *channel_ctx = NULL;
477     size_t elt_idx;
478 
479     /* Only bind to a channel (not the whole module) */
480     if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
481         /* Tried to bind to something other than a specific channel */
482         fwk_unexpected();
483         return FWK_E_PARAM;
484     }
485 
486     elt_idx = fwk_id_get_element_idx(target_id);
487     if (elt_idx >= smt_ctx.channel_count) {
488         return FWK_E_ACCESS;
489     }
490 
491     channel_ctx = &smt_ctx.channel_ctx_table[elt_idx];
492 
493     switch (fwk_id_get_api_idx(api_id)) {
494     case MOD_OPTEE_SMT_API_IDX_DRIVER_INPUT:
495         /* Driver input API */
496 
497         /*
498          * Make sure that the element that is trying to bind to us is the
499          * same element that we previously bound to.
500          *
501          * NOTE: We bound to an element but a sub-element should be binding
502          * back to us. This means we cannot use fwk_id_is_equal() because
503          * the ids have different types. For now we compare the indicies
504          * manually.
505          */
506         if (fwk_id_get_module_idx(channel_ctx->driver_id) ==
507             fwk_id_get_module_idx(source_id) &&
508             fwk_id_get_element_idx(channel_ctx->driver_id) ==
509             fwk_id_get_element_idx(source_id)) {
510 
511             /* Ids are equal */
512             *api = &driver_input_api;
513         } else {
514             /* A module that we did not bind to is trying to bind to us */
515             fwk_unexpected();
516             return FWK_E_ACCESS;
517         }
518         break;
519 
520     case MOD_OPTEE_SMT_API_IDX_SCMI_TRANSPORT:
521         /* SCMI transport API */
522         *api = &smt_mod_scmi_to_transport_api;
523         channel_ctx->scmi_service_id = source_id;
524         break;
525 
526     default:
527         /* Invalid API */
528         fwk_unexpected();
529         return FWK_E_PARAM;
530     }
531 
532     return FWK_SUCCESS;
533 }
534 
mailbox_start(fwk_id_t id)535 static int mailbox_start(fwk_id_t id)
536 {
537     return FWK_SUCCESS;
538 }
539 
540 const struct fwk_module module_optee_smt = {
541     .type = FWK_MODULE_TYPE_SERVICE,
542     .api_count = MOD_OPTEE_SMT_API_IDX_COUNT,
543     .init = mailbox_init,
544     .element_init = mailbox_channel_init,
545     .bind = mailbox_smt_bind,
546     .start = mailbox_start,
547     .process_bind_request = mailbox_smt_process_bind_request,
548 };
549