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