blob: 227d7cf52ed1d91e266faeea20118b86f5dd424b [file] [log] [blame]
Marc Bonnici9f23c8d2021-10-01 16:06:04 +01001/*
2 * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <errno.h>
7
8#include <common/debug.h>
9#include <common/runtime_svc.h>
10#include <lib/object_pool.h>
11#include <lib/spinlock.h>
12#include <lib/xlat_tables/xlat_tables_v2.h>
13#include <services/ffa_svc.h>
14#include "spmc.h"
15#include "spmc_shared_mem.h"
16
17#include <platform_def.h>
18
19/**
20 * struct spmc_shmem_obj - Shared memory object.
21 * @desc_size: Size of @desc.
22 * @desc_filled: Size of @desc already received.
23 * @in_use: Number of clients that have called ffa_mem_retrieve_req
24 * without a matching ffa_mem_relinquish call.
25 * @desc: FF-A memory region descriptor passed in ffa_mem_share.
26 */
27struct spmc_shmem_obj {
28 size_t desc_size;
29 size_t desc_filled;
30 size_t in_use;
31 struct ffa_mtd_v1_0 desc;
32};
33
34/*
35 * Declare our data structure to store the metadata of memory share requests.
36 * The main datastore is allocated on a per platform basis to ensure enough
37 * storage can be made available.
38 * The address of the data store will be populated by the SPMC during its
39 * initialization.
40 */
41
42struct spmc_shmem_obj_state spmc_shmem_obj_state = {
43 /* Set start value for handle so top 32 bits are needed quickly. */
44 .next_handle = 0xffffffc0U,
45};
46
47/**
48 * spmc_shmem_obj_size - Convert from descriptor size to object size.
49 * @desc_size: Size of struct ffa_memory_region_descriptor object.
50 *
51 * Return: Size of struct spmc_shmem_obj object.
52 */
53static size_t spmc_shmem_obj_size(size_t desc_size)
54{
55 return desc_size + offsetof(struct spmc_shmem_obj, desc);
56}
57
58/**
59 * spmc_shmem_obj_alloc - Allocate struct spmc_shmem_obj.
60 * @state: Global state.
61 * @desc_size: Size of struct ffa_memory_region_descriptor object that
62 * allocated object will hold.
63 *
64 * Return: Pointer to newly allocated object, or %NULL if there not enough space
65 * left. The returned pointer is only valid while @state is locked, to
66 * used it again after unlocking @state, spmc_shmem_obj_lookup must be
67 * called.
68 */
69static struct spmc_shmem_obj *
70spmc_shmem_obj_alloc(struct spmc_shmem_obj_state *state, size_t desc_size)
71{
72 struct spmc_shmem_obj *obj;
73 size_t free = state->data_size - state->allocated;
74
75 if (state->data == NULL) {
76 ERROR("Missing shmem datastore!\n");
77 return NULL;
78 }
79
80 if (spmc_shmem_obj_size(desc_size) > free) {
81 WARN("%s(0x%zx) failed, free 0x%zx\n",
82 __func__, desc_size, free);
83 return NULL;
84 }
85 obj = (struct spmc_shmem_obj *)(state->data + state->allocated);
86 obj->desc = (struct ffa_mtd_v1_0) {0};
87 obj->desc_size = desc_size;
88 obj->desc_filled = 0;
89 obj->in_use = 0;
90 state->allocated += spmc_shmem_obj_size(desc_size);
91 return obj;
92}
93
94/**
95 * spmc_shmem_obj_free - Free struct spmc_shmem_obj.
96 * @state: Global state.
97 * @obj: Object to free.
98 *
99 * Release memory used by @obj. Other objects may move, so on return all
100 * pointers to struct spmc_shmem_obj object should be considered invalid, not
101 * just @obj.
102 *
103 * The current implementation always compacts the remaining objects to simplify
104 * the allocator and to avoid fragmentation.
105 */
106
107static void spmc_shmem_obj_free(struct spmc_shmem_obj_state *state,
108 struct spmc_shmem_obj *obj)
109{
110 size_t free_size = spmc_shmem_obj_size(obj->desc_size);
111 uint8_t *shift_dest = (uint8_t *)obj;
112 uint8_t *shift_src = shift_dest + free_size;
113 size_t shift_size = state->allocated - (shift_src - state->data);
114
115 if (shift_size != 0U) {
116 memmove(shift_dest, shift_src, shift_size);
117 }
118 state->allocated -= free_size;
119}
120
121/**
122 * spmc_shmem_obj_lookup - Lookup struct spmc_shmem_obj by handle.
123 * @state: Global state.
124 * @handle: Unique handle of object to return.
125 *
126 * Return: struct spmc_shmem_obj_state object with handle matching @handle.
127 * %NULL, if not object in @state->data has a matching handle.
128 */
129static struct spmc_shmem_obj *
130spmc_shmem_obj_lookup(struct spmc_shmem_obj_state *state, uint64_t handle)
131{
132 uint8_t *curr = state->data;
133
134 while (curr - state->data < state->allocated) {
135 struct spmc_shmem_obj *obj = (struct spmc_shmem_obj *)curr;
136
137 if (obj->desc.handle == handle) {
138 return obj;
139 }
140 curr += spmc_shmem_obj_size(obj->desc_size);
141 }
142 return NULL;
143}
144
145static struct ffa_comp_mrd *
146spmc_shmem_obj_get_comp_mrd(struct spmc_shmem_obj *obj)
147{
148 return (struct ffa_comp_mrd *)
149 ((uint8_t *)(&obj->desc) + obj->desc.emad[0].comp_mrd_offset);
150}
151
152/**
153 * spmc_shmem_obj_ffa_constituent_size - Calculate variable size part of obj.
154 * @obj: Object containing ffa_memory_region_descriptor.
155 *
156 * Return: Size of ffa_constituent_memory_region_descriptors in @obj.
157 */
158static size_t
159spmc_shmem_obj_ffa_constituent_size(struct spmc_shmem_obj *obj)
160{
161 return spmc_shmem_obj_get_comp_mrd(obj)->address_range_count *
162 sizeof(struct ffa_cons_mrd);
163}
164
165/**
166 * spmc_shmem_check_obj - Check that counts in descriptor match overall size.
167 * @obj: Object containing ffa_memory_region_descriptor.
168 *
Marc Bonnici336630f2022-01-13 11:39:10 +0000169 * Return: 0 if object is valid, -EINVAL if constituent_memory_region_descriptor
170 * offset or count is invalid.
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100171 */
172static int spmc_shmem_check_obj(struct spmc_shmem_obj *obj)
173{
Marc Bonnici336630f2022-01-13 11:39:10 +0000174 if (obj->desc.emad_count == 0U) {
175 WARN("%s: unsupported attribute desc count %u.\n",
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100176 __func__, obj->desc.emad_count);
177 return -EINVAL;
178 }
179
Marc Bonnici336630f2022-01-13 11:39:10 +0000180 /*
181 * Ensure the emad array lies within the bounds of the descriptor by
182 * checking the address of the element past the end of the array.
183 */
184 if ((uintptr_t) &obj->desc.emad[obj->desc.emad_count] >
185 (uintptr_t)((uint8_t *) &obj->desc + obj->desc_size)) {
186 WARN("Invalid emad access.\n");
187 return -EINVAL;
188 }
189
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100190 for (size_t emad_num = 0; emad_num < obj->desc.emad_count; emad_num++) {
191 size_t size;
192 size_t count;
193 size_t expected_size;
194 size_t total_page_count;
195 struct ffa_comp_mrd *comp;
196
197 uint32_t offset = obj->desc.emad[emad_num].comp_mrd_offset;
198 size_t header_emad_size = sizeof(obj->desc) +
199 obj->desc.emad_count * sizeof(obj->desc.emad[emad_num]);
200
201 if (offset < header_emad_size) {
202 WARN("%s: invalid object, offset %u < header + emad %zu\n",
203 __func__, offset, header_emad_size);
204 return -EINVAL;
205 }
206
207 size = obj->desc_size;
208
209 if (offset > size) {
210 WARN("%s: invalid object, offset %u > total size %zu\n",
211 __func__, offset, obj->desc_size);
212 return -EINVAL;
213 }
214 size -= offset;
215
216 if (size < sizeof(struct ffa_comp_mrd)) {
217 WARN("%s: invalid object, offset %u, total size %zu, no header space.\n",
218 __func__, offset, obj->desc_size);
219 return -EINVAL;
220 }
221 size -= sizeof(struct ffa_comp_mrd);
222
223 count = size / sizeof(struct ffa_cons_mrd);
224
225 comp = spmc_shmem_obj_get_comp_mrd(obj);
226
227 if (comp->address_range_count != count) {
228 WARN("%s: invalid object, desc count %u != %zu\n",
229 __func__, comp->address_range_count, count);
230 return -EINVAL;
231 }
232
233 expected_size = offset + sizeof(*comp) +
234 spmc_shmem_obj_ffa_constituent_size(obj);
235 if (expected_size != obj->desc_size) {
236 WARN("%s: invalid object, computed size %zu != size %zu\n",
237 __func__, expected_size, obj->desc_size);
238 return -EINVAL;
239 }
240
241 if (obj->desc_filled < obj->desc_size) {
242 /*
243 * The whole descriptor has not yet been received.
244 * Skip final checks.
245 */
246 return 0;
247 }
248
249 total_page_count = 0;
250
251 for (size_t i = 0; i < count; i++) {
252 total_page_count +=
253 comp->address_range_array[i].page_count;
254 }
255 if (comp->total_page_count != total_page_count) {
256 WARN("%s: invalid object, desc total_page_count %u != %zu\n",
257 __func__, comp->total_page_count,
258 total_page_count);
259 return -EINVAL;
260 }
261 }
262
263 return 0;
264}
265
266static long spmc_ffa_fill_desc(struct mailbox *mbox,
267 struct spmc_shmem_obj *obj,
268 uint32_t fragment_length,
269 ffa_mtd_flag32_t mtd_flag,
270 void *smc_handle)
271{
272 int ret;
273 uint32_t handle_low;
274 uint32_t handle_high;
275
276 if (mbox->rxtx_page_count == 0U) {
277 WARN("%s: buffer pair not registered.\n", __func__);
278 ret = -EINVAL;
279 goto err_arg;
280 }
281
282 if (fragment_length > mbox->rxtx_page_count * PAGE_SIZE_4KB) {
283 WARN("%s: bad fragment size %u > %u buffer size\n", __func__,
284 fragment_length, mbox->rxtx_page_count * PAGE_SIZE_4KB);
285 ret = -EINVAL;
286 goto err_arg;
287 }
288
289 memcpy((uint8_t *)&obj->desc + obj->desc_filled,
290 (uint8_t *) mbox->tx_buffer,
291 fragment_length);
292
293 if (fragment_length > obj->desc_size - obj->desc_filled) {
294 WARN("%s: bad fragment size %u > %zu remaining\n", __func__,
295 fragment_length, obj->desc_size - obj->desc_filled);
296 ret = -EINVAL;
297 goto err_arg;
298 }
299
300 /* Ensure that the sender ID resides in the normal world. */
301 if (ffa_is_secure_world_id(obj->desc.sender_id)) {
302 WARN("%s: Invalid sender ID 0x%x.\n",
303 __func__, obj->desc.sender_id);
304 ret = FFA_ERROR_DENIED;
305 goto err_arg;
306 }
307
308 /*
309 * We don't currently support any optional flags so ensure none are
310 * requested.
311 */
312 if (obj->desc.flags != 0U && mtd_flag != 0U &&
313 (obj->desc.flags != mtd_flag)) {
314 WARN("%s: invalid memory transaction flags %u != %u\n",
315 __func__, obj->desc.flags, mtd_flag);
316 ret = -EINVAL;
317 goto err_arg;
318 }
319
320 if (obj->desc_filled == 0U) {
321 /* First fragment, descriptor header has been copied */
322 obj->desc.handle = spmc_shmem_obj_state.next_handle++;
323 obj->desc.flags |= mtd_flag;
324 }
325
326 obj->desc_filled += fragment_length;
327
328 ret = spmc_shmem_check_obj(obj);
329 if (ret != 0) {
330 goto err_bad_desc;
331 }
332
333 handle_low = (uint32_t)obj->desc.handle;
334 handle_high = obj->desc.handle >> 32;
335
336 if (obj->desc_filled != obj->desc_size) {
337 SMC_RET8(smc_handle, FFA_MEM_FRAG_RX, handle_low,
338 handle_high, obj->desc_filled,
339 (uint32_t)obj->desc.sender_id << 16, 0, 0, 0);
340 }
341
Marc Bonnici336630f2022-01-13 11:39:10 +0000342 /* The full descriptor has been received, perform any final checks. */
343
344 /*
345 * If a partition ID resides in the secure world validate that the
346 * partition ID is for a known partition. Ignore any partition ID
347 * belonging to the normal world as it is assumed the Hypervisor will
348 * have validated these.
349 */
350 for (size_t i = 0; i < obj->desc.emad_count; i++) {
351 ffa_endpoint_id16_t ep_id = obj->desc.emad[i].mapd.endpoint_id;
352
353 if (ffa_is_secure_world_id(ep_id)) {
354 if (spmc_get_sp_ctx(ep_id) == NULL) {
355 WARN("%s: Invalid receiver id 0x%x\n",
356 __func__, ep_id);
357 ret = FFA_ERROR_INVALID_PARAMETER;
358 goto err_bad_desc;
359 }
360 }
361 }
362
363 /* Ensure partition IDs are not duplicated. */
364 for (size_t i = 0; i < obj->desc.emad_count; i++) {
365 for (size_t j = i + 1; j < obj->desc.emad_count; j++) {
366 if (obj->desc.emad[i].mapd.endpoint_id ==
367 obj->desc.emad[j].mapd.endpoint_id) {
368 ret = FFA_ERROR_INVALID_PARAMETER;
369 goto err_bad_desc;
370 }
371 }
372 }
373
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100374 SMC_RET8(smc_handle, FFA_SUCCESS_SMC32, 0, handle_low, handle_high, 0,
375 0, 0, 0);
376
377err_bad_desc:
378err_arg:
379 spmc_shmem_obj_free(&spmc_shmem_obj_state, obj);
380 return spmc_ffa_error_return(smc_handle, FFA_ERROR_INVALID_PARAMETER);
381}
382
383/**
384 * spmc_ffa_mem_send - FFA_MEM_SHARE/LEND implementation.
385 * @client: Client state.
386 * @total_length: Total length of shared memory descriptor.
387 * @fragment_length: Length of fragment of shared memory descriptor passed in
388 * this call.
389 * @address: Not supported, must be 0.
390 * @page_count: Not supported, must be 0.
391 * @smc_handle: Handle passed to smc call. Used to return
392 * FFA_MEM_FRAG_RX or SMC_FC_FFA_SUCCESS.
393 *
394 * Implements a subset of the FF-A FFA_MEM_SHARE and FFA_MEM_LEND calls needed
395 * to share or lend memory from non-secure os to secure os (with no stream
396 * endpoints).
397 *
398 * Return: 0 on success, error code on failure.
399 */
400long spmc_ffa_mem_send(uint32_t smc_fid,
401 bool secure_origin,
402 uint64_t total_length,
403 uint32_t fragment_length,
404 uint64_t address,
405 uint32_t page_count,
406 void *cookie,
407 void *handle,
408 uint64_t flags)
409
410{
411 long ret;
412 struct spmc_shmem_obj *obj;
413 struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
414 ffa_mtd_flag32_t mtd_flag;
415
416 if (address != 0U || page_count != 0U) {
417 WARN("%s: custom memory region for message not supported.\n",
418 __func__);
419 return spmc_ffa_error_return(handle,
420 FFA_ERROR_INVALID_PARAMETER);
421 }
422
423 if (secure_origin) {
424 WARN("%s: unsupported share direction.\n", __func__);
425 return spmc_ffa_error_return(handle,
426 FFA_ERROR_INVALID_PARAMETER);
427 }
428
429 if (fragment_length < sizeof(obj->desc)) {
430 WARN("%s: bad first fragment size %u < %zu\n",
431 __func__, fragment_length, sizeof(obj->desc));
432 return spmc_ffa_error_return(handle,
433 FFA_ERROR_INVALID_PARAMETER);
434 }
435
436 if ((smc_fid & FUNCID_NUM_MASK) == FFA_FNUM_MEM_SHARE) {
437 mtd_flag = FFA_MTD_FLAG_TYPE_SHARE_MEMORY;
438 } else if ((smc_fid & FUNCID_NUM_MASK) == FFA_FNUM_MEM_LEND) {
439 mtd_flag = FFA_MTD_FLAG_TYPE_LEND_MEMORY;
440 } else {
441 WARN("%s: invalid memory management operation.\n", __func__);
442 return spmc_ffa_error_return(handle,
443 FFA_ERROR_INVALID_PARAMETER);
444 }
445
446 spin_lock(&spmc_shmem_obj_state.lock);
447
448 obj = spmc_shmem_obj_alloc(&spmc_shmem_obj_state, total_length);
449 if (obj == NULL) {
450 ret = FFA_ERROR_NO_MEMORY;
451 goto err_unlock;
452 }
453
454 spin_lock(&mbox->lock);
455 ret = spmc_ffa_fill_desc(mbox, obj, fragment_length, mtd_flag, handle);
456 spin_unlock(&mbox->lock);
457
458 spin_unlock(&spmc_shmem_obj_state.lock);
459 return ret;
460
461err_unlock:
462 spin_unlock(&spmc_shmem_obj_state.lock);
463 return spmc_ffa_error_return(handle, ret);
464}
465
466/**
467 * spmc_ffa_mem_frag_tx - FFA_MEM_FRAG_TX implementation.
468 * @client: Client state.
469 * @handle_low: Handle_low value returned from FFA_MEM_FRAG_RX.
470 * @handle_high: Handle_high value returned from FFA_MEM_FRAG_RX.
471 * @fragment_length: Length of fragments transmitted.
472 * @sender_id: Vmid of sender in bits [31:16]
473 * @smc_handle: Handle passed to smc call. Used to return
474 * FFA_MEM_FRAG_RX or SMC_FC_FFA_SUCCESS.
475 *
476 * Return: @smc_handle on success, error code on failure.
477 */
478long spmc_ffa_mem_frag_tx(uint32_t smc_fid,
479 bool secure_origin,
480 uint64_t handle_low,
481 uint64_t handle_high,
482 uint32_t fragment_length,
483 uint32_t sender_id,
484 void *cookie,
485 void *handle,
486 uint64_t flags)
487{
488 long ret;
489 uint32_t desc_sender_id;
490 struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
491
492 struct spmc_shmem_obj *obj;
493 uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
494
495 spin_lock(&spmc_shmem_obj_state.lock);
496
497 obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
498 if (obj == NULL) {
499 WARN("%s: invalid handle, 0x%lx, not a valid handle.\n",
500 __func__, mem_handle);
501 ret = FFA_ERROR_INVALID_PARAMETER;
502 goto err_unlock;
503 }
504
505 desc_sender_id = (uint32_t)obj->desc.sender_id << 16;
506 if (sender_id != desc_sender_id) {
507 WARN("%s: invalid sender_id 0x%x != 0x%x\n", __func__,
508 sender_id, desc_sender_id);
509 ret = FFA_ERROR_INVALID_PARAMETER;
510 goto err_unlock;
511 }
512
513 if (obj->desc_filled == obj->desc_size) {
514 WARN("%s: object desc already filled, %zu\n", __func__,
515 obj->desc_filled);
516 ret = FFA_ERROR_INVALID_PARAMETER;
517 goto err_unlock;
518 }
519
520 spin_lock(&mbox->lock);
521 ret = spmc_ffa_fill_desc(mbox, obj, fragment_length, 0, handle);
522 spin_unlock(&mbox->lock);
523
524 spin_unlock(&spmc_shmem_obj_state.lock);
525 return ret;
526
527err_unlock:
528 spin_unlock(&spmc_shmem_obj_state.lock);
529 return spmc_ffa_error_return(handle, ret);
530}
531
532/**
533 * spmc_ffa_mem_retrieve_req - FFA_MEM_RETRIEVE_REQ implementation.
534 * @smc_fid: FID of SMC
535 * @total_length: Total length of retrieve request descriptor if this is
536 * the first call. Otherwise (unsupported) must be 0.
537 * @fragment_length: Length of fragment of retrieve request descriptor passed
538 * in this call. Only @fragment_length == @length is
539 * supported by this implementation.
540 * @address: Not supported, must be 0.
541 * @page_count: Not supported, must be 0.
542 * @smc_handle: Handle passed to smc call. Used to return
543 * FFA_MEM_RETRIEVE_RESP.
544 *
545 * Implements a subset of the FF-A FFA_MEM_RETRIEVE_REQ call.
546 * Used by secure os to retrieve memory already shared by non-secure os.
547 * If the data does not fit in a single FFA_MEM_RETRIEVE_RESP message,
548 * the client must call FFA_MEM_FRAG_RX until the full response has been
549 * received.
550 *
551 * Return: @handle on success, error code on failure.
552 */
553long
554spmc_ffa_mem_retrieve_req(uint32_t smc_fid,
555 bool secure_origin,
556 uint32_t total_length,
557 uint32_t fragment_length,
558 uint64_t address,
559 uint32_t page_count,
560 void *cookie,
561 void *handle,
562 uint64_t flags)
563{
564 int ret;
565 size_t buf_size;
566 size_t copy_size;
567 struct ffa_mtd_v1_0 *resp;
568 const struct ffa_mtd_v1_0 *req;
569 struct spmc_shmem_obj *obj = NULL;
570 struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
571
572 if (!secure_origin) {
573 WARN("%s: unsupported retrieve req direction.\n", __func__);
574 return spmc_ffa_error_return(handle,
575 FFA_ERROR_INVALID_PARAMETER);
576 }
577
578 if (address != 0U || page_count != 0U) {
579 WARN("%s: custom memory region not supported.\n", __func__);
580 return spmc_ffa_error_return(handle,
581 FFA_ERROR_INVALID_PARAMETER);
582 }
583
584 spin_lock(&mbox->lock);
585
586 req = mbox->tx_buffer;
587 resp = mbox->rx_buffer;
588 buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
589
590 if (mbox->rxtx_page_count == 0U) {
591 WARN("%s: buffer pair not registered.\n", __func__);
592 ret = FFA_ERROR_INVALID_PARAMETER;
593 goto err_unlock_mailbox;
594 }
595
596 if (mbox->state != MAILBOX_STATE_EMPTY) {
597 WARN("%s: RX Buffer is full! %d\n", __func__, mbox->state);
598 ret = FFA_ERROR_DENIED;
599 goto err_unlock_mailbox;
600 }
601
602 if (fragment_length != total_length) {
603 WARN("%s: fragmented retrieve request not supported.\n",
604 __func__);
605 ret = FFA_ERROR_INVALID_PARAMETER;
606 goto err_unlock_mailbox;
607 }
608
Marc Bonnici336630f2022-01-13 11:39:10 +0000609 if (req->emad_count == 0U) {
610 WARN("%s: unsupported attribute desc count %u.\n",
611 __func__, obj->desc.emad_count);
612 return -EINVAL;
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100613 }
614
615 if (total_length < sizeof(*req)) {
616 WARN("%s: invalid length %u < %zu\n", __func__, total_length,
617 sizeof(*req));
618 ret = FFA_ERROR_INVALID_PARAMETER;
619 goto err_unlock_mailbox;
620 }
621
622 spin_lock(&spmc_shmem_obj_state.lock);
623
624 obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
625 if (obj == NULL) {
626 ret = FFA_ERROR_INVALID_PARAMETER;
627 goto err_unlock_all;
628 }
629
630 if (obj->desc_filled != obj->desc_size) {
631 WARN("%s: incomplete object desc filled %zu < size %zu\n",
632 __func__, obj->desc_filled, obj->desc_size);
633 ret = FFA_ERROR_INVALID_PARAMETER;
634 goto err_unlock_all;
635 }
636
637 if (req->emad_count != 0U && req->sender_id != obj->desc.sender_id) {
638 WARN("%s: wrong sender id 0x%x != 0x%x\n",
639 __func__, req->sender_id, obj->desc.sender_id);
640 ret = FFA_ERROR_INVALID_PARAMETER;
641 goto err_unlock_all;
642 }
643
644 if (req->emad_count != 0U && req->tag != obj->desc.tag) {
645 WARN("%s: wrong tag 0x%lx != 0x%lx\n",
646 __func__, req->tag, obj->desc.tag);
647 ret = FFA_ERROR_INVALID_PARAMETER;
648 goto err_unlock_all;
649 }
650
Marc Bonnici336630f2022-01-13 11:39:10 +0000651 if (req->emad_count != 0U && req->emad_count != obj->desc.emad_count) {
652 WARN("%s: mistmatch of endpoint counts %u != %u\n",
653 __func__, req->emad_count, obj->desc.emad_count);
654 ret = FFA_ERROR_INVALID_PARAMETER;
655 goto err_unlock_all;
656 }
657
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100658 if (req->flags != 0U) {
659 if ((req->flags & FFA_MTD_FLAG_TYPE_MASK) !=
660 (obj->desc.flags & FFA_MTD_FLAG_TYPE_MASK)) {
661 /*
662 * If the retrieve request specifies the memory
663 * transaction ensure it matches what we expect.
664 */
665 WARN("%s: wrong mem transaction flags %x != %x\n",
666 __func__, req->flags, obj->desc.flags);
667 ret = FFA_ERROR_INVALID_PARAMETER;
668 goto err_unlock_all;
669 }
670
671 if (req->flags != FFA_MTD_FLAG_TYPE_SHARE_MEMORY &&
672 req->flags != FFA_MTD_FLAG_TYPE_LEND_MEMORY) {
673 /*
674 * Current implementation does not support donate and
675 * it supports no other flags.
676 */
677 WARN("%s: invalid flags 0x%x\n", __func__, req->flags);
678 ret = FFA_ERROR_INVALID_PARAMETER;
679 goto err_unlock_all;
680 }
681 }
682
Marc Bonnici336630f2022-01-13 11:39:10 +0000683 /*
684 * Ensure the emad array lies within the bounds of the descriptor by
685 * checking the address of the element past the end of the array.
686 */
687 if ((uintptr_t) &req->emad[req->emad_count] >
688 (uintptr_t)((uint8_t *) &req + total_length)) {
689 WARN("Invalid emad access.\n");
690 return -EINVAL;
691 }
692
693 /*
694 * Validate all the endpoints match in the case of multiple
695 * borrowers. We don't mandate that the order of the borrowers
696 * must match in the descriptors therefore check to see if the
697 * endpoints match in any order.
698 */
699 for (size_t i = 0; i < req->emad_count; i++) {
700 bool found = false;
701
702 for (size_t j = 0; j < obj->desc.emad_count; j++) {
703 if (req->emad[i].mapd.endpoint_id ==
704 obj->desc.emad[j].mapd.endpoint_id) {
705 found = true;
706 break;
707 }
708 }
709
710 if (!found) {
711 WARN("%s: invalid receiver id (0x%x).\n",
712 __func__, req->emad[i].mapd.endpoint_id);
713 ret = FFA_ERROR_INVALID_PARAMETER;
714 goto err_unlock_all;
715 }
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100716 }
717
718 mbox->state = MAILBOX_STATE_FULL;
719
720 if (req->emad_count != 0U) {
721 obj->in_use++;
722 }
723
724 copy_size = MIN(obj->desc_size, buf_size);
725
726 memcpy(resp, &obj->desc, copy_size);
727
728 spin_unlock(&spmc_shmem_obj_state.lock);
729 spin_unlock(&mbox->lock);
730
731 SMC_RET8(handle, FFA_MEM_RETRIEVE_RESP, obj->desc_size,
732 copy_size, 0, 0, 0, 0, 0);
733
734err_unlock_all:
735 spin_unlock(&spmc_shmem_obj_state.lock);
736err_unlock_mailbox:
737 spin_unlock(&mbox->lock);
738 return spmc_ffa_error_return(handle, ret);
739}
740
741/**
742 * spmc_ffa_mem_frag_rx - FFA_MEM_FRAG_RX implementation.
743 * @client: Client state.
744 * @handle_low: Handle passed to &FFA_MEM_RETRIEVE_REQ. Bit[31:0].
745 * @handle_high: Handle passed to &FFA_MEM_RETRIEVE_REQ. Bit[63:32].
746 * @fragment_offset: Byte offset in descriptor to resume at.
747 * @sender_id: Bit[31:16]: Endpoint id of sender if client is a
748 * hypervisor. 0 otherwise.
749 * @smc_handle: Handle passed to smc call. Used to return
750 * FFA_MEM_FRAG_TX.
751 *
752 * Return: @smc_handle on success, error code on failure.
753 */
754long spmc_ffa_mem_frag_rx(uint32_t smc_fid,
755 bool secure_origin,
756 uint32_t handle_low,
757 uint32_t handle_high,
758 uint32_t fragment_offset,
759 uint32_t sender_id,
760 void *cookie,
761 void *handle,
762 uint64_t flags)
763{
764 int ret;
765 void *src;
766 size_t buf_size;
767 size_t copy_size;
768 size_t full_copy_size;
769 uint32_t desc_sender_id;
770 struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
771 uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
772 struct spmc_shmem_obj *obj;
773
774 if (!secure_origin) {
775 WARN("%s: can only be called from swld.\n",
776 __func__);
777 return spmc_ffa_error_return(handle,
778 FFA_ERROR_INVALID_PARAMETER);
779 }
780
781 spin_lock(&spmc_shmem_obj_state.lock);
782
783 obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
784 if (obj == NULL) {
785 WARN("%s: invalid handle, 0x%lx, not a valid handle.\n",
786 __func__, mem_handle);
787 ret = FFA_ERROR_INVALID_PARAMETER;
788 goto err_unlock_shmem;
789 }
790
791 desc_sender_id = (uint32_t)obj->desc.sender_id << 16;
792 if (sender_id != 0U && sender_id != desc_sender_id) {
793 WARN("%s: invalid sender_id 0x%x != 0x%x\n", __func__,
794 sender_id, desc_sender_id);
795 ret = FFA_ERROR_INVALID_PARAMETER;
796 goto err_unlock_shmem;
797 }
798
799 if (fragment_offset >= obj->desc_size) {
800 WARN("%s: invalid fragment_offset 0x%x >= 0x%zx\n",
801 __func__, fragment_offset, obj->desc_size);
802 ret = FFA_ERROR_INVALID_PARAMETER;
803 goto err_unlock_shmem;
804 }
805
806 spin_lock(&mbox->lock);
807
808 if (mbox->rxtx_page_count == 0U) {
809 WARN("%s: buffer pair not registered.\n", __func__);
810 ret = FFA_ERROR_INVALID_PARAMETER;
811 goto err_unlock_all;
812 }
813
814 if (mbox->state != MAILBOX_STATE_EMPTY) {
815 WARN("%s: RX Buffer is full!\n", __func__);
816 ret = FFA_ERROR_DENIED;
817 goto err_unlock_all;
818 }
819
820 buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE;
821
822 mbox->state = MAILBOX_STATE_FULL;
823
824 full_copy_size = obj->desc_size - fragment_offset;
825 copy_size = MIN(full_copy_size, buf_size);
826
827 src = &obj->desc;
828
829 memcpy(mbox->rx_buffer, src + fragment_offset, copy_size);
830
831 spin_unlock(&mbox->lock);
832 spin_unlock(&spmc_shmem_obj_state.lock);
833
834 SMC_RET8(handle, FFA_MEM_FRAG_TX, handle_low, handle_high,
835 copy_size, sender_id, 0, 0, 0);
836
837err_unlock_all:
838 spin_unlock(&mbox->lock);
839err_unlock_shmem:
840 spin_unlock(&spmc_shmem_obj_state.lock);
841 return spmc_ffa_error_return(handle, ret);
842}
843
844/**
845 * spmc_ffa_mem_relinquish - FFA_MEM_RELINQUISH implementation.
846 * @client: Client state.
847 *
848 * Implements a subset of the FF-A FFA_MEM_RELINQUISH call.
849 * Used by secure os release previously shared memory to non-secure os.
850 *
851 * The handle to release must be in the client's (secure os's) transmit buffer.
852 *
853 * Return: 0 on success, error code on failure.
854 */
855int spmc_ffa_mem_relinquish(uint32_t smc_fid,
856 bool secure_origin,
857 uint32_t handle_low,
858 uint32_t handle_high,
859 uint32_t fragment_offset,
860 uint32_t sender_id,
861 void *cookie,
862 void *handle,
863 uint64_t flags)
864{
865 int ret;
866 struct mailbox *mbox = spmc_get_mbox_desc(secure_origin);
867 struct spmc_shmem_obj *obj;
868 const struct ffa_mem_relinquish_descriptor *req;
869
870 if (!secure_origin) {
871 WARN("%s: unsupported relinquish direction.\n", __func__);
872 return spmc_ffa_error_return(handle,
873 FFA_ERROR_INVALID_PARAMETER);
874 }
875
876 spin_lock(&mbox->lock);
877
878 if (mbox->rxtx_page_count == 0U) {
879 WARN("%s: buffer pair not registered.\n", __func__);
880 ret = FFA_ERROR_INVALID_PARAMETER;
881 goto err_unlock_mailbox;
882 }
883
884 req = mbox->tx_buffer;
885
886 if (req->flags != 0U) {
887 WARN("%s: unsupported flags 0x%x\n", __func__, req->flags);
888 ret = FFA_ERROR_INVALID_PARAMETER;
889 goto err_unlock_mailbox;
890 }
891
Marc Bonnici336630f2022-01-13 11:39:10 +0000892 if (req->endpoint_count == 0) {
893 WARN("%s: endpoint count cannot be 0.\n", __func__);
894 ret = FFA_ERROR_INVALID_PARAMETER;
895 goto err_unlock_mailbox;
896 }
897
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100898 spin_lock(&spmc_shmem_obj_state.lock);
899
900 obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, req->handle);
901 if (obj == NULL) {
902 ret = FFA_ERROR_INVALID_PARAMETER;
903 goto err_unlock_all;
904 }
905
906 if (obj->desc.emad_count != req->endpoint_count) {
Marc Bonnici336630f2022-01-13 11:39:10 +0000907 WARN("%s: mismatch of endpoint count %u != %u\n", __func__,
908 obj->desc.emad_count, req->endpoint_count);
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100909 ret = FFA_ERROR_INVALID_PARAMETER;
910 goto err_unlock_all;
911 }
Marc Bonnici336630f2022-01-13 11:39:10 +0000912
913 /* Validate requested endpoint IDs match descriptor. */
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100914 for (size_t i = 0; i < req->endpoint_count; i++) {
Marc Bonnici336630f2022-01-13 11:39:10 +0000915 bool found = false;
916
917 for (unsigned int j = 0; j < obj->desc.emad_count; j++) {
918 if (req->endpoint_array[i] ==
919 obj->desc.emad[j].mapd.endpoint_id) {
920 found = true;
921 break;
922 }
923 }
924
925 if (!found) {
926 WARN("%s: Invalid endpoint ID (0x%x).\n",
927 __func__, req->endpoint_array[i]);
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100928 ret = FFA_ERROR_INVALID_PARAMETER;
929 goto err_unlock_all;
930 }
931 }
Marc Bonnici336630f2022-01-13 11:39:10 +0000932
Marc Bonnici9f23c8d2021-10-01 16:06:04 +0100933 if (obj->in_use == 0U) {
934 ret = FFA_ERROR_INVALID_PARAMETER;
935 goto err_unlock_all;
936 }
937 obj->in_use--;
938
939 spin_unlock(&spmc_shmem_obj_state.lock);
940 spin_unlock(&mbox->lock);
941
942 SMC_RET1(handle, FFA_SUCCESS_SMC32);
943
944err_unlock_all:
945 spin_unlock(&spmc_shmem_obj_state.lock);
946err_unlock_mailbox:
947 spin_unlock(&mbox->lock);
948 return spmc_ffa_error_return(handle, ret);
949}
950
951/**
952 * spmc_ffa_mem_reclaim - FFA_MEM_RECLAIM implementation.
953 * @client: Client state.
954 * @handle_low: Unique handle of shared memory object to reclaim. Bit[31:0].
955 * @handle_high: Unique handle of shared memory object to reclaim.
956 * Bit[63:32].
957 * @flags: Unsupported, ignored.
958 *
959 * Implements a subset of the FF-A FFA_MEM_RECLAIM call.
960 * Used by non-secure os reclaim memory previously shared with secure os.
961 *
962 * Return: 0 on success, error code on failure.
963 */
964int spmc_ffa_mem_reclaim(uint32_t smc_fid,
965 bool secure_origin,
966 uint32_t handle_low,
967 uint32_t handle_high,
968 uint32_t mem_flags,
969 uint64_t x4,
970 void *cookie,
971 void *handle,
972 uint64_t flags)
973{
974 int ret;
975 struct spmc_shmem_obj *obj;
976 uint64_t mem_handle = handle_low | (((uint64_t)handle_high) << 32);
977
978 if (secure_origin) {
979 WARN("%s: unsupported reclaim direction.\n", __func__);
980 return spmc_ffa_error_return(handle,
981 FFA_ERROR_INVALID_PARAMETER);
982 }
983
984 if (mem_flags != 0U) {
985 WARN("%s: unsupported flags 0x%x\n", __func__, mem_flags);
986 return spmc_ffa_error_return(handle,
987 FFA_ERROR_INVALID_PARAMETER);
988 }
989
990 spin_lock(&spmc_shmem_obj_state.lock);
991
992 obj = spmc_shmem_obj_lookup(&spmc_shmem_obj_state, mem_handle);
993 if (obj == NULL) {
994 ret = FFA_ERROR_INVALID_PARAMETER;
995 goto err_unlock;
996 }
997 if (obj->in_use != 0U) {
998 ret = FFA_ERROR_DENIED;
999 goto err_unlock;
1000 }
1001 spmc_shmem_obj_free(&spmc_shmem_obj_state, obj);
1002 spin_unlock(&spmc_shmem_obj_state.lock);
1003
1004 SMC_RET1(handle, FFA_SUCCESS_SMC32);
1005
1006err_unlock:
1007 spin_unlock(&spmc_shmem_obj_state.lock);
1008 return spmc_ffa_error_return(handle, ret);
1009}