xref: /rk3399_ARM-atf/plat/xilinx/common/plat_startup.c (revision 83a4dae1af916b938659b39b7d0884359c638185)
1 /*
2  * Copyright (c) 2014-2020, Arm Limited and Contributors. All rights reserved.
3  * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <assert.h>
9 #include <inttypes.h>
10 #include <stdint.h>
11 
12 #include <arch_helpers.h>
13 #include <common/debug.h>
14 #include <plat_startup.h>
15 
16 
17 /*
18  * TFAHandoffParams
19  * Parameter		bitfield	encoding
20  * -----------------------------------------------------------------------------
21  * Exec State		0		0 -> Aarch64, 1-> Aarch32
22  * endianness		1		0 -> LE, 1 -> BE
23  * secure (TZ)		2		0 -> Non secure, 1 -> secure
24  * EL			3:4		00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
25  * CPU#			5:6		00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
26  */
27 
28 #define FSBL_FLAGS_ESTATE_SHIFT		0U
29 #define FSBL_FLAGS_ESTATE_MASK		(1U << FSBL_FLAGS_ESTATE_SHIFT)
30 #define FSBL_FLAGS_ESTATE_A64		0U
31 #define FSBL_FLAGS_ESTATE_A32		1U
32 
33 #define FSBL_FLAGS_ENDIAN_SHIFT		1U
34 #define FSBL_FLAGS_ENDIAN_MASK		(1U << FSBL_FLAGS_ENDIAN_SHIFT)
35 #define FSBL_FLAGS_ENDIAN_LE		0U
36 #define FSBL_FLAGS_ENDIAN_BE		1U
37 
38 #define FSBL_FLAGS_TZ_SHIFT		2U
39 #define FSBL_FLAGS_TZ_MASK		(1U << FSBL_FLAGS_TZ_SHIFT)
40 #define FSBL_FLAGS_NON_SECURE		0U
41 #define FSBL_FLAGS_SECURE		1U
42 
43 #define FSBL_FLAGS_EL_SHIFT		3U
44 #define FSBL_FLAGS_EL_MASK		(3U << FSBL_FLAGS_EL_SHIFT)
45 #define FSBL_FLAGS_EL0			0U
46 #define FSBL_FLAGS_EL1			1U
47 #define FSBL_FLAGS_EL2			2U
48 #define FSBL_FLAGS_EL3			3U
49 
50 #define FSBL_FLAGS_CPU_SHIFT		5U
51 #define FSBL_FLAGS_CPU_MASK		(3U << FSBL_FLAGS_CPU_SHIFT)
52 #define FSBL_FLAGS_A53_0		0U
53 #define FSBL_FLAGS_A53_1		1U
54 #define FSBL_FLAGS_A53_2		2U
55 #define FSBL_FLAGS_A53_3		3U
56 
57 /**
58  * get_fsbl_cpu() - Get the target CPU for partition.
59  * @partition: Pointer to partition struct.
60  *
61  * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or
62  *         FSBL_FLAGS_A53_3.
63  *
64  */
65 static int32_t get_fsbl_cpu(const struct xfsbl_partition *partition)
66 {
67 	uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK;
68 
69 	return flags >> FSBL_FLAGS_CPU_SHIFT;
70 }
71 
72 /**
73  * get_fsbl_el() - Get the target exception level for partition.
74  * @partition: Pointer to partition struct.
75  *
76  * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3.
77  *
78  */
79 static int32_t get_fsbl_el(const struct xfsbl_partition *partition)
80 {
81 	uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK;
82 
83 	return flags >> FSBL_FLAGS_EL_SHIFT;
84 }
85 
86 /**
87  * get_fsbl_ss() - Get the target security state for partition.
88  * @partition: Pointer to partition struct.
89  *
90  * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE.
91  *
92  */
93 static int32_t get_fsbl_ss(const struct xfsbl_partition *partition)
94 {
95 	uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK;
96 
97 	return flags >> FSBL_FLAGS_TZ_SHIFT;
98 }
99 
100 /**
101  * get_fsbl_endian() - Get the target endianness for partition.
102  * @partition: Pointer to partition struct.
103  *
104  * Return: SPSR_E_LITTLE or SPSR_E_BIG.
105  *
106  */
107 static int32_t get_fsbl_endian(const struct xfsbl_partition *partition)
108 {
109 	uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK;
110 
111 	flags >>= FSBL_FLAGS_ENDIAN_SHIFT;
112 
113 	if (flags == FSBL_FLAGS_ENDIAN_BE) {
114 		return SPSR_E_BIG;
115 	} else {
116 		return SPSR_E_LITTLE;
117 	}
118 }
119 
120 /**
121  * get_fsbl_estate() - Get the target execution state for partition.
122  * @partition: Pointer to partition struct.
123  *
124  * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64.
125  *
126  */
127 static int32_t get_fsbl_estate(const struct xfsbl_partition *partition)
128 {
129 	uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK;
130 
131 	return flags >> FSBL_FLAGS_ESTATE_SHIFT;
132 }
133 
134 /**
135  * fsbl_tfa_handover() - Populates the bl32 and bl33 image info structures.
136  * @bl32: BL32 image info structure.
137  * @bl33: BL33 image info structure.
138  * @tfa_handoff_addr: TF-A handoff address.
139  *
140  * Process the handoff parameters from the FSBL and populate the BL32 and BL33
141  * image info structures accordingly.
142  *
143  * Return: Return the status of the handoff. The value will be from the
144  *         fsbl_handoff enum.
145  *
146  */
147 enum fsbl_handoff fsbl_tfa_handover(entry_point_info_t *bl32,
148 					entry_point_info_t *bl33,
149 					uint64_t tfa_handoff_addr)
150 {
151 	const struct xfsbl_tfa_handoff_params *TFAHandoffParams;
152 	if (!tfa_handoff_addr) {
153 		WARN("BL31: No TFA handoff structure passed\n");
154 		return FSBL_HANDOFF_NO_STRUCT;
155 	}
156 
157 	TFAHandoffParams = (struct xfsbl_tfa_handoff_params *)tfa_handoff_addr;
158 	if ((TFAHandoffParams->magic[0] != 'X') ||
159 	    (TFAHandoffParams->magic[1] != 'L') ||
160 	    (TFAHandoffParams->magic[2] != 'N') ||
161 	    (TFAHandoffParams->magic[3] != 'X')) {
162 		ERROR("BL31: invalid TF-A handoff structure at %" PRIx64 "\n",
163 		      tfa_handoff_addr);
164 		return FSBL_HANDOFF_INVAL_STRUCT;
165 	}
166 
167 	VERBOSE("BL31: TF-A handoff params at:0x%" PRIx64 ", entries:%u\n",
168 		tfa_handoff_addr, TFAHandoffParams->num_entries);
169 	if (TFAHandoffParams->num_entries > FSBL_MAX_PARTITIONS) {
170 		ERROR("BL31: TF-A handoff params: too many partitions (%u/%u)\n",
171 		      TFAHandoffParams->num_entries, FSBL_MAX_PARTITIONS);
172 		return FSBL_HANDOFF_TOO_MANY_PARTS;
173 	}
174 
175 	/*
176 	 * we loop over all passed entries but only populate two image structs
177 	 * (bl32, bl33). I.e. the last applicable images in the handoff
178 	 * structure will be used for the hand off
179 	 */
180 	for (size_t i = 0; i < TFAHandoffParams->num_entries; i++) {
181 		entry_point_info_t *image;
182 		int32_t target_estate, target_secure, target_cpu;
183 		uint32_t target_endianness, target_el;
184 
185 		VERBOSE("BL31: %zd: entry:0x%" PRIx64 ", flags:0x%" PRIx64 "\n", i,
186 			TFAHandoffParams->partition[i].entry_point,
187 			TFAHandoffParams->partition[i].flags);
188 
189 		target_cpu = get_fsbl_cpu(&TFAHandoffParams->partition[i]);
190 		if (target_cpu != FSBL_FLAGS_A53_0) {
191 			WARN("BL31: invalid target CPU (%i)\n", target_cpu);
192 			continue;
193 		}
194 
195 		target_el = get_fsbl_el(&TFAHandoffParams->partition[i]);
196 		if ((target_el == FSBL_FLAGS_EL3) ||
197 		    (target_el == FSBL_FLAGS_EL0)) {
198 			WARN("BL31: invalid exception level (%i)\n", target_el);
199 			continue;
200 		}
201 
202 		target_secure = get_fsbl_ss(&TFAHandoffParams->partition[i]);
203 		if (target_secure == FSBL_FLAGS_SECURE &&
204 		    target_el == FSBL_FLAGS_EL2) {
205 			WARN("BL31: invalid security state (%i) for exception level (%i)\n",
206 			     target_secure, target_el);
207 			continue;
208 		}
209 
210 		target_estate = get_fsbl_estate(&TFAHandoffParams->partition[i]);
211 		target_endianness = get_fsbl_endian(&TFAHandoffParams->partition[i]);
212 
213 		if (target_secure == FSBL_FLAGS_SECURE) {
214 			image = bl32;
215 
216 			if (target_estate == FSBL_FLAGS_ESTATE_A32) {
217 				bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
218 							 target_endianness,
219 							 DISABLE_ALL_EXCEPTIONS);
220 			} else {
221 				bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
222 						     DISABLE_ALL_EXCEPTIONS);
223 			}
224 		} else {
225 			image = bl33;
226 
227 			if (target_estate == FSBL_FLAGS_ESTATE_A32) {
228 				if (target_el == FSBL_FLAGS_EL2) {
229 					target_el = MODE32_hyp;
230 				} else {
231 					target_el = MODE32_sys;
232 				}
233 
234 				bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM,
235 							 target_endianness,
236 							 DISABLE_ALL_EXCEPTIONS);
237 			} else {
238 				if (target_el == FSBL_FLAGS_EL2) {
239 					target_el = MODE_EL2;
240 				} else {
241 					target_el = MODE_EL1;
242 				}
243 
244 				bl33->spsr = SPSR_64(target_el, MODE_SP_ELX,
245 						     DISABLE_ALL_EXCEPTIONS);
246 			}
247 		}
248 
249 		VERBOSE("Setting up %s entry point to:%" PRIx64 ", el:%x\n",
250 			target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33",
251 			TFAHandoffParams->partition[i].entry_point,
252 			target_el);
253 		image->pc = TFAHandoffParams->partition[i].entry_point;
254 
255 		if (target_endianness == SPSR_E_BIG) {
256 			EP_SET_EE(image->h.attr, EP_EE_BIG);
257 		} else {
258 			EP_SET_EE(image->h.attr, EP_EE_LITTLE);
259 		}
260 	}
261 
262 	return FSBL_HANDOFF_SUCCESS;
263 }
264