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(¤t_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(¤t_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