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 int lfa_setup(void) 59 { 60 is_lfa_initialized = lfa_initialize_components(); 61 if (!is_lfa_initialized) { 62 return -1; 63 } 64 65 lfa_reset_activation(); 66 67 return 0; 68 } 69 70 uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, 71 u_register_t x3, u_register_t x4, void *cookie, 72 void *handle, u_register_t flags) 73 { 74 uint64_t retx1, retx2; 75 uint8_t *uuid_p; 76 uint32_t fw_seq_id = (uint32_t)x1; 77 78 /** 79 * TODO: Acquire serialization lock. 80 */ 81 82 if (!is_lfa_initialized) { 83 return LFA_NOT_SUPPORTED; 84 } 85 86 switch (smc_fid) { 87 case LFA_VERSION: 88 SMC_RET1(handle, LFA_VERSION_VAL); 89 break; 90 91 case LFA_FEATURES: 92 SMC_RET1(handle, is_lfa_fid(x1) ? LFA_SUCCESS : LFA_NOT_SUPPORTED); 93 break; 94 95 case LFA_GET_INFO: 96 /** 97 * The current specification limits this input parameter to be zero for 98 * version 1.0 of LFA 99 */ 100 if (x1 == 0ULL) { 101 SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0); 102 } else { 103 SMC_RET1(handle, LFA_INVALID_PARAMETERS); 104 } 105 break; 106 107 case LFA_GET_INVENTORY: 108 if (lfa_component_count == 0U) { 109 SMC_RET1(handle, LFA_WRONG_STATE); 110 } 111 112 /* 113 * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan 114 * platform firmware and create a valid number of firmware components. 115 */ 116 if (fw_seq_id >= lfa_component_count) { 117 SMC_RET1(handle, LFA_INVALID_PARAMETERS); 118 } 119 120 /* 121 * grab the UUID of asked fw_seq_id and set the return UUID 122 * variables 123 */ 124 uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid; 125 memcpy(&retx1, uuid_p, sizeof(uint64_t)); 126 memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t)); 127 128 /* 129 * check the given fw_seq_id's update available 130 * and accordingly set the active_pending flag 131 */ 132 lfa_components[fw_seq_id].activation_pending = 133 is_plat_lfa_activation_pending(fw_seq_id); 134 135 INFO("Component %lu %s live activation:\n", x1, 136 lfa_components[fw_seq_id].activator ? "supports" : 137 "does not support"); 138 139 if (lfa_components[fw_seq_id].activator != NULL) { 140 INFO("Activation pending: %s\n", 141 lfa_components[fw_seq_id].activation_pending ? "true" : "false"); 142 } 143 144 INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2); 145 146 SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id)); 147 148 break; 149 150 case LFA_PRIME: 151 break; 152 153 case LFA_ACTIVATE: 154 break; 155 156 case LFA_CANCEL: 157 break; 158 159 default: 160 WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid); 161 SMC_RET1(handle, SMC_UNK); 162 break; /* unreachable */ 163 164 } 165 166 SMC_RET1(handle, SMC_UNK); 167 168 return 0; 169 } 170