1 /*
2  * Copyright (c) 2019-2023, Arm Limited. All rights reserved.
3  * Copyright (c) 2022-2023 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 #include "ffm/psa_api.h"
11 #include "spm.h"
12 #include "utilities.h"
13 #include "tfm_hal_isolation.h"
14 
tfm_spm_partition_psa_read(psa_handle_t msg_handle,uint32_t invec_idx,void * buffer,size_t num_bytes)15 size_t tfm_spm_partition_psa_read(psa_handle_t msg_handle, uint32_t invec_idx,
16                                   void *buffer, size_t num_bytes)
17 {
18     size_t bytes, remaining;
19     struct connection_t *handle = NULL;
20     struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
21     fih_int fih_rc = FIH_FAILURE;
22 
23     /* It is a fatal error if message handle is invalid */
24     handle = spm_msg_handle_to_connection(msg_handle);
25     if (!handle) {
26         tfm_core_panic();
27     }
28 
29     /*
30      * It is a fatal error if message handle does not refer to a request
31      * message
32      */
33     if (handle->msg.type < PSA_IPC_CALL) {
34         tfm_core_panic();
35     }
36 
37     /*
38      * It is a fatal error if invec_idx is equal to or greater than
39      * PSA_MAX_IOVEC
40      */
41     if (invec_idx >= PSA_MAX_IOVEC) {
42         tfm_core_panic();
43     }
44 
45 #if PSA_FRAMEWORK_HAS_MM_IOVEC
46     /*
47      * It is a fatal error if the input vector has already been mapped using
48      * psa_map_invec().
49      */
50     if (IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
51         tfm_core_panic();
52     }
53 
54     SET_IOVEC_ACCESSED(handle, (invec_idx + INVEC_IDX_BASE));
55 #endif
56 
57     remaining = handle->msg.in_size[invec_idx] - handle->invec_accessed[invec_idx];
58     /* There was no remaining data in this input vector */
59     if (remaining == 0) {
60         return 0;
61     }
62 
63     /*
64      * Copy the client data to the service buffer. It is a fatal error
65      * if the memory reference for buffer is invalid or not read-write.
66      */
67     FIH_CALL(tfm_hal_memory_check, fih_rc,
68              curr_partition->boundary, (uintptr_t)buffer,
69              num_bytes, TFM_HAL_ACCESS_READWRITE);
70     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
71         tfm_core_panic();
72     }
73 
74     bytes = num_bytes < remaining ? num_bytes : remaining;
75 
76     spm_memcpy(buffer, (char *)handle->invec_base[invec_idx] +
77                                handle->invec_accessed[invec_idx], bytes);
78 
79     /* Update the data size read */
80     handle->invec_accessed[invec_idx] += bytes;
81 
82     return bytes;
83 }
84 
tfm_spm_partition_psa_skip(psa_handle_t msg_handle,uint32_t invec_idx,size_t num_bytes)85 size_t tfm_spm_partition_psa_skip(psa_handle_t msg_handle, uint32_t invec_idx,
86                                   size_t num_bytes)
87 {
88     struct connection_t *handle = NULL;
89     size_t remaining;
90 
91     /* It is a fatal error if message handle is invalid */
92     handle = spm_msg_handle_to_connection(msg_handle);
93     if (!handle) {
94         tfm_core_panic();
95     }
96 
97     /*
98      * It is a fatal error if message handle does not refer to a request
99      * message
100      */
101     if (handle->msg.type < PSA_IPC_CALL) {
102         tfm_core_panic();
103     }
104 
105     /*
106      * It is a fatal error if invec_idx is equal to or greater than
107      * PSA_MAX_IOVEC
108      */
109     if (invec_idx >= PSA_MAX_IOVEC) {
110         tfm_core_panic();
111     }
112 
113 #if PSA_FRAMEWORK_HAS_MM_IOVEC
114     /*
115      * It is a fatal error if the input vector has already been mapped using
116      * psa_map_invec().
117      */
118     if (IOVEC_IS_MAPPED(handle, (invec_idx + INVEC_IDX_BASE))) {
119         tfm_core_panic();
120     }
121 
122     SET_IOVEC_ACCESSED(handle, (invec_idx + INVEC_IDX_BASE));
123 #endif
124 
125     remaining = handle->msg.in_size[invec_idx] - handle->invec_accessed[invec_idx];
126     /* There was no remaining data in this input vector */
127     if (remaining == 0) {
128         return 0;
129     }
130 
131     /*
132      * If num_bytes is greater than the remaining size of the input vector then
133      * the remaining size of the input vector is used.
134      */
135     if (num_bytes > remaining) {
136         num_bytes = remaining;
137     }
138 
139     /* Update the data size accessed */
140     handle->invec_accessed[invec_idx] += num_bytes;
141 
142     return num_bytes;
143 }
144 
tfm_spm_partition_psa_write(psa_handle_t msg_handle,uint32_t outvec_idx,const void * buffer,size_t num_bytes)145 psa_status_t tfm_spm_partition_psa_write(psa_handle_t msg_handle, uint32_t outvec_idx,
146                                          const void *buffer, size_t num_bytes)
147 {
148     struct connection_t *handle = NULL;
149     struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
150     fih_int fih_rc = FIH_FAILURE;
151 
152     /* It is a fatal error if message handle is invalid */
153     handle = spm_msg_handle_to_connection(msg_handle);
154     if (!handle) {
155         tfm_core_panic();
156     }
157 
158     /*
159      * It is a fatal error if message handle does not refer to a request
160      * message
161      */
162     if (handle->msg.type < PSA_IPC_CALL) {
163         tfm_core_panic();
164     }
165 
166     /*
167      * It is a fatal error if outvec_idx is equal to or greater than
168      * PSA_MAX_IOVEC
169      */
170     if (outvec_idx >= PSA_MAX_IOVEC) {
171         tfm_core_panic();
172     }
173 
174     /*
175      * It is a fatal error if the call attempts to write data past the end of
176      * the client output vector
177      */
178     if (num_bytes > handle->msg.out_size[outvec_idx] - handle->outvec_written[outvec_idx]) {
179         tfm_core_panic();
180     }
181 
182 #if PSA_FRAMEWORK_HAS_MM_IOVEC
183     /*
184      * It is a fatal error if the output vector has already been mapped using
185      * psa_map_outvec().
186      */
187     if (IOVEC_IS_MAPPED(handle, (outvec_idx + OUTVEC_IDX_BASE))) {
188         tfm_core_panic();
189     }
190 
191     SET_IOVEC_ACCESSED(handle, (outvec_idx + OUTVEC_IDX_BASE));
192 #endif
193 
194     /*
195      * Copy the service buffer to client outvecs. It is a fatal error
196      * if the memory reference for buffer is invalid or not readable.
197      */
198     FIH_CALL(tfm_hal_memory_check, fih_rc,
199              curr_partition->boundary, (uintptr_t)buffer,
200              num_bytes, TFM_HAL_ACCESS_READABLE);
201     if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
202         tfm_core_panic();
203     }
204 
205     spm_memcpy((char *)handle->outvec_base[outvec_idx] +
206                handle->outvec_written[outvec_idx], buffer, num_bytes);
207 
208     /* Update the data size written */
209     handle->outvec_written[outvec_idx] += num_bytes;
210 
211     return PSA_SUCCESS;
212 }
213