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