1cf48f49fSManish V Badarkhe /* 2cf48f49fSManish V Badarkhe * Copyright (c) 2025, Arm Limited. All rights reserved. 3cf48f49fSManish V Badarkhe * 4cf48f49fSManish V Badarkhe * SPDX-License-Identifier: BSD-3-Clause 5cf48f49fSManish V Badarkhe */ 6cf48f49fSManish V Badarkhe 7*07de22d2SManish V Badarkhe #include <errno.h> 8*07de22d2SManish V Badarkhe 9b9dee50cSManish V Badarkhe #include <plat/common/platform.h> 10b9dee50cSManish V Badarkhe #include <services/bl31_lfa.h> 11cf48f49fSManish V Badarkhe #include <services/lfa_svc.h> 12b9dee50cSManish V Badarkhe #include <services/rmmd_rmm_lfa.h> 13cf48f49fSManish V Badarkhe #include <smccc_helpers.h> 14cf48f49fSManish V Badarkhe 15b9dee50cSManish V Badarkhe static uint32_t lfa_component_count; 16b9dee50cSManish V Badarkhe static plat_lfa_component_info_t *lfa_components; 17b9dee50cSManish V Badarkhe static struct lfa_component_status current_activation; 18b9dee50cSManish V Badarkhe static bool is_lfa_initialized; 19b9dee50cSManish V Badarkhe 20b9dee50cSManish V Badarkhe void lfa_reset_activation(void) 21b9dee50cSManish V Badarkhe { 22b9dee50cSManish V Badarkhe current_activation.component_id = LFA_INVALID_COMPONENT; 23b9dee50cSManish V Badarkhe current_activation.prime_status = PRIME_NONE; 24*07de22d2SManish V Badarkhe current_activation.cpu_rendezvous_required = false; 25b9dee50cSManish V Badarkhe } 26b9dee50cSManish V Badarkhe 2767fa182fSManish V Badarkhe static int convert_to_lfa_error(int ret) 2867fa182fSManish V Badarkhe { 2967fa182fSManish V Badarkhe switch (ret) { 3067fa182fSManish V Badarkhe case 0: 3167fa182fSManish V Badarkhe return LFA_SUCCESS; 3267fa182fSManish V Badarkhe case -EAUTH: 3367fa182fSManish V Badarkhe return LFA_AUTH_ERROR; 3467fa182fSManish V Badarkhe case -ENOMEM: 3567fa182fSManish V Badarkhe return LFA_NO_MEMORY; 3667fa182fSManish V Badarkhe default: 3767fa182fSManish V Badarkhe return LFA_DEVICE_ERROR; 3867fa182fSManish V Badarkhe } 3967fa182fSManish V Badarkhe } 4067fa182fSManish V Badarkhe 41b9dee50cSManish V Badarkhe static bool lfa_initialize_components(void) 42b9dee50cSManish V Badarkhe { 43b9dee50cSManish V Badarkhe lfa_component_count = plat_lfa_get_components(&lfa_components); 44b9dee50cSManish V Badarkhe 45b9dee50cSManish V Badarkhe if (lfa_component_count == 0U || lfa_components == NULL) { 46b9dee50cSManish V Badarkhe /* unlikely to reach here */ 47b9dee50cSManish V Badarkhe ERROR("Invalid LFA component setup: count = 0 or components are NULL"); 48b9dee50cSManish V Badarkhe return false; 49b9dee50cSManish V Badarkhe } 50b9dee50cSManish V Badarkhe 51b9dee50cSManish V Badarkhe return true; 52b9dee50cSManish V Badarkhe } 53b9dee50cSManish V Badarkhe 5406a6f296SManish V Badarkhe static uint64_t get_fw_activation_flags(uint32_t fw_seq_id) 5506a6f296SManish V Badarkhe { 5606a6f296SManish V Badarkhe const plat_lfa_component_info_t *comp = 5706a6f296SManish V Badarkhe &lfa_components[fw_seq_id]; 5806a6f296SManish V Badarkhe uint64_t flags = 0ULL; 5906a6f296SManish V Badarkhe 6006a6f296SManish V Badarkhe flags |= ((comp->activator == NULL ? 0ULL : 1ULL) 6106a6f296SManish V Badarkhe << LFA_ACTIVATION_CAPABLE_SHIFT); 6206a6f296SManish V Badarkhe flags |= (uint64_t)(comp->activation_pending) 6306a6f296SManish V Badarkhe << LFA_ACTIVATION_PENDING_SHIFT; 6406a6f296SManish V Badarkhe 6506a6f296SManish V Badarkhe if (comp->activator != NULL) { 6606a6f296SManish V Badarkhe flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL) 6706a6f296SManish V Badarkhe << LFA_MAY_RESET_CPU_SHIFT); 6806a6f296SManish V Badarkhe flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL) 6906a6f296SManish V Badarkhe << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT); 7006a6f296SManish V Badarkhe } 7106a6f296SManish V Badarkhe 7206a6f296SManish V Badarkhe return flags; 7306a6f296SManish V Badarkhe } 7406a6f296SManish V Badarkhe 753f7b2862SManish V Badarkhe static int lfa_cancel(uint32_t component_id) 763f7b2862SManish V Badarkhe { 773f7b2862SManish V Badarkhe int ret = LFA_SUCCESS; 783f7b2862SManish V Badarkhe 793f7b2862SManish V Badarkhe if (lfa_component_count == 0U) { 803f7b2862SManish V Badarkhe return LFA_WRONG_STATE; 813f7b2862SManish V Badarkhe } 823f7b2862SManish V Badarkhe 833f7b2862SManish V Badarkhe /* Check if component ID is in range. */ 843f7b2862SManish V Badarkhe if ((component_id >= lfa_component_count) || 853f7b2862SManish V Badarkhe (component_id != current_activation.component_id)) { 863f7b2862SManish V Badarkhe return LFA_INVALID_PARAMETERS; 873f7b2862SManish V Badarkhe } 883f7b2862SManish V Badarkhe 893f7b2862SManish V Badarkhe ret = plat_lfa_cancel(component_id); 903f7b2862SManish V Badarkhe if (ret != LFA_SUCCESS) { 913f7b2862SManish V Badarkhe return LFA_BUSY; 923f7b2862SManish V Badarkhe } 933f7b2862SManish V Badarkhe 943f7b2862SManish V Badarkhe /* TODO: add proper termination prime and activate phases */ 953f7b2862SManish V Badarkhe lfa_reset_activation(); 963f7b2862SManish V Badarkhe 973f7b2862SManish V Badarkhe return ret; 983f7b2862SManish V Badarkhe } 993f7b2862SManish V Badarkhe 100*07de22d2SManish V Badarkhe static int lfa_activate(uint32_t component_id, uint64_t flags, 101*07de22d2SManish V Badarkhe uint64_t ep_address, uint64_t context_id) 102*07de22d2SManish V Badarkhe { 103*07de22d2SManish V Badarkhe int ret = LFA_ACTIVATION_FAILED; 104*07de22d2SManish V Badarkhe struct lfa_component_ops *activator; 105*07de22d2SManish V Badarkhe 106*07de22d2SManish V Badarkhe if ((lfa_component_count == 0U) || 107*07de22d2SManish V Badarkhe (!lfa_components[component_id].activation_pending) || 108*07de22d2SManish V Badarkhe (current_activation.prime_status != PRIME_COMPLETE)) { 109*07de22d2SManish V Badarkhe return LFA_COMPONENT_WRONG_STATE; 110*07de22d2SManish V Badarkhe } 111*07de22d2SManish V Badarkhe 112*07de22d2SManish V Badarkhe /* Check if fw_seq_id is in range. */ 113*07de22d2SManish V Badarkhe if ((component_id >= lfa_component_count) || 114*07de22d2SManish V Badarkhe (current_activation.component_id != component_id)) { 115*07de22d2SManish V Badarkhe return LFA_INVALID_PARAMETERS; 116*07de22d2SManish V Badarkhe } 117*07de22d2SManish V Badarkhe 118*07de22d2SManish V Badarkhe if (lfa_components[component_id].activator == NULL) { 119*07de22d2SManish V Badarkhe return LFA_NOT_SUPPORTED; 120*07de22d2SManish V Badarkhe } 121*07de22d2SManish V Badarkhe 122*07de22d2SManish V Badarkhe activator = lfa_components[component_id].activator; 123*07de22d2SManish V Badarkhe if (activator->activate != NULL) { 124*07de22d2SManish V Badarkhe /* 125*07de22d2SManish V Badarkhe * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1 126*07de22d2SManish V Badarkhe * & CPU_RENDEZVOUS is not required. 127*07de22d2SManish V Badarkhe */ 128*07de22d2SManish V Badarkhe if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) { 129*07de22d2SManish V Badarkhe if (!activator->cpu_rendezvous_required) { 130*07de22d2SManish V Badarkhe INFO("Skipping rendezvous requested by caller.\n"); 131*07de22d2SManish V Badarkhe current_activation.cpu_rendezvous_required = false; 132*07de22d2SManish V Badarkhe } 133*07de22d2SManish V Badarkhe /* 134*07de22d2SManish V Badarkhe * Return error if caller tries to skip rendezvous when 135*07de22d2SManish V Badarkhe * it is required. 136*07de22d2SManish V Badarkhe */ 137*07de22d2SManish V Badarkhe else { 138*07de22d2SManish V Badarkhe ERROR("CPU Rendezvous is required, can't skip.\n"); 139*07de22d2SManish V Badarkhe return LFA_INVALID_PARAMETERS; 140*07de22d2SManish V Badarkhe } 141*07de22d2SManish V Badarkhe } 142*07de22d2SManish V Badarkhe 143*07de22d2SManish V Badarkhe ret = activator->activate(¤t_activation, ep_address, 144*07de22d2SManish V Badarkhe context_id); 145*07de22d2SManish V Badarkhe } 146*07de22d2SManish V Badarkhe 147*07de22d2SManish V Badarkhe lfa_components[component_id].activation_pending = false; 148*07de22d2SManish V Badarkhe 149*07de22d2SManish V Badarkhe return ret; 150*07de22d2SManish V Badarkhe } 151*07de22d2SManish V Badarkhe 15267fa182fSManish V Badarkhe static int lfa_prime(uint32_t component_id, uint64_t *flags) 15367fa182fSManish V Badarkhe { 15467fa182fSManish V Badarkhe int ret = LFA_SUCCESS; 15567fa182fSManish V Badarkhe struct lfa_component_ops *activator; 15667fa182fSManish V Badarkhe 15767fa182fSManish V Badarkhe if (lfa_component_count == 0U || 15867fa182fSManish V Badarkhe !lfa_components[component_id].activation_pending) { 15967fa182fSManish V Badarkhe return LFA_WRONG_STATE; 16067fa182fSManish V Badarkhe } 16167fa182fSManish V Badarkhe 16267fa182fSManish V Badarkhe /* Check if fw_seq_id is in range. */ 16367fa182fSManish V Badarkhe if (component_id >= lfa_component_count) { 16467fa182fSManish V Badarkhe return LFA_INVALID_PARAMETERS; 16567fa182fSManish V Badarkhe } 16667fa182fSManish V Badarkhe 16767fa182fSManish V Badarkhe if (lfa_components[component_id].activator == NULL) { 16867fa182fSManish V Badarkhe return LFA_NOT_SUPPORTED; 16967fa182fSManish V Badarkhe } 17067fa182fSManish V Badarkhe 17167fa182fSManish V Badarkhe switch (current_activation.prime_status) { 17267fa182fSManish V Badarkhe case PRIME_NONE: 17367fa182fSManish V Badarkhe current_activation.component_id = component_id; 17467fa182fSManish V Badarkhe current_activation.prime_status = PRIME_STARTED; 17567fa182fSManish V Badarkhe break; 17667fa182fSManish V Badarkhe 17767fa182fSManish V Badarkhe case PRIME_STARTED: 17867fa182fSManish V Badarkhe if (current_activation.component_id != component_id) { 17967fa182fSManish V Badarkhe /* Mismatched component trying to continue PRIME - error */ 18067fa182fSManish V Badarkhe return LFA_WRONG_STATE; 18167fa182fSManish V Badarkhe } 18267fa182fSManish V Badarkhe break; 18367fa182fSManish V Badarkhe 18467fa182fSManish V Badarkhe case PRIME_COMPLETE: 18567fa182fSManish V Badarkhe default: 18667fa182fSManish V Badarkhe break; 18767fa182fSManish V Badarkhe } 18867fa182fSManish V Badarkhe 18967fa182fSManish V Badarkhe ret = plat_lfa_load_auth_image(component_id); 19067fa182fSManish V Badarkhe ret = convert_to_lfa_error(ret); 19167fa182fSManish V Badarkhe 19267fa182fSManish V Badarkhe activator = lfa_components[component_id].activator; 19367fa182fSManish V Badarkhe if (activator->prime != NULL) { 19467fa182fSManish V Badarkhe ret = activator->prime(¤t_activation); 19567fa182fSManish V Badarkhe if (ret != LFA_SUCCESS) { 19667fa182fSManish V Badarkhe /* 19767fa182fSManish V Badarkhe * TODO: it should be LFA_PRIME_FAILED but specification 19867fa182fSManish V Badarkhe * has not define this error yet 19967fa182fSManish V Badarkhe */ 20067fa182fSManish V Badarkhe return ret; 20167fa182fSManish V Badarkhe } 20267fa182fSManish V Badarkhe } 20367fa182fSManish V Badarkhe 20467fa182fSManish V Badarkhe current_activation.prime_status = PRIME_COMPLETE; 20567fa182fSManish V Badarkhe 20667fa182fSManish V Badarkhe /* TODO: split this into multiple PRIME calls */ 20767fa182fSManish V Badarkhe *flags = 0ULL; 20867fa182fSManish V Badarkhe 20967fa182fSManish V Badarkhe return ret; 21067fa182fSManish V Badarkhe } 21167fa182fSManish V Badarkhe 212cf48f49fSManish V Badarkhe int lfa_setup(void) 213cf48f49fSManish V Badarkhe { 214b9dee50cSManish V Badarkhe is_lfa_initialized = lfa_initialize_components(); 215b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 216b9dee50cSManish V Badarkhe return -1; 217b9dee50cSManish V Badarkhe } 218b9dee50cSManish V Badarkhe 219b9dee50cSManish V Badarkhe lfa_reset_activation(); 220b9dee50cSManish V Badarkhe 221b9dee50cSManish V Badarkhe return 0; 222cf48f49fSManish V Badarkhe } 223cf48f49fSManish V Badarkhe 224cf48f49fSManish V Badarkhe uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 225cf48f49fSManish V Badarkhe u_register_t x3, u_register_t x4, void *cookie, 226cf48f49fSManish V Badarkhe void *handle, u_register_t flags) 227cf48f49fSManish V Badarkhe { 22806a6f296SManish V Badarkhe uint64_t retx1, retx2; 22967fa182fSManish V Badarkhe uint64_t lfa_flags; 23006a6f296SManish V Badarkhe uint8_t *uuid_p; 23106a6f296SManish V Badarkhe uint32_t fw_seq_id = (uint32_t)x1; 2323f7b2862SManish V Badarkhe int ret; 23306a6f296SManish V Badarkhe 234cf48f49fSManish V Badarkhe /** 235cf48f49fSManish V Badarkhe * TODO: Acquire serialization lock. 236cf48f49fSManish V Badarkhe */ 237b9dee50cSManish V Badarkhe 238b9dee50cSManish V Badarkhe if (!is_lfa_initialized) { 239b9dee50cSManish V Badarkhe return LFA_NOT_SUPPORTED; 240b9dee50cSManish V Badarkhe } 241b9dee50cSManish V Badarkhe 242cf48f49fSManish V Badarkhe switch (smc_fid) { 243cf48f49fSManish V Badarkhe case LFA_VERSION: 244cf48f49fSManish V Badarkhe SMC_RET1(handle, LFA_VERSION_VAL); 245cf48f49fSManish V Badarkhe break; 246cf48f49fSManish V Badarkhe 247cf48f49fSManish V Badarkhe case LFA_FEATURES: 248cf48f49fSManish V Badarkhe SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED); 249cf48f49fSManish V Badarkhe break; 250cf48f49fSManish V Badarkhe 251cf48f49fSManish V Badarkhe case LFA_GET_INFO: 252b9dee50cSManish V Badarkhe /** 253b9dee50cSManish V Badarkhe * The current specification limits this input parameter to be zero for 254b9dee50cSManish V Badarkhe * version 1.0 of LFA 255b9dee50cSManish V Badarkhe */ 256b9dee50cSManish V Badarkhe if (x1 == 0ULL) { 257b9dee50cSManish V Badarkhe SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0); 258b9dee50cSManish V Badarkhe } else { 259b9dee50cSManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 260b9dee50cSManish V Badarkhe } 261cf48f49fSManish V Badarkhe break; 262cf48f49fSManish V Badarkhe 263cf48f49fSManish V Badarkhe case LFA_GET_INVENTORY: 26406a6f296SManish V Badarkhe if (lfa_component_count == 0U) { 26506a6f296SManish V Badarkhe SMC_RET1(handle, LFA_WRONG_STATE); 26606a6f296SManish V Badarkhe } 26706a6f296SManish V Badarkhe 26806a6f296SManish V Badarkhe /* 26906a6f296SManish V Badarkhe * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan 27006a6f296SManish V Badarkhe * platform firmware and create a valid number of firmware components. 27106a6f296SManish V Badarkhe */ 27206a6f296SManish V Badarkhe if (fw_seq_id >= lfa_component_count) { 27306a6f296SManish V Badarkhe SMC_RET1(handle, LFA_INVALID_PARAMETERS); 27406a6f296SManish V Badarkhe } 27506a6f296SManish V Badarkhe 27606a6f296SManish V Badarkhe /* 27706a6f296SManish V Badarkhe * grab the UUID of asked fw_seq_id and set the return UUID 27806a6f296SManish V Badarkhe * variables 27906a6f296SManish V Badarkhe */ 28006a6f296SManish V Badarkhe uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid; 28106a6f296SManish V Badarkhe memcpy(&retx1, uuid_p, sizeof(uint64_t)); 28206a6f296SManish V Badarkhe memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t)); 28306a6f296SManish V Badarkhe 28406a6f296SManish V Badarkhe /* 28506a6f296SManish V Badarkhe * check the given fw_seq_id's update available 28606a6f296SManish V Badarkhe * and accordingly set the active_pending flag 28706a6f296SManish V Badarkhe */ 28806a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending = 28906a6f296SManish V Badarkhe is_plat_lfa_activation_pending(fw_seq_id); 29006a6f296SManish V Badarkhe 29106a6f296SManish V Badarkhe INFO("Component %lu %s live activation:\n", x1, 29206a6f296SManish V Badarkhe lfa_components[fw_seq_id].activator ? "supports" : 29306a6f296SManish V Badarkhe "does not support"); 29406a6f296SManish V Badarkhe 29506a6f296SManish V Badarkhe if (lfa_components[fw_seq_id].activator != NULL) { 29606a6f296SManish V Badarkhe INFO("Activation pending: %s\n", 29706a6f296SManish V Badarkhe lfa_components[fw_seq_id].activation_pending ? "true" : "false"); 29806a6f296SManish V Badarkhe } 29906a6f296SManish V Badarkhe 30006a6f296SManish V Badarkhe INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2); 30106a6f296SManish V Badarkhe 30206a6f296SManish V Badarkhe SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id)); 30306a6f296SManish V Badarkhe 304cf48f49fSManish V Badarkhe break; 305cf48f49fSManish V Badarkhe 306cf48f49fSManish V Badarkhe case LFA_PRIME: 30767fa182fSManish V Badarkhe ret = lfa_prime(x1, &lfa_flags); 30867fa182fSManish V Badarkhe if (ret != LFA_SUCCESS) { 30967fa182fSManish V Badarkhe SMC_RET1(handle, ret); 31067fa182fSManish V Badarkhe } else { 31167fa182fSManish V Badarkhe SMC_RET2(handle, ret, lfa_flags); 31267fa182fSManish V Badarkhe } 313cf48f49fSManish V Badarkhe break; 314cf48f49fSManish V Badarkhe 315cf48f49fSManish V Badarkhe case LFA_ACTIVATE: 316*07de22d2SManish V Badarkhe ret = lfa_activate(fw_seq_id, x2, x3, x4); 317*07de22d2SManish V Badarkhe /* TODO: implement activate again */ 318*07de22d2SManish V Badarkhe SMC_RET2(handle, ret, 0ULL); 319*07de22d2SManish V Badarkhe 320cf48f49fSManish V Badarkhe break; 321cf48f49fSManish V Badarkhe 322cf48f49fSManish V Badarkhe case LFA_CANCEL: 3233f7b2862SManish V Badarkhe ret = lfa_cancel(x1); 3243f7b2862SManish V Badarkhe SMC_RET1(handle, ret); 325cf48f49fSManish V Badarkhe break; 326cf48f49fSManish V Badarkhe 327cf48f49fSManish V Badarkhe default: 328cf48f49fSManish V Badarkhe WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid); 329cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 330cf48f49fSManish V Badarkhe break; /* unreachable */ 331cf48f49fSManish V Badarkhe 332cf48f49fSManish V Badarkhe } 333cf48f49fSManish V Badarkhe 334cf48f49fSManish V Badarkhe SMC_RET1(handle, SMC_UNK); 335cf48f49fSManish V Badarkhe 336cf48f49fSManish V Badarkhe return 0; 337cf48f49fSManish V Badarkhe } 338