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