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