xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision 8beca56ab371515ee99cf491c77d1c22fd8a480b)
1 /*
2  * Copyright (c) 2025, Arm Limited. All rights reserved.
3  * Copyright (c) 2025, NVIDIA Corporation. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 
11 #include <lib/spinlock.h>
12 #include <plat/common/platform.h>
13 #include <services/bl31_lfa.h>
14 #include <services/lfa_svc.h>
15 #include <services/rmmd_rmm_lfa.h>
16 #include <smccc_helpers.h>
17 
18 static uint32_t lfa_component_count;
19 static plat_lfa_component_info_t *lfa_components;
20 static struct lfa_component_status current_activation;
21 static bool is_lfa_initialized;
22 
23 /*
24  * Spinlock to serialize LFA operations (PRIME, ACTIVATE).
25  * This ensures that these calls from different CPUs are properly
26  * serialized and do not execute concurrently, while still allowing
27  * the same operation to be invoked from any CPU.
28  */
29 static spinlock_t lfa_lock;
30 
lfa_reset_activation(void)31 void lfa_reset_activation(void)
32 {
33 	current_activation.component_id = LFA_INVALID_COMPONENT;
34 	current_activation.prime_status = PRIME_NONE;
35 	current_activation.cpu_rendezvous_required = false;
36 }
37 
convert_to_lfa_error(int ret)38 static int convert_to_lfa_error(int ret)
39 {
40 	switch (ret) {
41 	case 0:
42 		return LFA_SUCCESS;
43 	case -EAUTH:
44 		return LFA_AUTH_ERROR;
45 	case -ENOMEM:
46 		return LFA_NO_MEMORY;
47 	default:
48 		return LFA_DEVICE_ERROR;
49 	}
50 }
51 
lfa_initialize_components(void)52 static bool lfa_initialize_components(void)
53 {
54 	lfa_component_count = plat_lfa_get_components(&lfa_components);
55 
56 	if (lfa_component_count == 0U || lfa_components == NULL) {
57 		/* unlikely to reach here */
58 		ERROR("Invalid LFA component setup: count = 0 or components are NULL");
59 		return false;
60 	}
61 
62 	return true;
63 }
64 
get_fw_activation_flags(uint32_t fw_seq_id)65 static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
66 {
67 	const plat_lfa_component_info_t *comp =
68 				&lfa_components[fw_seq_id];
69 	uint64_t flags = 0ULL;
70 
71 	flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
72 		 << LFA_ACTIVATION_CAPABLE_SHIFT);
73 	flags |= (uint64_t)(comp->activation_pending)
74 		 << LFA_ACTIVATION_PENDING_SHIFT;
75 
76 	if (comp->activator != NULL) {
77 		flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
78 			 << LFA_MAY_RESET_CPU_SHIFT);
79 		flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
80 			 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
81 	}
82 
83 	return flags;
84 }
85 
lfa_cancel(uint32_t component_id)86 static int lfa_cancel(uint32_t component_id)
87 {
88 	int ret = LFA_SUCCESS;
89 
90 	if (lfa_component_count == 0U) {
91 		return LFA_WRONG_STATE;
92 	}
93 
94 	/* Check if component ID is in range. */
95 	if ((component_id >= lfa_component_count) ||
96 	    (component_id != current_activation.component_id)) {
97 		return LFA_INVALID_PARAMETERS;
98 	}
99 
100 	ret = plat_lfa_cancel(component_id);
101 	if (ret != LFA_SUCCESS) {
102 		return LFA_BUSY;
103 	}
104 
105 	/* TODO: add proper termination prime and activate phases */
106 	lfa_reset_activation();
107 
108 	return ret;
109 }
110 
lfa_activate(uint32_t component_id,uint64_t flags,uint64_t ep_address,uint64_t context_id)111 static int lfa_activate(uint32_t component_id, uint64_t flags,
112 			uint64_t ep_address, uint64_t context_id)
113 {
114 	int ret = LFA_ACTIVATION_FAILED;
115 	struct lfa_component_ops *activator;
116 
117 	if ((lfa_component_count == 0U) ||
118 	    (!lfa_components[component_id].activation_pending) ||
119 	    (current_activation.prime_status != PRIME_COMPLETE)) {
120 		return LFA_COMPONENT_WRONG_STATE;
121 	}
122 
123 	/* Check if fw_seq_id is in range. */
124 	if ((component_id >= lfa_component_count) ||
125 	    (current_activation.component_id != component_id)) {
126 		return LFA_INVALID_PARAMETERS;
127 	}
128 
129 	if (lfa_components[component_id].activator == NULL) {
130 		return LFA_NOT_SUPPORTED;
131 	}
132 
133 	ret = plat_lfa_notify_activate(component_id);
134 	if (ret != 0) {
135 		return LFA_ACTIVATION_FAILED;
136 	}
137 
138 	activator = lfa_components[component_id].activator;
139 	if (activator->activate != NULL) {
140 		/*
141 		 * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
142 		 * & CPU_RENDEZVOUS is not required.
143 		 */
144 		if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
145 			if (!activator->cpu_rendezvous_required) {
146 				INFO("Skipping rendezvous requested by caller.\n");
147 				current_activation.cpu_rendezvous_required = false;
148 			}
149 			/*
150 			 * Return error if caller tries to skip rendezvous when
151 			 * it is required.
152 			 */
153 			else {
154 				ERROR("CPU Rendezvous is required, can't skip.\n");
155 				return LFA_INVALID_PARAMETERS;
156 			}
157 		}
158 
159 		ret = activator->activate(&current_activation, ep_address,
160 					  context_id);
161 	}
162 
163 	/*
164 	 * Update the activation pending flag only if the activation was
165 	 * successful.
166 	 */
167 	if (ret == LFA_SUCCESS) {
168 		lfa_components[component_id].activation_pending = false;
169 	}
170 
171 	return ret;
172 }
173 
lfa_prime(uint32_t component_id,uint64_t * flags)174 static int lfa_prime(uint32_t component_id, uint64_t *flags)
175 {
176 	int ret = LFA_SUCCESS;
177 	struct lfa_component_ops *activator;
178 
179 	if (lfa_component_count == 0U ||
180 	    !lfa_components[component_id].activation_pending) {
181 		return LFA_WRONG_STATE;
182 	}
183 
184 	/* Check if fw_seq_id is in range. */
185 	if (component_id >= lfa_component_count) {
186 		return LFA_INVALID_PARAMETERS;
187 	}
188 
189 	if (lfa_components[component_id].activator == NULL) {
190 		return LFA_NOT_SUPPORTED;
191 	}
192 
193 	switch (current_activation.prime_status) {
194 	case PRIME_NONE:
195 		current_activation.component_id = component_id;
196 		current_activation.prime_status = PRIME_STARTED;
197 		break;
198 
199 	case PRIME_STARTED:
200 		if (current_activation.component_id != component_id) {
201 			/* Mismatched component trying to continue PRIME - error */
202 			return LFA_WRONG_STATE;
203 		}
204 		break;
205 
206 	case PRIME_COMPLETE:
207 	default:
208 		break;
209 	}
210 
211 	/* Initialise the flags to start with. Only valid if ret=LFA_SUCCESS. */
212 	*flags = 0ULL;
213 
214 	ret = plat_lfa_load_auth_image(component_id);
215 	if (ret == 0) {
216 		activator = lfa_components[component_id].activator;
217 		if (activator->prime != NULL) {
218 			ret = activator->prime(&current_activation);
219 			if (ret != LFA_SUCCESS) {
220 				/*
221 				* TODO: it should be LFA_PRIME_FAILED but specification
222 				* has not define this error yet
223 				*/
224 				return ret;
225 			}
226 		}
227 
228 		current_activation.prime_status = PRIME_COMPLETE;
229 	}
230 
231 	/*
232 	 * Set lfa_flags to indicate that LFA_PRIME must be called again and
233 	 * reset ret to 0, as LFA_PRIME must return LFA_SUCCESS if it is
234 	 * incomplete.
235 	 */
236 	if (ret == -EAGAIN) {
237 		ret = 0;
238 		*flags = LFA_CALL_AGAIN;
239 	}
240 
241 	return convert_to_lfa_error(ret);
242 }
243 
lfa_is_prime_complete(uint32_t lfa_component_id)244 bool lfa_is_prime_complete(uint32_t lfa_component_id)
245 {
246 	if (lfa_component_id >= lfa_component_count) {
247 		return false;
248 	}
249 
250 	return (current_activation.component_id == lfa_component_id &&
251 		current_activation.prime_status == PRIME_COMPLETE &&
252 		lfa_components[lfa_component_id].activation_pending == true);
253 }
254 
lfa_setup(void)255 int lfa_setup(void)
256 {
257 	is_lfa_initialized = lfa_initialize_components();
258 	if (!is_lfa_initialized) {
259 		return -1;
260 	}
261 
262 	lfa_reset_activation();
263 
264 	return 0;
265 }
266 
lfa_smc_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)267 uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
268 			 u_register_t x3, u_register_t x4, void *cookie,
269 			 void *handle, u_register_t flags)
270 {
271 	uint64_t retx1, retx2;
272 	uint64_t lfa_flags;
273 	uint8_t *uuid_p;
274 	uint32_t fw_seq_id = (uint32_t)x1;
275 	int ret;
276 
277 	/**
278 	 * TODO: Acquire serialization lock.
279 	 */
280 
281 	if (!is_lfa_initialized) {
282 		return LFA_NOT_SUPPORTED;
283 	}
284 
285 	switch (smc_fid) {
286 	case LFA_VERSION:
287 		SMC_RET1(handle, LFA_VERSION_VAL);
288 		break;
289 
290 	case LFA_FEATURES:
291 		SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
292 		break;
293 
294 	case LFA_GET_INFO:
295 		/**
296 		 * The current specification limits this input parameter to be zero for
297 		 * version 1.0 of LFA
298 		 */
299 		if (x1 == 0ULL) {
300 			SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
301 		} else {
302 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
303 		}
304 		break;
305 
306 	case LFA_GET_INVENTORY:
307 		if (lfa_component_count == 0U) {
308 			SMC_RET1(handle, LFA_WRONG_STATE);
309 		}
310 
311 		/*
312 		 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
313 		 * platform firmware and create a valid number of firmware components.
314 		 */
315 		if (fw_seq_id >= lfa_component_count) {
316 			SMC_RET1(handle, LFA_INVALID_PARAMETERS);
317 		}
318 
319 		/*
320 		 * grab the UUID of asked fw_seq_id and set the return UUID
321 		 * variables
322 		 */
323 		uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
324 		memcpy(&retx1, uuid_p, sizeof(uint64_t));
325 		memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
326 
327 		/*
328 		 * check the given fw_seq_id's update available
329 		 * and accordingly set the active_pending flag
330 		 */
331 		lfa_components[fw_seq_id].activation_pending =
332 				is_plat_lfa_activation_pending(fw_seq_id);
333 
334 		INFO("Component %lu %s live activation:\n", x1,
335 		      lfa_components[fw_seq_id].activator ? "supports" :
336 		      "does not support");
337 
338 		if (lfa_components[fw_seq_id].activator != NULL) {
339 			INFO("Activation pending: %s\n",
340 			      lfa_components[fw_seq_id].activation_pending ? "true" : "false");
341 		}
342 
343 		INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
344 
345 		SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
346 
347 		break;
348 
349 	case LFA_PRIME:
350 		/*
351 		 * Acquire lock to serialize PRIME operations across CPUs.
352 		 * This ensures that multiple PRIME calls to the same component
353 		 * do not execute concurrently, even if issued from different
354 		 * CPUs.
355 		 */
356 		if (!spin_trylock(&lfa_lock)) {
357 			SMC_RET1(handle, LFA_BUSY);
358 		}
359 
360 		ret = lfa_prime(x1, &lfa_flags);
361 
362 		spin_unlock(&lfa_lock);
363 
364 		if (ret != LFA_SUCCESS) {
365 			SMC_RET1(handle, ret);
366 		} else {
367 			SMC_RET2(handle, ret, lfa_flags);
368 		}
369 		break;
370 
371 	case LFA_ACTIVATE:
372 		ret = lfa_activate(fw_seq_id, x2, x3, x4);
373 		/* TODO: implement activate again */
374 		SMC_RET2(handle, ret, 0ULL);
375 
376 		break;
377 
378 	case LFA_CANCEL:
379 		ret = lfa_cancel(x1);
380 		SMC_RET1(handle, ret);
381 		break;
382 
383 	default:
384 		WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
385 		SMC_RET1(handle, SMC_UNK);
386 		break; /* unreachable */
387 
388 	}
389 
390 	SMC_RET1(handle, SMC_UNK);
391 
392 	return 0;
393 }
394