1 /*
2  * Copyright (c) 2019-2022, Arm Limited. All rights reserved.
3  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
4  * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5  * reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 #include <stdint.h>
12 #include "bitops.h"
13 #include "config_impl.h"
14 #include "config_spm.h"
15 #include "critical_section.h"
16 #include "psa/lifecycle.h"
17 #include "psa/service.h"
18 #include "interrupt.h"
19 #include "spm_ipc.h"
20 #include "tfm_arch.h"
21 #include "load/partition_defs.h"
22 #include "load/service_defs.h"
23 #include "load/interrupt_defs.h"
24 #include "ffm/psa_api.h"
25 #include "utilities.h"
26 #include "ffm/backend.h"
27 #include "ffm/psa_api.h"
28 #include "tfm_rpc.h"
29 #include "tfm_api.h"
30 #include "tfm_hal_interrupt.h"
31 #include "tfm_hal_platform.h"
32 #include "tfm_psa_call_pack.h"
33 #include "tfm_hal_isolation.h"
34 
35 #define GET_STATELESS_SERVICE(index)    (stateless_services_ref_tbl[index])
36 extern struct service_t *stateless_services_ref_tbl[];
37 
38 #if PSA_FRAMEWORK_HAS_MM_IOVEC
39 
40 /*
41  * The MM-IOVEC status
42  * The max total number of invec and outvec is 8.
43  * Each invec/outvec takes 4 bit, 32 bits in total.
44  *
45  * The encoding format of the MM-IOVEC status:
46  *--------------------------------------------------------------
47  *|  Bit   |  31 - 28  |  27 - 24  | ... |  7 - 4   |  3 - 0   |
48  *--------------------------------------------------------------
49  *| Vector | outvec[3] | outvec[2] | ... | invec[1] | invec[0] |
50  *--------------------------------------------------------------
51  *
52  * Take invec[0] as an example:
53  *
54  * bit 0:  whether invec[0] has been mapped.
55  * bit 1:  whether invec[0] has been unmapped.
56  * bit 2:  whether invec[0] has been accessed using psa_read(), psa_skip() or
57  *         psa_write().
58  * bit 3:  reserved for invec[0].
59  */
60 
61 #define IOVEC_STATUS_BITS              4   /* Each vector occupies 4 bits. */
62 #define OUTVEC_IDX_BASE                4   /*
63                                             * Base index of outvec.
64                                             * There are four invecs in front of
65                                             * outvec.
66                                             */
67 #define INVEC_IDX_BASE                 0   /* Base index of invec. */
68 
69 #define IOVEC_MAPPED_BIT               (1U << 0)
70 #define IOVEC_UNMAPPED_BIT             (1U << 1)
71 #define IOVEC_ACCESSED_BIT             (1U << 2)
72 
73 #define IOVEC_IS_MAPPED(handle, iovec_idx)      \
74     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
75                                IOVEC_MAPPED_BIT)
76 #define IOVEC_IS_UNMAPPED(handle, iovec_idx)    \
77     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
78                                IOVEC_UNMAPPED_BIT)
79 #define IOVEC_IS_ACCESSED(handle, iovec_idx)    \
80     ((((handle)->iovec_status) >> ((iovec_idx) * IOVEC_STATUS_BITS)) &  \
81                                IOVEC_ACCESSED_BIT)
82 #define SET_IOVEC_MAPPED(handle, iovec_idx)     \
83     (((handle)->iovec_status) |= (IOVEC_MAPPED_BIT <<   \
84                               ((iovec_idx) * IOVEC_STATUS_BITS)))
85 #define SET_IOVEC_UNMAPPED(handle, iovec_idx)   \
86     (((handle)->iovec_status) |= (IOVEC_UNMAPPED_BIT << \
87                               ((iovec_idx) * IOVEC_STATUS_BITS)))
88 #define SET_IOVEC_ACCESSED(handle, iovec_idx)   \
89     (((handle)->iovec_status) |= (IOVEC_ACCESSED_BIT << \
90                               ((iovec_idx) * IOVEC_STATUS_BITS)))
91 
92 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
93 
spm_handle_programmer_errors(psa_status_t status)94 void spm_handle_programmer_errors(psa_status_t status)
95 {
96     if (status == PSA_ERROR_PROGRAMMER_ERROR ||
97         status == PSA_ERROR_CONNECTION_REFUSED) {
98         if (!tfm_spm_is_ns_caller()) {
99             tfm_core_panic();
100         }
101     }
102 }
103 
tfm_spm_get_lifecycle_state(void)104 uint32_t tfm_spm_get_lifecycle_state(void)
105 {
106     /*
107      * FixMe: return PSA_LIFECYCLE_UNKNOWN to the caller directly. It will be
108      * implemented in the future.
109      */
110     return PSA_LIFECYCLE_UNKNOWN;
111 }
112 
113 /* PSA Client API function body */
114 
tfm_spm_client_psa_framework_version(void)115 uint32_t tfm_spm_client_psa_framework_version(void)
116 {
117     return PSA_FRAMEWORK_VERSION;
118 }
119 
tfm_spm_client_psa_version(uint32_t sid)120 uint32_t tfm_spm_client_psa_version(uint32_t sid)
121 {
122     struct service_t *service;
123     bool ns_caller = tfm_spm_is_ns_caller();
124 
125     /*
126      * It should return PSA_VERSION_NONE if the RoT Service is not
127      * implemented.
128      */
129     service = tfm_spm_get_service_by_sid(sid);
130     if (!service) {
131         return PSA_VERSION_NONE;
132     }
133 
134     /*
135      * It should return PSA_VERSION_NONE if the caller is not authorized
136      * to access the RoT Service.
137      */
138     if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
139         return PSA_VERSION_NONE;
140     }
141 
142     return service->p_ldinf->version;
143 }
144 
tfm_spm_client_psa_call(psa_handle_t handle,uint32_t ctrl_param,const psa_invec * inptr,psa_outvec * outptr)145 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
146                                      uint32_t ctrl_param,
147                                      const psa_invec *inptr,
148                                      psa_outvec *outptr)
149 {
150     psa_invec invecs[PSA_MAX_IOVEC];
151     psa_outvec outvecs[PSA_MAX_IOVEC];
152     struct conn_handle_t *conn_handle;
153     struct service_t *service;
154     int i, j;
155     int32_t client_id;
156     uint32_t sid, version, index;
157     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
158     bool ns_caller = tfm_spm_is_ns_caller();
159     struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
160     int32_t type = (int32_t)(int16_t)((ctrl_param & TYPE_MASK) >> TYPE_OFFSET);
161     size_t in_num = (size_t)((ctrl_param & IN_LEN_MASK) >> IN_LEN_OFFSET);
162     size_t out_num = (size_t)((ctrl_param & OUT_LEN_MASK) >> OUT_LEN_OFFSET);
163     fih_int fih_rc = FIH_FAILURE;
164 
165     /* The request type must be zero or positive. */
166     if (type < 0) {
167         return PSA_ERROR_PROGRAMMER_ERROR;
168     }
169 
170     /* It is a PROGRAMMER ERROR if in_len + out_len > PSA_MAX_IOVEC. */
171     if ((in_num > SIZE_MAX - out_num) ||
172         (in_num + out_num > PSA_MAX_IOVEC)) {
173         return PSA_ERROR_PROGRAMMER_ERROR;
174     }
175 
176     /* It is a PROGRAMMER ERROR if the handle is a null handle. */
177     if (handle == PSA_NULL_HANDLE) {
178         return PSA_ERROR_PROGRAMMER_ERROR;
179     }
180 
181     client_id = tfm_spm_get_client_id(ns_caller);
182 
183     /* Allocate space from handle pool for static handle. */
184     if (IS_STATIC_HANDLE(handle)) {
185         index = GET_INDEX_FROM_STATIC_HANDLE(handle);
186 
187         if (!IS_VALID_STATIC_HANDLE_IDX(index)) {
188             return PSA_ERROR_PROGRAMMER_ERROR;
189         }
190 
191         service = GET_STATELESS_SERVICE(index);
192         if (!service) {
193             return PSA_ERROR_PROGRAMMER_ERROR;
194         }
195 
196         sid = service->p_ldinf->sid;
197 
198         /*
199          * It is a PROGRAMMER ERROR if the caller is not authorized to access
200          * the RoT Service.
201          */
202         if (tfm_spm_check_authorization(sid, service, ns_caller)
203             != PSA_SUCCESS) {
204             return PSA_ERROR_CONNECTION_REFUSED;
205         }
206 
207         version = GET_VERSION_FROM_STATIC_HANDLE(handle);
208 
209         if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
210             return PSA_ERROR_PROGRAMMER_ERROR;
211         }
212 
213         CRITICAL_SECTION_ENTER(cs_assert);
214         conn_handle = tfm_spm_create_conn_handle();
215         CRITICAL_SECTION_LEAVE(cs_assert);
216 
217         if (!conn_handle) {
218             return PSA_ERROR_CONNECTION_BUSY;
219         }
220 
221         conn_handle->rhandle = NULL;
222         handle = tfm_spm_to_user_handle(conn_handle);
223     } else {
224 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
225         /* It is a PROGRAMMER ERROR if an invalid handle was passed. */
226         conn_handle = spm_get_handle_by_client_handle(handle, client_id);
227         if (!conn_handle) {
228             return PSA_ERROR_PROGRAMMER_ERROR;
229         }
230 
231         /*
232          * It is a PROGRAMMER ERROR if the connection is currently
233          * handling a request.
234          */
235         if (conn_handle->status != TFM_HANDLE_STATUS_IDLE) {
236             return PSA_ERROR_PROGRAMMER_ERROR;
237         }
238 
239         service = conn_handle->service;
240 
241         if (!service) {
242             /* FixMe: Need to implement a mechanism to resolve this failure. */
243             return PSA_ERROR_PROGRAMMER_ERROR;
244         }
245 #else
246         return PSA_ERROR_PROGRAMMER_ERROR;
247 #endif
248     }
249 
250     /*
251      * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
252      * if the memory reference for the wrap input vector is invalid or not
253      * readable.
254      */
255     FIH_CALL(tfm_hal_memory_check, fih_rc,
256              curr_partition->boundary, (uintptr_t)inptr,
257              in_num * sizeof(psa_invec), TFM_HAL_ACCESS_READABLE);
258     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
259         return PSA_ERROR_PROGRAMMER_ERROR;
260     }
261 
262     /*
263      * Read client outvecs from the wrap output vector and will update the
264      * actual length later. It is a PROGRAMMER ERROR if the memory reference for
265      * the wrap output vector is invalid or not read-write.
266      */
267     FIH_CALL(tfm_hal_memory_check, fih_rc,
268              curr_partition->boundary, (uintptr_t)outptr,
269              out_num * sizeof(psa_outvec), TFM_HAL_ACCESS_READWRITE);
270     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
271         return PSA_ERROR_PROGRAMMER_ERROR;
272     }
273 
274     spm_memset(invecs, 0, sizeof(invecs));
275     spm_memset(outvecs, 0, sizeof(outvecs));
276 
277     /* Copy the address out to avoid TOCTOU attacks. */
278     spm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
279     spm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));
280 
281     /*
282      * For client input vector, it is a PROGRAMMER ERROR if the provided payload
283      * memory reference was invalid or not readable.
284      */
285     for (i = 0; i < in_num; i++) {
286         FIH_CALL(tfm_hal_memory_check, fih_rc,
287                  curr_partition->boundary, (uintptr_t)invecs[i].base,
288                  invecs[i].len, TFM_HAL_ACCESS_READABLE);
289         if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
290             return PSA_ERROR_PROGRAMMER_ERROR;
291         }
292     }
293 
294     /*
295      * Clients must never overlap input parameters because of the risk of a
296      * double-fetch inconsistency.
297      * Overflow is checked in tfm_hal_memory_check functions.
298      */
299     for (i = 0; i + 1 < in_num; i++) {
300         for (j = i+1; j < in_num; j++) {
301             if (!((char *) invecs[j].base + invecs[j].len <=
302                   (char *) invecs[i].base ||
303                   (char *) invecs[j].base >=
304                   (char *) invecs[i].base + invecs[i].len)) {
305                 return PSA_ERROR_PROGRAMMER_ERROR;
306             }
307         }
308     }
309 
310     /*
311      * For client output vector, it is a PROGRAMMER ERROR if the provided
312      * payload memory reference was invalid or not read-write.
313      */
314     for (i = 0; i < out_num; i++) {
315         FIH_CALL(tfm_hal_memory_check, fih_rc,
316                  curr_partition->boundary, (uintptr_t)outvecs[i].base,
317                  outvecs[i].len, TFM_HAL_ACCESS_READWRITE);
318         if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
319             return PSA_ERROR_PROGRAMMER_ERROR;
320         }
321     }
322 
323     spm_fill_message(conn_handle, service, handle, type, client_id,
324                      invecs, in_num, outvecs, out_num, outptr);
325 
326     return backend_messaging(service, conn_handle);
327 }
328 
329 /* Following PSA APIs are only needed by connection-based services */
330 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
331 
tfm_spm_client_psa_connect(uint32_t sid,uint32_t version)332 psa_status_t tfm_spm_client_psa_connect(uint32_t sid, uint32_t version)
333 {
334     struct service_t *service;
335     struct conn_handle_t *conn_handle;
336     int32_t client_id;
337     psa_handle_t handle;
338     bool ns_caller = tfm_spm_is_ns_caller();
339     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
340 
341     /*
342      * It is a PROGRAMMER ERROR if the RoT Service does not exist on the
343      * platform.
344      */
345     service = tfm_spm_get_service_by_sid(sid);
346     if (!service) {
347         return PSA_ERROR_CONNECTION_REFUSED;
348     }
349 
350     /* It is a PROGRAMMER ERROR if connecting to a stateless service. */
351     if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
352         return PSA_ERROR_PROGRAMMER_ERROR;
353     }
354 
355     /*
356      * It is a PROGRAMMER ERROR if the caller is not authorized to access the
357      * RoT Service.
358      */
359     if (tfm_spm_check_authorization(sid, service, ns_caller) != PSA_SUCCESS) {
360         return PSA_ERROR_CONNECTION_REFUSED;
361     }
362 
363     /*
364      * It is a PROGRAMMER ERROR if the version of the RoT Service requested is
365      * not supported on the platform.
366      */
367     if (tfm_spm_check_client_version(service, version) != PSA_SUCCESS) {
368         return PSA_ERROR_CONNECTION_REFUSED;
369     }
370 
371     client_id = tfm_spm_get_client_id(ns_caller);
372 
373     /*
374      * Create connection handle here since it is possible to return the error
375      * code to client when creation fails.
376      */
377     CRITICAL_SECTION_ENTER(cs_assert);
378     conn_handle = tfm_spm_create_conn_handle();
379     CRITICAL_SECTION_LEAVE(cs_assert);
380     if (!conn_handle) {
381         return PSA_ERROR_CONNECTION_BUSY;
382     }
383 
384     handle = tfm_spm_to_user_handle(conn_handle);
385     /* No input or output needed for connect message */
386     spm_fill_message(conn_handle, service, handle, PSA_IPC_CONNECT,
387                      client_id, NULL, 0, NULL, 0, NULL);
388 
389     return backend_messaging(service, conn_handle);
390 }
391 
tfm_spm_client_psa_close(psa_handle_t handle)392 psa_status_t tfm_spm_client_psa_close(psa_handle_t handle)
393 {
394     struct service_t *service;
395     struct conn_handle_t *conn_handle;
396     int32_t client_id;
397     bool ns_caller = tfm_spm_is_ns_caller();
398 
399     /* It will have no effect if called with the NULL handle */
400     if (handle == PSA_NULL_HANDLE) {
401         return PSA_SUCCESS;
402     }
403 
404     /* It is a PROGRAMMER ERROR if called with a stateless handle. */
405     if (IS_STATIC_HANDLE(handle)) {
406         return PSA_ERROR_PROGRAMMER_ERROR;
407     }
408 
409     client_id = tfm_spm_get_client_id(ns_caller);
410 
411     /*
412      * It is a PROGRAMMER ERROR if an invalid handle was provided that is not
413      * the null handle.
414      */
415     conn_handle = spm_get_handle_by_client_handle(handle, client_id);
416     if (!conn_handle) {
417         return PSA_ERROR_PROGRAMMER_ERROR;
418     }
419 
420     service = conn_handle->service;
421     if (!service) {
422         /* FixMe: Need to implement one mechanism to resolve this failure. */
423         return PSA_ERROR_PROGRAMMER_ERROR;
424     }
425 
426     /*
427      * It is a PROGRAMMER ERROR if the connection is currently handling a
428      * request.
429      */
430     if (conn_handle->status == TFM_HANDLE_STATUS_ACTIVE) {
431         return PSA_ERROR_PROGRAMMER_ERROR;
432     }
433 
434     /* No input or output needed for close message */
435     spm_fill_message(conn_handle, service, handle, PSA_IPC_DISCONNECT,
436                      client_id, NULL, 0, NULL, 0, NULL);
437 
438     return backend_messaging(service, conn_handle);
439 }
440 
441 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
442 
443 /* PSA Partition API function body */
444 
445 #if CONFIG_TFM_SPM_BACKEND_IPC == 1 \
446     || CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1
tfm_spm_partition_psa_wait(psa_signal_t signal_mask,uint32_t timeout)447 psa_signal_t tfm_spm_partition_psa_wait(psa_signal_t signal_mask,
448                                         uint32_t timeout)
449 {
450     struct partition_t *partition = NULL;
451 
452     /*
453      * Timeout[30:0] are reserved for future use.
454      * SPM must ignore the value of RES.
455      */
456     timeout &= PSA_TIMEOUT_MASK;
457 
458     partition = GET_CURRENT_COMPONENT();
459 
460     /*
461      * signals_allowed can be 0 for TF-M internal partitions for special usages.
462      * Regular Secure Partitions should have at least one signal.
463      * This is gauranteed by the manifest tool.
464      * It is a PROGRAMMER ERROR if the signal_mask does not include any assigned
465      * signals.
466      */
467     if ((partition->signals_allowed) &&
468         (partition->signals_allowed & signal_mask) == 0) {
469         tfm_core_panic();
470     }
471 
472     /*
473      * backend_wake_up() blocks the caller thread if no signals are
474      * available. In this case, the return value of this function is temporary
475      * set into runtime context. After new signal(s) are available, the return
476      * value is updated with the available signal(s) and blocked thread gets
477      * to run.
478      */
479     if (timeout == PSA_BLOCK) {
480         return backend_wait(partition, signal_mask);
481     }
482 
483     return partition->signals_asserted & signal_mask;
484 }
485 #endif
486 
487 #if CONFIG_TFM_SPM_BACKEND_IPC == 1
tfm_spm_partition_psa_get(psa_signal_t signal,psa_msg_t * msg)488 psa_status_t tfm_spm_partition_psa_get(psa_signal_t signal, psa_msg_t *msg)
489 {
490     struct conn_handle_t *handle = NULL;
491     struct partition_t *partition = NULL;
492     fih_int fih_rc = FIH_FAILURE;
493 
494     /*
495      * Only one message could be retrieved every time for psa_get(). It is a
496      * fatal error if the input signal has more than a signal bit set.
497      */
498     if (!IS_ONLY_ONE_BIT_IN_UINT32(signal)) {
499         tfm_core_panic();
500     }
501 
502     partition = GET_CURRENT_COMPONENT();
503 
504     /*
505      * Write the message to the service buffer. It is a fatal error if the
506      * input msg pointer is not a valid memory reference or not read-write.
507      */
508     FIH_CALL(tfm_hal_memory_check, fih_rc,
509              partition->boundary, (uintptr_t)msg,
510              sizeof(psa_msg_t), TFM_HAL_ACCESS_READWRITE);
511     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
512         tfm_core_panic();
513     }
514 
515     /*
516      * It is a fatal error if the caller call psa_get() when no message has
517      * been set. The caller must call this function after an RoT Service signal
518      * is returned by psa_wait().
519      */
520     if (partition->signals_asserted == 0) {
521         tfm_core_panic();
522     }
523 
524     /*
525      * It is a fatal error if the RoT Service signal is not currently asserted.
526      */
527     if ((partition->signals_asserted & signal) == 0) {
528         tfm_core_panic();
529     }
530 
531     /*
532      * Get message by signal from partition. It is a fatal error if getting
533      * failed, which means the input signal is not correspond to an RoT service.
534      */
535     handle = spm_get_handle_by_signal(partition, signal);
536     if (!handle) {
537         return PSA_ERROR_DOES_NOT_EXIST;
538     }
539 
540     spm_memcpy(msg, &handle->msg, sizeof(psa_msg_t));
541 
542     return PSA_SUCCESS;
543 }
544 #endif
545 
tfm_spm_partition_psa_read(psa_handle_t msg_handle,uint32_t invec_idx,void * buffer,size_t num_bytes)546 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
547                                   void *buffer, size_t num_bytes)
548 {
549     size_t bytes;
550     struct conn_handle_t *handle = NULL;
551     struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
552     fih_int fih_rc = FIH_FAILURE;
553 
554     /* It is a fatal error if message handle is invalid */
555     handle = spm_get_handle_by_msg_handle(msg_handle);
556     if (!handle) {
557         tfm_core_panic();
558     }
559 
560     /*
561      * It is a fatal error if message handle does not refer to a request
562      * message
563      */
564     if (handle->msg.type < PSA_IPC_CALL) {
565         tfm_core_panic();
566     }
567 
568     /*
569      * It is a fatal error if invec_idx is equal to or greater than
570      * PSA_MAX_IOVEC
571      */
572     if (invec_idx >= PSA_MAX_IOVEC) {
573         tfm_core_panic();
574     }
575 
576 #if PSA_FRAMEWORK_HAS_MM_IOVEC
577     /*
578      * It is a fatal error if the input vector has already been mapped using
579      * psa_map_invec().
580      */
581     if (IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
582         tfm_core_panic();
583     }
584 
585     SET_IOVEC_ACCESSED(handle, (invec_idx + INVEC_IDX_BASE));
586 #endif
587 
588     /* There was no remaining data in this input vector */
589     if (handle->msg.in_size[invec_idx] == 0) {
590         return 0;
591     }
592 
593     /*
594      * Copy the client data to the service buffer. It is a fatal error
595      * if the memory reference for buffer is invalid or not read-write.
596      */
597     FIH_CALL(tfm_hal_memory_check, fih_rc,
598              curr_partition->boundary, (uintptr_t)buffer,
599              num_bytes, TFM_HAL_ACCESS_READWRITE);
600     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
601         tfm_core_panic();
602     }
603 
604     bytes = num_bytes > handle->msg.in_size[invec_idx] ?
605                         handle->msg.in_size[invec_idx] : num_bytes;
606 
607     spm_memcpy(buffer, handle->invec[invec_idx].base, bytes);
608 
609     /* There maybe some remaining data */
610     handle->invec[invec_idx].base =
611                                 (char *)handle->invec[invec_idx].base + bytes;
612     handle->msg.in_size[invec_idx] -= bytes;
613 
614     return bytes;
615 }
616 
tfm_spm_partition_psa_skip(psa_handle_t msg_handle,uint32_t invec_idx,size_t num_bytes)617 size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
618                                   size_t num_bytes)
619 {
620     struct conn_handle_t *handle = NULL;
621 
622     /* It is a fatal error if message handle is invalid */
623     handle = spm_get_handle_by_msg_handle(msg_handle);
624     if (!handle) {
625         tfm_core_panic();
626     }
627 
628     /*
629      * It is a fatal error if message handle does not refer to a request
630      * message
631      */
632     if (handle->msg.type < PSA_IPC_CALL) {
633         tfm_core_panic();
634     }
635 
636     /*
637      * It is a fatal error if invec_idx is equal to or greater than
638      * PSA_MAX_IOVEC
639      */
640     if (invec_idx >= PSA_MAX_IOVEC) {
641         tfm_core_panic();
642     }
643 
644 #if PSA_FRAMEWORK_HAS_MM_IOVEC
645     /*
646      * It is a fatal error if the input vector has already been mapped using
647      * psa_map_invec().
648      */
649     if (IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
650         tfm_core_panic();
651     }
652 
653     SET_IOVEC_ACCESSED(handle, (invec_idx + INVEC_IDX_BASE));
654 #endif
655 
656     /* There was no remaining data in this input vector */
657     if (handle->msg.in_size[invec_idx] == 0) {
658         return 0;
659     }
660 
661     /*
662      * If num_bytes is greater than the remaining size of the input vector then
663      * the remaining size of the input vector is used.
664      */
665     if (num_bytes > handle->msg.in_size[invec_idx]) {
666         num_bytes = handle->msg.in_size[invec_idx];
667     }
668 
669     /* There maybe some remaining data */
670     handle->invec[invec_idx].base =
671                             (char *)handle->invec[invec_idx].base + num_bytes;
672     handle->msg.in_size[invec_idx] -= num_bytes;
673 
674     return num_bytes;
675 }
676 
tfm_spm_partition_psa_write(psa_handle_t msg_handle,uint32_t outvec_idx,const void * buffer,size_t num_bytes)677 void tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
678                                  const void *buffer, size_t num_bytes)
679 {
680     struct conn_handle_t *handle = NULL;
681     struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
682     fih_int fih_rc = FIH_FAILURE;
683 
684     /* It is a fatal error if message handle is invalid */
685     handle = spm_get_handle_by_msg_handle(msg_handle);
686     if (!handle) {
687         tfm_core_panic();
688     }
689 
690     /*
691      * It is a fatal error if message handle does not refer to a request
692      * message
693      */
694     if (handle->msg.type < PSA_IPC_CALL) {
695         tfm_core_panic();
696     }
697 
698     /*
699      * It is a fatal error if outvec_idx is equal to or greater than
700      * PSA_MAX_IOVEC
701      */
702     if (outvec_idx >= PSA_MAX_IOVEC) {
703         tfm_core_panic();
704     }
705 
706     /*
707      * It is a fatal error if the call attempts to write data past the end of
708      * the client output vector
709      */
710     if (num_bytes > handle->msg.out_size[outvec_idx] -
711         handle->outvec[outvec_idx].len) {
712         tfm_core_panic();
713     }
714 
715 #if PSA_FRAMEWORK_HAS_MM_IOVEC
716     /*
717      * It is a fatal error if the output vector has already been mapped using
718      * psa_map_outvec().
719      */
720     if (IOVEC_IS_MAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
721         tfm_core_panic();
722     }
723 
724     SET_IOVEC_ACCESSED(handle, (outvec_idx + OUTVEC_IDX_BASE));
725 #endif
726 
727     /*
728      * Copy the service buffer to client outvecs. It is a fatal error
729      * if the memory reference for buffer is invalid or not readable.
730      */
731     FIH_CALL(tfm_hal_memory_check, fih_rc,
732              curr_partition->boundary, (uintptr_t)buffer,
733              num_bytes, TFM_HAL_ACCESS_READABLE);
734     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
735         tfm_core_panic();
736     }
737 
738     spm_memcpy((char *)handle->outvec[outvec_idx].base +
739                handle->outvec[outvec_idx].len, buffer, num_bytes);
740 
741     /* Update the write number */
742     handle->outvec[outvec_idx].len += num_bytes;
743 }
744 
tfm_spm_partition_psa_reply(psa_handle_t msg_handle,psa_status_t status)745 psa_status_t tfm_spm_partition_psa_reply(psa_handle_t msg_handle,
746                                          psa_status_t status)
747 {
748     struct service_t *service;
749     struct conn_handle_t *handle;
750     psa_status_t ret = PSA_SUCCESS;
751     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
752 
753     /* It is a fatal error if message handle is invalid */
754     handle = spm_get_handle_by_msg_handle(msg_handle);
755     if (!handle) {
756         tfm_core_panic();
757     }
758 
759     /*
760      * RoT Service information is needed in this function, stored it in message
761      * body structure. Only two parameters are passed in this function: handle
762      * and status, so it is useful and simply to do like this.
763      */
764     service = handle->service;
765     if (!service) {
766         tfm_core_panic();
767     }
768 
769     switch (handle->msg.type) {
770     case PSA_IPC_CONNECT:
771         /*
772          * Reply to PSA_IPC_CONNECT message. Connect handle is returned if the
773          * input status is PSA_SUCCESS. Others return values are based on the
774          * input status.
775          */
776         if (status == PSA_SUCCESS) {
777             ret = msg_handle;
778         } else if (status == PSA_ERROR_CONNECTION_REFUSED) {
779             /* Refuse the client connection, indicating a permanent error. */
780             ret = PSA_ERROR_CONNECTION_REFUSED;
781             handle->status = TFM_HANDLE_STATUS_TO_FREE;
782         } else if (status == PSA_ERROR_CONNECTION_BUSY) {
783             /* Fail the client connection, indicating a transient error. */
784             ret = PSA_ERROR_CONNECTION_BUSY;
785         } else {
786             tfm_core_panic();
787         }
788         break;
789     case PSA_IPC_DISCONNECT:
790         /* Service handle is not used anymore */
791         handle->status = TFM_HANDLE_STATUS_TO_FREE;
792 
793         /*
794          * If the message type is PSA_IPC_DISCONNECT, then the status code is
795          * ignored
796          */
797         break;
798     default:
799         if (handle->msg.type >= PSA_IPC_CALL) {
800 
801 #if PSA_FRAMEWORK_HAS_MM_IOVEC
802 
803             /*
804              * If the unmapped function is not called for an input/output vector
805              * that has been mapped, the framework will remove the mapping.
806              */
807             int i;
808 
809             for (i = 0; i < PSA_MAX_IOVEC * 2; i++) {
810                 if (IOVEC_IS_MAPPED(handle, i) &&
811                     (!IOVEC_IS_UNMAPPED(handle, i))) {
812                     SET_IOVEC_UNMAPPED(handle, i);
813                     /*
814                      * Any output vectors that are still mapped will report that
815                      * zero bytes have been written.
816                      */
817                     if (i >= OUTVEC_IDX_BASE) {
818                         handle->outvec[i - OUTVEC_IDX_BASE].len = 0;
819                     }
820                 }
821             }
822 
823 #endif
824             /* Reply to a request message. Return values are based on status */
825             ret = status;
826             /*
827              * The total number of bytes written to a single parameter must be
828              * reported to the client by updating the len member of the
829              * psa_outvec structure for the parameter before returning from
830              * psa_call().
831              */
832             update_caller_outvec_len(handle);
833             if (SERVICE_IS_STATELESS(service->p_ldinf->flags)) {
834                 handle->status = TFM_HANDLE_STATUS_TO_FREE;
835             }
836         } else {
837             tfm_core_panic();
838         }
839     }
840 
841     if (ret == PSA_ERROR_PROGRAMMER_ERROR) {
842         /*
843          * If the source of the programmer error is a Secure Partition, the SPM
844          * must panic the Secure Partition in response to a PROGRAMMER ERROR.
845          */
846         if (!TFM_CLIENT_ID_IS_NS(handle->msg.client_id)) {
847             tfm_core_panic();
848         }
849     }
850 
851     /*
852      * TODO: It can be optimized further by moving critical section protection
853      * to mailbox. Also need to check implementation when secure context is
854      * involved.
855      */
856     CRITICAL_SECTION_ENTER(cs_assert);
857     ret = backend_replying(handle, ret);
858     CRITICAL_SECTION_LEAVE(cs_assert);
859 
860     if (handle->status == TFM_HANDLE_STATUS_TO_FREE) {
861         tfm_spm_free_conn_handle(handle);
862     } else {
863         handle->status = TFM_HANDLE_STATUS_IDLE;
864     }
865 
866     return ret;
867 }
868 
869 #if CONFIG_TFM_DOORBELL_API == 1
tfm_spm_partition_psa_notify(int32_t partition_id)870 void tfm_spm_partition_psa_notify(int32_t partition_id)
871 {
872     struct partition_t *p_pt = tfm_spm_get_partition_by_id(partition_id);
873 
874     spm_assert_signal(p_pt, PSA_DOORBELL);
875 }
876 
tfm_spm_partition_psa_clear(void)877 void tfm_spm_partition_psa_clear(void)
878 {
879     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
880     struct partition_t *partition = NULL;
881 
882     partition = GET_CURRENT_COMPONENT();
883 
884     /*
885      * It is a fatal error if the Secure Partition's doorbell signal is not
886      * currently asserted.
887      */
888     if ((partition->signals_asserted & PSA_DOORBELL) == 0) {
889         tfm_core_panic();
890     }
891 
892     CRITICAL_SECTION_ENTER(cs_assert);
893     partition->signals_asserted &= ~PSA_DOORBELL;
894     CRITICAL_SECTION_LEAVE(cs_assert);
895 }
896 #endif /* CONFIG_TFM_DOORBELL_API == 1 */
897 
tfm_spm_partition_psa_panic(void)898 void tfm_spm_partition_psa_panic(void)
899 {
900 #ifdef CONFIG_TFM_HALT_ON_CORE_PANIC
901     tfm_hal_system_halt();
902 #else
903     /*
904      * PSA FF recommends that the SPM causes the system to restart when a secure
905      * partition panics.
906      */
907     tfm_hal_system_reset();
908 #endif
909 }
910 
911 /* psa_set_rhandle is only needed by connection-based services */
912 #if CONFIG_TFM_CONNECTION_BASED_SERVICE_API == 1
913 
tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle,void * rhandle)914 void tfm_spm_partition_psa_set_rhandle(psa_handle_t msg_handle, void *rhandle)
915 {
916     struct conn_handle_t *handle;
917 
918     /* It is a fatal error if message handle is invalid */
919     handle = spm_get_handle_by_msg_handle(msg_handle);
920     if (!handle) {
921         tfm_core_panic();
922     }
923 
924     /* It is a PROGRAMMER ERROR if a stateless service sets rhandle. */
925     if (SERVICE_IS_STATELESS(handle->service->p_ldinf->flags)) {
926         tfm_core_panic();
927     }
928 
929     handle->msg.rhandle = rhandle;
930     handle->rhandle = rhandle;
931 }
932 
933 #endif /* CONFIG_TFM_CONNECTION_BASED_SERVICE_API */
934 
935 #if CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1
tfm_spm_partition_psa_irq_enable(psa_signal_t irq_signal)936 void tfm_spm_partition_psa_irq_enable(psa_signal_t irq_signal)
937 {
938     struct partition_t *partition;
939     const struct irq_load_info_t *irq_info;
940 
941     partition = GET_CURRENT_COMPONENT();
942 
943     irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
944     if (!irq_info) {
945         tfm_core_panic();
946     }
947 
948     tfm_hal_irq_enable(irq_info->source);
949 }
950 
tfm_spm_partition_psa_irq_disable(psa_signal_t irq_signal)951 psa_irq_status_t tfm_spm_partition_psa_irq_disable(psa_signal_t irq_signal)
952 {
953     struct partition_t *partition;
954     const struct irq_load_info_t *irq_info;
955 
956     partition = GET_CURRENT_COMPONENT();
957 
958     irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
959     if (!irq_info) {
960         tfm_core_panic();
961     }
962 
963     tfm_hal_irq_disable(irq_info->source);
964 
965     return 1;
966 }
967 
968 /* This API is only used for FLIH. */
969 #if CONFIG_TFM_FLIH_API == 1
tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)970 void tfm_spm_partition_psa_reset_signal(psa_signal_t irq_signal)
971 {
972     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
973     const struct irq_load_info_t *irq_info;
974     struct partition_t *partition;
975 
976     partition = GET_CURRENT_COMPONENT();
977 
978     irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
979     if (!irq_info) {
980         tfm_core_panic();
981     }
982 
983     if (!irq_info->flih_func) {
984         /* This API is for FLIH IRQs only */
985         tfm_core_panic();
986     }
987 
988     if ((partition->signals_asserted & irq_signal) == 0) {
989         /* The signal is not asserted */
990         tfm_core_panic();
991     }
992 
993     CRITICAL_SECTION_ENTER(cs_assert);
994     partition->signals_asserted &= ~irq_signal;
995     CRITICAL_SECTION_LEAVE(cs_assert);
996 }
997 #endif
998 
999 /* This API is only used for SLIH. */
1000 #if CONFIG_TFM_SLIH_API == 1
tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)1001 void tfm_spm_partition_psa_eoi(psa_signal_t irq_signal)
1002 {
1003     struct critical_section_t cs_assert = CRITICAL_SECTION_STATIC_INIT;
1004     const struct irq_load_info_t *irq_info = NULL;
1005     struct partition_t *partition = NULL;
1006 
1007     partition = GET_CURRENT_COMPONENT();
1008 
1009     irq_info = get_irq_info_for_signal(partition->p_ldinf, irq_signal);
1010     /* It is a fatal error if passed signal is not an interrupt signal. */
1011     if (!irq_info) {
1012         tfm_core_panic();
1013     }
1014 
1015     if (irq_info->flih_func) {
1016         /* This API is for SLIH IRQs only */
1017         tfm_core_panic();
1018     }
1019 
1020     /* It is a fatal error if passed signal is not currently asserted */
1021     if ((partition->signals_asserted & irq_signal) == 0) {
1022         tfm_core_panic();
1023     }
1024 
1025     CRITICAL_SECTION_ENTER(cs_assert);
1026     partition->signals_asserted &= ~irq_signal;
1027     CRITICAL_SECTION_LEAVE(cs_assert);
1028 
1029     tfm_hal_irq_clear_pending(irq_info->source);
1030     tfm_hal_irq_enable(irq_info->source);
1031 }
1032 #endif
1033 #endif /* CONFIG_TFM_FLIH_API == 1 || CONFIG_TFM_SLIH_API == 1 */
1034 
1035 #if PSA_FRAMEWORK_HAS_MM_IOVEC
1036 
tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle,uint32_t invec_idx)1037 const void *tfm_spm_partition_psa_map_invec(psa_handle_t msg_handle,
1038                                             uint32_t invec_idx)
1039 {
1040     struct conn_handle_t *handle;
1041     struct partition_t *partition = NULL;
1042     fih_int fih_rc = FIH_FAILURE;
1043 
1044     /* It is a fatal error if message handle is invalid */
1045     handle = spm_get_handle_by_msg_handle(msg_handle);
1046     if (!handle) {
1047         tfm_core_panic();
1048     }
1049 
1050     partition = handle->service->partition;
1051 
1052     /*
1053      * It is a fatal error if MM-IOVEC has not been enabled for the RoT
1054      * Service that received the message.
1055      */
1056     if (!SERVICE_ENABLED_MM_IOVEC(handle->service->p_ldinf->flags)) {
1057         tfm_core_panic();
1058     }
1059 
1060     /*
1061      * It is a fatal error if message handle does not refer to a request
1062      * message.
1063      */
1064     if (handle->msg.type < PSA_IPC_CALL) {
1065         tfm_core_panic();
1066     }
1067 
1068     /*
1069      * It is a fatal error if invec_idx is equal to or greater than
1070      * PSA_MAX_IOVEC.
1071      */
1072     if (invec_idx >= PSA_MAX_IOVEC) {
1073         tfm_core_panic();
1074     }
1075 
1076     /* It is a fatal error if the input vector has length zero. */
1077     if (handle->msg.in_size[invec_idx] == 0) {
1078         tfm_core_panic();
1079     }
1080 
1081     /*
1082      * It is a fatal error if the input vector has already been mapped using
1083      * psa_map_invec().
1084      */
1085     if (IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
1086         tfm_core_panic();
1087     }
1088 
1089     /*
1090      * It is a fatal error if the input vector has already been accessed
1091      * using psa_read() or psa_skip().
1092      */
1093     if (IOVEC_IS_ACCESSED(handle, (invec_idx + INVEC_IDX_BASE))) {
1094         tfm_core_panic();
1095     }
1096 
1097     /*
1098      * It is a fatal error if the memory reference for the wrap input vector is
1099      * invalid or not readable.
1100      */
1101     FIH_CALL(tfm_hal_memory_check, fih_rc,
1102              partition->boundary, (uintptr_t)handle->invec[invec_idx].base,
1103              handle->invec[invec_idx].len, TFM_HAL_ACCESS_READABLE);
1104     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
1105         tfm_core_panic();
1106     }
1107 
1108     SET_IOVEC_MAPPED(handle, (invec_idx + INVEC_IDX_BASE));
1109 
1110     return handle->invec[invec_idx].base;
1111 }
1112 
tfm_spm_partition_psa_unmap_invec(psa_handle_t msg_handle,uint32_t invec_idx)1113 void tfm_spm_partition_psa_unmap_invec(psa_handle_t msg_handle,
1114                                        uint32_t invec_idx)
1115 {
1116     struct conn_handle_t *handle;
1117 
1118     /* It is a fatal error if message handle is invalid */
1119     handle = spm_get_handle_by_msg_handle(msg_handle);
1120     if (!handle) {
1121         tfm_core_panic();
1122     }
1123 
1124     /*
1125      * It is a fatal error if MM-IOVEC has not been enabled for the RoT
1126      * Service that received the message.
1127      */
1128     if (!SERVICE_ENABLED_MM_IOVEC(handle->service->p_ldinf->flags)) {
1129         tfm_core_panic();
1130     }
1131 
1132     /*
1133      * It is a fatal error if message handle does not refer to a request
1134      * message.
1135      */
1136     if (handle->msg.type < PSA_IPC_CALL) {
1137         tfm_core_panic();
1138     }
1139 
1140     /*
1141      * It is a fatal error if invec_idx is equal to or greater than
1142      * PSA_MAX_IOVEC.
1143      */
1144     if (invec_idx >= PSA_MAX_IOVEC) {
1145         tfm_core_panic();
1146     }
1147 
1148     /*
1149      * It is a fatal error if The input vector has not been mapped by a call to
1150      * psa_map_invec().
1151      */
1152     if (!IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
1153         tfm_core_panic();
1154     }
1155 
1156     /*
1157      * It is a fatal error if the input vector has already been unmapped by a
1158      * call to psa_unmap_invec().
1159      */
1160     if (IOVEC_IS_UNMAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
1161         tfm_core_panic();
1162     }
1163 
1164     SET_IOVEC_UNMAPPED(handle, (invec_idx + INVEC_IDX_BASE));
1165 }
1166 
tfm_spm_partition_psa_map_outvec(psa_handle_t msg_handle,uint32_t outvec_idx)1167 void *tfm_spm_partition_psa_map_outvec(psa_handle_t msg_handle,
1168                                        uint32_t outvec_idx)
1169 {
1170     struct conn_handle_t *handle;
1171     uint32_t privileged;
1172     struct partition_t *partition = NULL;
1173     fih_int fih_rc = FIH_FAILURE;
1174 
1175     /* It is a fatal error if message handle is invalid */
1176     handle = spm_get_handle_by_msg_handle(msg_handle);
1177     if (!handle) {
1178         tfm_core_panic();
1179     }
1180 
1181     partition = handle->service->partition;
1182     privileged = GET_PARTITION_PRIVILEGED_MODE(partition->p_ldinf);
1183 
1184     /*
1185      * It is a fatal error if MM-IOVEC has not been enabled for the RoT
1186      * Service that received the message.
1187      */
1188     if (!SERVICE_ENABLED_MM_IOVEC(handle->service->p_ldinf->flags)) {
1189         tfm_core_panic();
1190     }
1191 
1192     /*
1193      * It is a fatal error if message handle does not refer to a request
1194      * message.
1195      */
1196     if (handle->msg.type < PSA_IPC_CALL) {
1197         tfm_core_panic();
1198     }
1199 
1200     /*
1201      * It is a fatal error if outvec_idx is equal to or greater than
1202      * PSA_MAX_IOVEC.
1203      */
1204     if (outvec_idx >= PSA_MAX_IOVEC) {
1205         tfm_core_panic();
1206     }
1207 
1208     /* It is a fatal error if the output vector has length zero. */
1209     if (handle->msg.out_size[outvec_idx] == 0) {
1210         tfm_core_panic();
1211     }
1212 
1213     /*
1214      * It is a fatal error if the output vector has already been mapped using
1215      * psa_map_outvec().
1216      */
1217     if (IOVEC_IS_MAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
1218         tfm_core_panic();
1219     }
1220 
1221     /*
1222      * It is a fatal error if the output vector has already been accessed
1223      * using psa_write().
1224      */
1225     if (IOVEC_IS_ACCESSED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
1226         tfm_core_panic();
1227     }
1228 
1229     /*
1230      * It is a fatal error if the output vector is invalid or not read-write.
1231      */
1232     FIH_CALL(tfm_hal_memory_check, fih_rc,
1233              partition->boundary, (uintptr_t)handle->outvec[outvec_idx].base,
1234              handle->outvec[outvec_idx].len, TFM_HAL_ACCESS_READWRITE);
1235     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
1236         tfm_core_panic();
1237     }
1238     SET_IOVEC_MAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE));
1239 
1240     return handle->outvec[outvec_idx].base;
1241 }
1242 
tfm_spm_partition_psa_unmap_outvec(psa_handle_t msg_handle,uint32_t outvec_idx,size_t len)1243 void tfm_spm_partition_psa_unmap_outvec(psa_handle_t msg_handle,
1244                                         uint32_t outvec_idx, size_t len)
1245 {
1246     struct conn_handle_t *handle;
1247 
1248     /* It is a fatal error if message handle is invalid */
1249     handle = spm_get_handle_by_msg_handle(msg_handle);
1250     if (!handle) {
1251         tfm_core_panic();
1252     }
1253 
1254     /*
1255      * It is a fatal error if MM-IOVEC has not been enabled for the RoT
1256      * Service that received the message.
1257      */
1258     if (!SERVICE_ENABLED_MM_IOVEC(handle->service->p_ldinf->flags)) {
1259         tfm_core_panic();
1260     }
1261 
1262     /*
1263      * It is a fatal error if message handle does not refer to a request
1264      * message.
1265      */
1266     if (handle->msg.type < PSA_IPC_CALL) {
1267         tfm_core_panic();
1268     }
1269 
1270     /*
1271      * It is a fatal error if outvec_idx is equal to or greater than
1272      * PSA_MAX_IOVEC.
1273      */
1274     if (outvec_idx >= PSA_MAX_IOVEC) {
1275         tfm_core_panic();
1276     }
1277 
1278     /*
1279      * It is a fatal error if len is greater than the output vector size.
1280      */
1281     if (len > handle->msg.out_size[outvec_idx]) {
1282         tfm_core_panic();
1283     }
1284 
1285     /*
1286      * It is a fatal error if The output vector has not been mapped by a call to
1287      * psa_map_outvec().
1288      */
1289     if (!IOVEC_IS_MAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
1290         tfm_core_panic();
1291     }
1292 
1293     /*
1294      * It is a fatal error if the output vector has already been unmapped by a
1295      * call to psa_unmap_outvec().
1296      */
1297     if (IOVEC_IS_UNMAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
1298         tfm_core_panic();
1299     }
1300 
1301     SET_IOVEC_UNMAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE));
1302 
1303     /* Update the write number */
1304     handle->outvec[outvec_idx].len = len;
1305 }
1306 
1307 #endif /* PSA_FRAMEWORK_HAS_MM_IOVEC */
1308