blob: 1cf65ae6358d0dc04f4b43f5fda4bdafc9be1532 [file] [log] [blame]
Manish V Badarkhe033f2b12025-04-15 20:16:32 +01001/*
2 * Copyright (c) 2025, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Manish V Badarkhe0be70f62025-05-16 15:16:53 +01007#include <errno.h>
8
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +01009#include <plat/common/platform.h>
10#include <services/bl31_lfa.h>
Manish V Badarkhe033f2b12025-04-15 20:16:32 +010011#include <services/lfa_svc.h>
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +010012#include <services/rmmd_rmm_lfa.h>
Manish V Badarkhe033f2b12025-04-15 20:16:32 +010013#include <smccc_helpers.h>
14
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +010015static uint32_t lfa_component_count;
16static plat_lfa_component_info_t *lfa_components;
17static struct lfa_component_status current_activation;
18static bool is_lfa_initialized;
19
20void lfa_reset_activation(void)
21{
22 current_activation.component_id = LFA_INVALID_COMPONENT;
23 current_activation.prime_status = PRIME_NONE;
Manish V Badarkhe0be70f62025-05-16 15:16:53 +010024 current_activation.cpu_rendezvous_required = false;
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +010025}
26
Manish V Badarkhe0ad7f442025-04-15 20:16:36 +010027static int convert_to_lfa_error(int ret)
28{
29 switch (ret) {
30 case 0:
31 return LFA_SUCCESS;
32 case -EAUTH:
33 return LFA_AUTH_ERROR;
34 case -ENOMEM:
35 return LFA_NO_MEMORY;
36 default:
37 return LFA_DEVICE_ERROR;
38 }
39}
40
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +010041static bool lfa_initialize_components(void)
42{
43 lfa_component_count = plat_lfa_get_components(&lfa_components);
44
45 if (lfa_component_count == 0U || lfa_components == NULL) {
46 /* unlikely to reach here */
47 ERROR("Invalid LFA component setup: count = 0 or components are NULL");
48 return false;
49 }
50
51 return true;
52}
53
Manish V Badarkhe7f104ee2025-04-15 20:16:34 +010054static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
55{
56 const plat_lfa_component_info_t *comp =
57 &lfa_components[fw_seq_id];
58 uint64_t flags = 0ULL;
59
60 flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
61 << LFA_ACTIVATION_CAPABLE_SHIFT);
62 flags |= (uint64_t)(comp->activation_pending)
63 << LFA_ACTIVATION_PENDING_SHIFT;
64
65 if (comp->activator != NULL) {
66 flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL)
67 << LFA_MAY_RESET_CPU_SHIFT);
68 flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL)
69 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT);
70 }
71
72 return flags;
73}
74
Manish V Badarkhe33b5d1a2025-04-15 20:16:35 +010075static int lfa_cancel(uint32_t component_id)
76{
77 int ret = LFA_SUCCESS;
78
79 if (lfa_component_count == 0U) {
80 return LFA_WRONG_STATE;
81 }
82
83 /* Check if component ID is in range. */
84 if ((component_id >= lfa_component_count) ||
85 (component_id != current_activation.component_id)) {
86 return LFA_INVALID_PARAMETERS;
87 }
88
89 ret = plat_lfa_cancel(component_id);
90 if (ret != LFA_SUCCESS) {
91 return LFA_BUSY;
92 }
93
94 /* TODO: add proper termination prime and activate phases */
95 lfa_reset_activation();
96
97 return ret;
98}
99
Manish V Badarkhe0be70f62025-05-16 15:16:53 +0100100static int lfa_activate(uint32_t component_id, uint64_t flags,
101 uint64_t ep_address, uint64_t context_id)
102{
103 int ret = LFA_ACTIVATION_FAILED;
104 struct lfa_component_ops *activator;
105
106 if ((lfa_component_count == 0U) ||
107 (!lfa_components[component_id].activation_pending) ||
108 (current_activation.prime_status != PRIME_COMPLETE)) {
109 return LFA_COMPONENT_WRONG_STATE;
110 }
111
112 /* Check if fw_seq_id is in range. */
113 if ((component_id >= lfa_component_count) ||
114 (current_activation.component_id != component_id)) {
115 return LFA_INVALID_PARAMETERS;
116 }
117
118 if (lfa_components[component_id].activator == NULL) {
119 return LFA_NOT_SUPPORTED;
120 }
121
122 activator = lfa_components[component_id].activator;
123 if (activator->activate != NULL) {
124 /*
125 * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
126 * & CPU_RENDEZVOUS is not required.
127 */
128 if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
129 if (!activator->cpu_rendezvous_required) {
130 INFO("Skipping rendezvous requested by caller.\n");
131 current_activation.cpu_rendezvous_required = false;
132 }
133 /*
134 * Return error if caller tries to skip rendezvous when
135 * it is required.
136 */
137 else {
138 ERROR("CPU Rendezvous is required, can't skip.\n");
139 return LFA_INVALID_PARAMETERS;
140 }
141 }
142
143 ret = activator->activate(&current_activation, ep_address,
144 context_id);
145 }
146
147 lfa_components[component_id].activation_pending = false;
148
149 return ret;
150}
151
Manish V Badarkhe0ad7f442025-04-15 20:16:36 +0100152static int lfa_prime(uint32_t component_id, uint64_t *flags)
153{
154 int ret = LFA_SUCCESS;
155 struct lfa_component_ops *activator;
156
157 if (lfa_component_count == 0U ||
158 !lfa_components[component_id].activation_pending) {
159 return LFA_WRONG_STATE;
160 }
161
162 /* Check if fw_seq_id is in range. */
163 if (component_id >= lfa_component_count) {
164 return LFA_INVALID_PARAMETERS;
165 }
166
167 if (lfa_components[component_id].activator == NULL) {
168 return LFA_NOT_SUPPORTED;
169 }
170
171 switch (current_activation.prime_status) {
172 case PRIME_NONE:
173 current_activation.component_id = component_id;
174 current_activation.prime_status = PRIME_STARTED;
175 break;
176
177 case PRIME_STARTED:
178 if (current_activation.component_id != component_id) {
179 /* Mismatched component trying to continue PRIME - error */
180 return LFA_WRONG_STATE;
181 }
182 break;
183
184 case PRIME_COMPLETE:
185 default:
186 break;
187 }
188
189 ret = plat_lfa_load_auth_image(component_id);
190 ret = convert_to_lfa_error(ret);
191
192 activator = lfa_components[component_id].activator;
193 if (activator->prime != NULL) {
194 ret = activator->prime(&current_activation);
195 if (ret != LFA_SUCCESS) {
196 /*
197 * TODO: it should be LFA_PRIME_FAILED but specification
198 * has not define this error yet
199 */
200 return ret;
201 }
202 }
203
204 current_activation.prime_status = PRIME_COMPLETE;
205
206 /* TODO: split this into multiple PRIME calls */
207 *flags = 0ULL;
208
209 return ret;
210}
211
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100212int lfa_setup(void)
213{
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +0100214 is_lfa_initialized = lfa_initialize_components();
215 if (!is_lfa_initialized) {
216 return -1;
217 }
218
219 lfa_reset_activation();
220
221 return 0;
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100222}
223
224uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
225 u_register_t x3, u_register_t x4, void *cookie,
226 void *handle, u_register_t flags)
227{
Manish V Badarkhe7f104ee2025-04-15 20:16:34 +0100228 uint64_t retx1, retx2;
Manish V Badarkhe0ad7f442025-04-15 20:16:36 +0100229 uint64_t lfa_flags;
Manish V Badarkhe7f104ee2025-04-15 20:16:34 +0100230 uint8_t *uuid_p;
231 uint32_t fw_seq_id = (uint32_t)x1;
Manish V Badarkhe33b5d1a2025-04-15 20:16:35 +0100232 int ret;
Manish V Badarkhe7f104ee2025-04-15 20:16:34 +0100233
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100234 /**
235 * TODO: Acquire serialization lock.
236 */
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +0100237
238 if (!is_lfa_initialized) {
239 return LFA_NOT_SUPPORTED;
240 }
241
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100242 switch (smc_fid) {
243 case LFA_VERSION:
244 SMC_RET1(handle, LFA_VERSION_VAL);
245 break;
246
247 case LFA_FEATURES:
248 SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED);
249 break;
250
251 case LFA_GET_INFO:
Manish V Badarkhe982ca0c2025-05-30 13:17:05 +0100252 /**
253 * The current specification limits this input parameter to be zero for
254 * version 1.0 of LFA
255 */
256 if (x1 == 0ULL) {
257 SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
258 } else {
259 SMC_RET1(handle, LFA_INVALID_PARAMETERS);
260 }
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100261 break;
262
263 case LFA_GET_INVENTORY:
Manish V Badarkhe7f104ee2025-04-15 20:16:34 +0100264 if (lfa_component_count == 0U) {
265 SMC_RET1(handle, LFA_WRONG_STATE);
266 }
267
268 /*
269 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
270 * platform firmware and create a valid number of firmware components.
271 */
272 if (fw_seq_id >= lfa_component_count) {
273 SMC_RET1(handle, LFA_INVALID_PARAMETERS);
274 }
275
276 /*
277 * grab the UUID of asked fw_seq_id and set the return UUID
278 * variables
279 */
280 uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
281 memcpy(&retx1, uuid_p, sizeof(uint64_t));
282 memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
283
284 /*
285 * check the given fw_seq_id's update available
286 * and accordingly set the active_pending flag
287 */
288 lfa_components[fw_seq_id].activation_pending =
289 is_plat_lfa_activation_pending(fw_seq_id);
290
291 INFO("Component %lu %s live activation:\n", x1,
292 lfa_components[fw_seq_id].activator ? "supports" :
293 "does not support");
294
295 if (lfa_components[fw_seq_id].activator != NULL) {
296 INFO("Activation pending: %s\n",
297 lfa_components[fw_seq_id].activation_pending ? "true" : "false");
298 }
299
300 INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
301
302 SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
303
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100304 break;
305
306 case LFA_PRIME:
Manish V Badarkhe0ad7f442025-04-15 20:16:36 +0100307 ret = lfa_prime(x1, &lfa_flags);
308 if (ret != LFA_SUCCESS) {
309 SMC_RET1(handle, ret);
310 } else {
311 SMC_RET2(handle, ret, lfa_flags);
312 }
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100313 break;
314
315 case LFA_ACTIVATE:
Manish V Badarkhe0be70f62025-05-16 15:16:53 +0100316 ret = lfa_activate(fw_seq_id, x2, x3, x4);
317 /* TODO: implement activate again */
318 SMC_RET2(handle, ret, 0ULL);
319
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100320 break;
321
322 case LFA_CANCEL:
Manish V Badarkhe33b5d1a2025-04-15 20:16:35 +0100323 ret = lfa_cancel(x1);
324 SMC_RET1(handle, ret);
Manish V Badarkhe033f2b12025-04-15 20:16:32 +0100325 break;
326
327 default:
328 WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
329 SMC_RET1(handle, SMC_UNK);
330 break; /* unreachable */
331
332 }
333
334 SMC_RET1(handle, SMC_UNK);
335
336 return 0;
337}