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