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