xref: /rk3399_ARM-atf/services/std_svc/lfa/lfa_main.c (revision e4d0622c7e9a259a28172a1dfcf5bc4f38ca8594)
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(&current_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(&current_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