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 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 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 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 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 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 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 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 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 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 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