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