1 /*
2 * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
3 * Copyright (c) 2022-2024 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 "config_impl.h"
12 #include "critical_section.h"
13 #include "ffm/backend.h"
14 #include "ffm/psa_api.h"
15 #include "tfm_hal_isolation.h"
16 #include "tfm_psa_call_pack.h"
17 #include "utilities.h"
18
spm_associate_call_params(struct connection_t * p_connection,uint32_t ctrl_param,const psa_invec * inptr,psa_outvec * outptr)19 psa_status_t spm_associate_call_params(struct connection_t *p_connection,
20 uint32_t ctrl_param,
21 const psa_invec *inptr,
22 psa_outvec *outptr)
23 {
24 psa_invec ivecs_local[PSA_MAX_IOVEC];
25 psa_outvec ovecs_local[PSA_MAX_IOVEC];
26 int i, j;
27 fih_int fih_rc = FIH_FAILURE;
28 uint32_t ns_access = 0;
29 size_t ivec_num = PARAM_UNPACK_IN_LEN(ctrl_param);
30 size_t ovec_num = PARAM_UNPACK_OUT_LEN(ctrl_param);
31 struct partition_t *curr_partition = GET_CURRENT_COMPONENT();
32 int32_t type = PARAM_UNPACK_TYPE(ctrl_param);
33
34 /* The request type must be zero or positive. */
35 if (type < 0) {
36 return PSA_ERROR_PROGRAMMER_ERROR;
37 }
38
39 p_connection->msg.type = type;
40
41 if (!PARAM_HAS_IOVEC(ctrl_param)) {
42 return PSA_SUCCESS;
43 }
44
45 /* Process IO vectors */
46 /* in_len + out_len SHOULD <= PSA_MAX_IOVEC */
47 if ((ivec_num > SIZE_MAX - ovec_num) ||
48 (ivec_num + ovec_num > PSA_MAX_IOVEC)) {
49 return PSA_ERROR_PROGRAMMER_ERROR;
50 }
51
52 if (PARAM_IS_NS_VEC(ctrl_param)) {
53 ns_access = TFM_HAL_ACCESS_NS;
54 }
55
56 /*
57 * Read client invecs from the wrap input vector. It is a PROGRAMMER ERROR
58 * if the memory reference for the wrap input vector is invalid or not
59 * readable.
60 */
61 FIH_CALL(tfm_hal_memory_check, fih_rc,
62 curr_partition->boundary, (uintptr_t)inptr,
63 ivec_num * sizeof(psa_invec), TFM_HAL_ACCESS_READABLE | ns_access);
64 if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
65 return PSA_ERROR_PROGRAMMER_ERROR;
66 }
67
68 spm_memset(ivecs_local, 0, sizeof(ivecs_local));
69 spm_memcpy(ivecs_local, inptr, ivec_num * sizeof(psa_invec));
70
71 /*
72 * Read client outvecs from the wrap output vector and will update the
73 * actual length later. It is a PROGRAMMER ERROR if the memory reference for
74 * the wrap output vector is invalid or not read-write.
75 */
76 FIH_CALL(tfm_hal_memory_check, fih_rc,
77 curr_partition->boundary, (uintptr_t)outptr,
78 ovec_num * sizeof(psa_outvec), TFM_HAL_ACCESS_READWRITE | ns_access);
79 if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
80 return PSA_ERROR_PROGRAMMER_ERROR;
81 }
82
83 spm_memset(ovecs_local, 0, sizeof(ovecs_local));
84 spm_memcpy(ovecs_local, outptr, ovec_num * sizeof(psa_outvec));
85
86 /*
87 * Clients must never overlap input parameters because of the risk of a
88 * double-fetch inconsistency.
89 * Overflow is checked in tfm_hal_memory_check functions.
90 */
91 for (i = 0; i + 1 < ivec_num; i++) {
92 for (j = i + 1; j < ivec_num; j++) {
93 if (!((char *) ivecs_local[j].base + ivecs_local[j].len <=
94 (char *) ivecs_local[i].base ||
95 (char *) ivecs_local[j].base >=
96 (char *) ivecs_local[i].base + ivecs_local[i].len)) {
97 return PSA_ERROR_PROGRAMMER_ERROR;
98 }
99 }
100 }
101
102 if (PARAM_IS_NS_INVEC(ctrl_param)) {
103 /* Vector descriptor is non-secure then vectors are non-secure. */
104 ns_access = TFM_HAL_ACCESS_NS;
105 }
106
107 /* Make sure in_size and out_size arrays in the msg structure are cleared first */
108 spm_memset(p_connection->msg.in_size, 0, sizeof(p_connection->msg.in_size));
109 spm_memset(p_connection->msg.out_size, 0, sizeof(p_connection->msg.out_size));
110
111 /*
112 * For client input vector, it is a PROGRAMMER ERROR if the provided payload
113 * memory reference was invalid or not readable.
114 */
115 for (i = 0; i < ivec_num; i++) {
116 FIH_CALL(tfm_hal_memory_check, fih_rc,
117 curr_partition->boundary, (uintptr_t)ivecs_local[i].base,
118 ivecs_local[i].len, TFM_HAL_ACCESS_READABLE | ns_access);
119 if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
120 return PSA_ERROR_PROGRAMMER_ERROR;
121 }
122
123 p_connection->msg.in_size[i] = ivecs_local[i].len;
124 p_connection->invec_base[i] = ivecs_local[i].base;
125 p_connection->invec_accessed[i] = 0;
126 }
127
128 if (ns_access == TFM_HAL_ACCESS_NS &&
129 !PARAM_IS_NS_VEC(ctrl_param) &&
130 !PARAM_IS_NS_OUTVEC(ctrl_param)) {
131 ns_access = 0;
132 }
133
134 /*
135 * For client output vector, it is a PROGRAMMER ERROR if the provided
136 * payload memory reference was invalid or not read-write.
137 */
138 for (i = 0; i < ovec_num; i++) {
139 FIH_CALL(tfm_hal_memory_check, fih_rc,
140 curr_partition->boundary, (uintptr_t)ovecs_local[i].base,
141 ovecs_local[i].len, TFM_HAL_ACCESS_READWRITE | ns_access);
142 if (fih_not_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
143 return PSA_ERROR_PROGRAMMER_ERROR;
144 }
145
146 p_connection->msg.out_size[i] = ovecs_local[i].len;
147 p_connection->outvec_base[i] = ovecs_local[i].base;
148 p_connection->outvec_written[i] = 0;
149 }
150
151 p_connection->caller_outvec = outptr;
152
153 return PSA_SUCCESS;
154 }
155
tfm_spm_client_psa_call(psa_handle_t handle,uint32_t ctrl_param,const psa_invec * inptr,psa_outvec * outptr)156 psa_status_t tfm_spm_client_psa_call(psa_handle_t handle,
157 uint32_t ctrl_param,
158 const psa_invec *inptr,
159 psa_outvec *outptr)
160 {
161 struct connection_t *p_connection;
162 int32_t client_id;
163 bool ns_caller = tfm_spm_is_ns_caller();
164 psa_status_t status;
165
166 client_id = tfm_spm_get_client_id(ns_caller);
167
168 status = spm_get_idle_connection(&p_connection, handle, client_id);
169 if (status != PSA_SUCCESS) {
170 return status;
171 }
172
173 status = spm_associate_call_params(p_connection, ctrl_param, inptr, outptr);
174 if (status != PSA_SUCCESS) {
175 if (IS_STATIC_HANDLE(handle)) {
176 spm_free_connection(p_connection);
177 }
178 return status;
179 }
180
181 return backend_messaging(p_connection);
182 }
183