1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3 * Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
4 */
5
6 #include "sp_discovery.h"
7 #include "ffa_api.h"
8 #include "sp_rxtx.h"
9 #include "util.h"
10 #include <string.h>
11
12 static const struct sp_uuid uuid_nil = { 0 };
13
sp_discovery_ffa_version_get(uint16_t * major,uint16_t * minor)14 sp_result sp_discovery_ffa_version_get(uint16_t *major, uint16_t *minor)
15 {
16 uint32_t version = 0;
17 ffa_result ffa_res = FFA_OK;
18
19 ffa_res = ffa_version(&version);
20 if (ffa_res != FFA_OK) {
21 *major = UINT16_C(0);
22 *minor = UINT16_C(0);
23
24 return SP_RESULT_FFA(ffa_res);
25 }
26
27 *major = (version >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK;
28 *minor = (version >> FFA_VERSION_MINOR_SHIFT) & FFA_VERSION_MINOR_MASK;
29
30 return SP_RESULT_OK;
31 }
32
sp_discovery_own_id_get(uint16_t * id)33 sp_result sp_discovery_own_id_get(uint16_t *id)
34 {
35 ffa_result ffa_res = FFA_OK;
36
37 ffa_res = ffa_id_get(id);
38 return SP_RESULT_FFA(ffa_res);
39 }
40
unpack_ffa_info(const struct ffa_partition_information * ffa_info,struct sp_partition_info * sp_info)41 static void unpack_ffa_info(const struct ffa_partition_information *ffa_info,
42 struct sp_partition_info *sp_info)
43 {
44 uint32_t props = ffa_info->partition_properties;
45
46 sp_info->partition_id = ffa_info->partition_id;
47 sp_info->execution_context_count = ffa_info->execution_context_count;
48 sp_info->supports_direct_requests =
49 props & FFA_PARTITION_SUPPORTS_DIRECT_REQUESTS;
50 sp_info->can_send_direct_requests =
51 props & FFA_PARTITION_CAN_SEND_DIRECT_REQUESTS;
52 sp_info->supports_indirect_requests =
53 props & FFA_PARTITION_SUPPORTS_INDIRECT_REQUESTS;
54 #if CFG_FFA_VERSION >= FFA_VERSION_1_1
55 sp_info->partition_id_type =
56 (props >> FFA_PARTITION_PART_ID_SHIFT) & FFA_PARTITION_PART_ID_MASK;
57 sp_info->inform_vm_create = props & FFA_PARTITION_INFORM_VM_CREATE;
58 sp_info->inform_vm_destroy = props & FFA_PARTITION_INFORM_VM_DESTROY;
59 if (props & FFA_PARTITION_AARCH64_EXECUTION_STATE)
60 sp_info->execution_state = sp_execution_state_aarch64;
61 else
62 sp_info->execution_state = sp_execution_state_aarch32;
63 memcpy(sp_info->uuid.uuid, ffa_info->uuid.uuid, sizeof(sp_info->uuid.uuid));
64
65 #endif /* CFG_FFA_VERSION */
66 }
67
partition_info_get(const struct sp_uuid * uuid,struct sp_partition_info info[],uint32_t * count,bool allow_nil_uuid)68 static sp_result partition_info_get(const struct sp_uuid *uuid, struct sp_partition_info info[],
69 uint32_t *count, bool allow_nil_uuid)
70 {
71 const struct ffa_partition_information *ffa_info = NULL;
72 uint32_t ffa_count = 0;
73 uint32_t i = 0;
74 sp_result sp_res = SP_RESULT_OK;
75 const void *buffer = NULL;
76 size_t buffer_size = 0;
77 struct ffa_uuid ffa_uuid = { 0 };
78 ffa_result ffa_res = FFA_OK;
79 uint32_t __maybe_unused ffa_size = 0;
80
81 if (count == NULL)
82 return SP_RESULT_INVALID_PARAMETERS;
83
84 if (info == NULL) {
85 *count = UINT32_C(0);
86 return SP_RESULT_INVALID_PARAMETERS;
87 }
88
89 if (uuid == NULL || (!allow_nil_uuid &&
90 memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)) {
91 sp_res = SP_RESULT_INVALID_PARAMETERS;
92 goto out;
93 }
94
95 sp_res = sp_rxtx_buffer_rx_get(&buffer, &buffer_size);
96 if (sp_res != SP_RESULT_OK) {
97 goto out;
98 }
99
100 /* Safely convert to FF-A UUID format */
101 memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
102
103 #if CFG_FFA_VERSION == FFA_VERSION_1_0
104 ffa_res = ffa_partition_info_get(&ffa_uuid, &ffa_count);
105 if (ffa_res != FFA_OK) {
106 sp_res = SP_RESULT_FFA(ffa_res);
107 goto out;
108 }
109 #elif CFG_FFA_VERSION >= FFA_VERSION_1_1
110 ffa_res = ffa_partition_info_get(&ffa_uuid, 0, &ffa_count, &ffa_size);
111 if (ffa_res != FFA_OK) {
112 sp_res = SP_RESULT_FFA(ffa_res);
113 goto out;
114 }
115
116 if (ffa_size != sizeof(struct ffa_partition_information)) {
117 /* Non-matching structure size, this may happen in future FF-A versions */
118 sp_res = SP_RESULT_INTERNAL_ERROR;
119 goto out;
120 }
121 #endif
122
123 if ((ffa_count * sizeof(struct ffa_partition_information)) > buffer_size) {
124 /* The indicated amount of info structures doesn't fit into the RX buffer */
125 sp_res = SP_RESULT_INTERNAL_ERROR;
126 goto out;
127 }
128
129 ffa_info = (const struct ffa_partition_information *)buffer;
130
131 if (ffa_count == 0) {
132 sp_res = SP_RESULT_NOT_FOUND;
133 goto out;
134 }
135
136 *count = MIN(*count, ffa_count);
137 for (i = 0; i < *count; i++)
138 unpack_ffa_info(&ffa_info[i], &info[i]);
139
140 return SP_RESULT_OK;
141
142 out:
143 for (i = 0; i < *count; i++)
144 info[i] = (struct sp_partition_info){ 0 };
145 *count = UINT32_C(0);
146
147 return sp_res;
148 }
149
sp_discovery_partition_id_get(const struct sp_uuid * uuid,uint16_t * id)150 sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
151 uint16_t *id)
152 {
153 struct sp_partition_info sp_info = { 0 };
154 sp_result sp_res = SP_RESULT_OK;
155 uint32_t count = 1;
156
157 if (id == NULL)
158 return SP_RESULT_INVALID_PARAMETERS;
159
160 *id = FFA_ID_GET_ID_MASK;
161
162 if (uuid == NULL || memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)
163 return SP_RESULT_INVALID_PARAMETERS;
164
165 sp_res = partition_info_get(uuid, &sp_info, &count, false);
166 if (sp_res != SP_RESULT_OK)
167 return sp_res;
168
169 *id = sp_info.partition_id;
170
171 return SP_RESULT_OK;
172 }
173
sp_discovery_partition_info_get(const struct sp_uuid * uuid,struct sp_partition_info info[],uint32_t * count)174 sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
175 struct sp_partition_info info[],
176 uint32_t *count)
177 {
178 return partition_info_get(uuid, info, count, false);
179 }
180
sp_discovery_partition_info_get_all(struct sp_partition_info info[],uint32_t * count)181 sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
182 uint32_t *count)
183 {
184 return partition_info_get(&uuid_nil, info, count, true);
185 }
186
187 #if CFG_FFA_VERSION >= FFA_VERSION_1_1
sp_discovery_partition_info_get_count(const struct sp_uuid * uuid,uint32_t * count)188 sp_result sp_discovery_partition_info_get_count(const struct sp_uuid *uuid, uint32_t *count)
189 {
190 struct ffa_uuid ffa_uuid = { 0 };
191 ffa_result ffa_res = FFA_OK;
192 uint32_t ffa_size = 0;
193
194 if (count == NULL)
195 return SP_RESULT_INVALID_PARAMETERS;
196
197 *count = 0;
198
199 if (uuid == NULL)
200 return SP_RESULT_INVALID_PARAMETERS;
201
202 /* Safely convert to FF-A UUID format */
203 memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
204
205 ffa_res = ffa_partition_info_get(&ffa_uuid, FFA_PARTITION_INFO_GET_FLAG_COUNT_ONLY, count,
206 &ffa_size);
207 if (ffa_res != FFA_OK)
208 return SP_RESULT_FFA(ffa_res);
209
210 if (ffa_size != 0)
211 /* Size is MBZ if FFA_PARTITION_INFO_GET_FLAG_COUNT_ONLY is set */
212 return SP_RESULT_INTERNAL_ERROR;
213
214 return SP_RESULT_OK;
215 }
216 #endif /* CFG_FFA_VERSION */
217