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 bool lfa_initialize_components(void) 25 { 26 lfa_component_count = plat_lfa_get_components(&lfa_components); 27 28 if (lfa_component_count == 0U || lfa_components == NULL) { 29 /* unlikely to reach here */ 30 ERROR("Invalid LFA component setup: count = 0 or components are NULL"); 31 return false; 32 } 33 34 return true; 35 } 36 37 static uint64_t get_fw_activation_flags(uint32_t fw_seq_id) 38 { 39 const plat_lfa_component_info_t *comp = 40 &lfa_components[fw_seq_id]; 41 uint64_t flags = 0ULL; 42 43 flags |= ((comp->activator == NULL ? 0ULL : 1ULL) 44 << LFA_ACTIVATION_CAPABLE_SHIFT); 45 flags |= (uint64_t)(comp->activation_pending) 46 << LFA_ACTIVATION_PENDING_SHIFT; 47 48 if (comp->activator != NULL) { 49 flags |= ((comp->activator->may_reset_cpu ? 1ULL : 0ULL) 50 << LFA_MAY_RESET_CPU_SHIFT); 51 flags |= ((comp->activator->cpu_rendezvous_required ? 0ULL : 1ULL) 52 << LFA_CPU_RENDEZVOUS_OPTIONAL_SHIFT); 53 } 54 55 return flags; 56 } 57 58 static int lfa_cancel(uint32_t component_id) 59 { 60 int ret = LFA_SUCCESS; 61 62 if (lfa_component_count == 0U) { 63 return LFA_WRONG_STATE; 64 } 65 66 /* Check if component ID is in range. */ 67 if ((component_id >= lfa_component_count) || 68 (component_id != current_activation.component_id)) { 69 return LFA_INVALID_PARAMETERS; 70 } 71 72 ret = plat_lfa_cancel(component_id); 73 if (ret != LFA_SUCCESS) { 74 return LFA_BUSY; 75 } 76 77 /* TODO: add proper termination prime and activate phases */ 78 lfa_reset_activation(); 79 80 return ret; 81 } 82 83 int lfa_setup(void) 84 { 85 is_lfa_initialized = lfa_initialize_components(); 86 if (!is_lfa_initialized) { 87 return -1; 88 } 89 90 lfa_reset_activation(); 91 92 return 0; 93 } 94 95 uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 96 u_register_t x3, u_register_t x4, void *cookie, 97 void *handle, u_register_t flags) 98 { 99 uint64_t retx1, retx2; 100 uint8_t *uuid_p; 101 uint32_t fw_seq_id = (uint32_t)x1; 102 int ret; 103 104 /** 105 * TODO: Acquire serialization lock. 106 */ 107 108 if (!is_lfa_initialized) { 109 return LFA_NOT_SUPPORTED; 110 } 111 112 switch (smc_fid) { 113 case LFA_VERSION: 114 SMC_RET1(handle, LFA_VERSION_VAL); 115 break; 116 117 case LFA_FEATURES: 118 SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED); 119 break; 120 121 case LFA_GET_INFO: 122 /** 123 * The current specification limits this input parameter to be zero for 124 * version 1.0 of LFA 125 */ 126 if (x1 == 0ULL) { 127 SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0); 128 } else { 129 SMC_RET1(handle, LFA_INVALID_PARAMETERS); 130 } 131 break; 132 133 case LFA_GET_INVENTORY: 134 if (lfa_component_count == 0U) { 135 SMC_RET1(handle, LFA_WRONG_STATE); 136 } 137 138 /* 139 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan 140 * platform firmware and create a valid number of firmware components. 141 */ 142 if (fw_seq_id >= lfa_component_count) { 143 SMC_RET1(handle, LFA_INVALID_PARAMETERS); 144 } 145 146 /* 147 * grab the UUID of asked fw_seq_id and set the return UUID 148 * variables 149 */ 150 uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid; 151 memcpy(&retx1, uuid_p, sizeof(uint64_t)); 152 memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t)); 153 154 /* 155 * check the given fw_seq_id's update available 156 * and accordingly set the active_pending flag 157 */ 158 lfa_components[fw_seq_id].activation_pending = 159 is_plat_lfa_activation_pending(fw_seq_id); 160 161 INFO("Component %lu %s live activation:\n", x1, 162 lfa_components[fw_seq_id].activator ? "supports" : 163 "does not support"); 164 165 if (lfa_components[fw_seq_id].activator != NULL) { 166 INFO("Activation pending: %s\n", 167 lfa_components[fw_seq_id].activation_pending ? "true" : "false"); 168 } 169 170 INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2); 171 172 SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id)); 173 174 break; 175 176 case LFA_PRIME: 177 break; 178 179 case LFA_ACTIVATE: 180 break; 181 182 case LFA_CANCEL: 183 ret = lfa_cancel(x1); 184 SMC_RET1(handle, ret); 185 break; 186 187 default: 188 WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid); 189 SMC_RET1(handle, SMC_UNK); 190 break; /* unreachable */ 191 192 } 193 194 SMC_RET1(handle, SMC_UNK); 195 196 return 0; 197 } 198