blob: a5de62412cf3714e0f4c9ea661ee19794f12d89d [file] [log] [blame]
Michal Simekb96f77c2015-06-15 14:22:50 +02001/*
2 * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch_helpers.h>
32#include <assert.h>
33#include <debug.h>
34#include <mmio.h>
35#include "zynqmp_def.h"
36
37/*
38 * ATFHandoffParams
39 * Parameter bitfield encoding
40 * -----------------------------------------------------------------------------
41 * Exec State 0 0 -> Aarch64, 1-> Aarch32
Soren Brinkmann55eae0d2016-05-29 09:48:26 -070042 * endianness 1 0 -> LE, 1 -> BE
Michal Simekb96f77c2015-06-15 14:22:50 +020043 * secure (TZ) 2 0 -> Non secure, 1 -> secure
44 * EL 3:4 00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
45 * CPU# 5:6 00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
46 */
47
48#define FSBL_FLAGS_ESTATE_SHIFT 0
49#define FSBL_FLAGS_ESTATE_MASK (1 << FSBL_FLAGS_ESTATE_SHIFT)
50#define FSBL_FLAGS_ESTATE_A64 0
51#define FSBL_FLAGS_ESTATE_A32 1
52
53#define FSBL_FLAGS_ENDIAN_SHIFT 1
54#define FSBL_FLAGS_ENDIAN_MASK (1 << FSBL_FLAGS_ENDIAN_SHIFT)
55#define FSBL_FLAGS_ENDIAN_LE 0
56#define FSBL_FLAGS_ENDIAN_BE 1
57
58#define FSBL_FLAGS_TZ_SHIFT 2
59#define FSBL_FLAGS_TZ_MASK (1 << FSBL_FLAGS_TZ_SHIFT)
60#define FSBL_FLAGS_NON_SECURE 0
61#define FSBL_FLAGS_SECURE 1
62
63#define FSBL_FLAGS_EL_SHIFT 3
64#define FSBL_FLAGS_EL_MASK (3 << FSBL_FLAGS_EL_SHIFT)
65#define FSBL_FLAGS_EL0 0
66#define FSBL_FLAGS_EL1 1
67#define FSBL_FLAGS_EL2 2
68#define FSBL_FLAGS_EL3 3
69
70#define FSBL_FLAGS_CPU_SHIFT 5
71#define FSBL_FLAGS_CPU_MASK (3 << FSBL_FLAGS_CPU_SHIFT)
72#define FSBL_FLAGS_A53_0 0
73#define FSBL_FLAGS_A53_1 1
74#define FSBL_FLAGS_A53_2 2
75#define FSBL_FLAGS_A53_3 3
76
77#define FSBL_MAX_PARTITIONS 8
78
79/* Structure corresponding to each partition entry */
80struct xfsbl_partition {
81 uint64_t entry_point;
82 uint64_t flags;
83};
84
85/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */
86struct xfsbl_atf_handoff_params {
87 uint8_t magic[4];
88 uint32_t num_entries;
89 struct xfsbl_partition partition[FSBL_MAX_PARTITIONS];
90};
91
92/**
93 * @partition: Pointer to partition struct
94 *
95 * Get the target CPU for @partition.
96 *
97 * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3
98 */
99static int get_fsbl_cpu(const struct xfsbl_partition *partition)
100{
101 uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK;
102
103 return flags >> FSBL_FLAGS_CPU_SHIFT;
104}
105
106/**
107 * @partition: Pointer to partition struct
108 *
109 * Get the target exception level for @partition.
110 *
111 * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3
112 */
113static int get_fsbl_el(const struct xfsbl_partition *partition)
114{
115 uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK;
116
117 return flags >> FSBL_FLAGS_EL_SHIFT;;
118}
119
120/**
121 * @partition: Pointer to partition struct
122 *
123 * Get the target security state for @partition.
124 *
125 * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE
126 */
127static int get_fsbl_ss(const struct xfsbl_partition *partition)
128{
129 uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK;
130
131 return flags >> FSBL_FLAGS_TZ_SHIFT;
132}
133
134/**
135 * @partition: Pointer to partition struct
136 *
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700137 * Get the target endianness for @partition.
Michal Simekb96f77c2015-06-15 14:22:50 +0200138 *
139 * Return: SPSR_E_LITTLE or SPSR_E_BIG
140 */
141static int get_fsbl_endian(const struct xfsbl_partition *partition)
142{
143 uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK;
144
145 flags >>= FSBL_FLAGS_ENDIAN_SHIFT;
146
147 if (flags == FSBL_FLAGS_ENDIAN_BE)
148 return SPSR_E_BIG;
149 else
150 return SPSR_E_LITTLE;
151}
152
153/**
154 * @partition: Pointer to partition struct
155 *
156 * Get the target execution state for @partition.
157 *
158 * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64
159 */
160static int get_fsbl_estate(const struct xfsbl_partition *partition)
161{
162 uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK;
163
164 return flags >> FSBL_FLAGS_ESTATE_SHIFT;
165}
166
167/**
168 * Populates the bl32 and bl33 image info structures
169 * @bl32: BL32 image info structure
170 * @bl33: BL33 image info structure
171 *
172 * Process the handoff paramters from the FSBL and populate the BL32 and BL33
173 * image info structures accordingly.
174 */
175void fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33)
176{
177 uint64_t atf_handoff_addr;
178 const struct xfsbl_atf_handoff_params *ATFHandoffParams;
179
180 atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
181 assert((atf_handoff_addr < BL31_BASE) ||
182 (atf_handoff_addr > (uint64_t)&__BL31_END__));
183 if (!atf_handoff_addr) {
184 ERROR("BL31: No ATF handoff structure passed\n");
185 panic();
186 }
187
188 ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr;
189 if ((ATFHandoffParams->magic[0] != 'X') ||
190 (ATFHandoffParams->magic[1] != 'L') ||
191 (ATFHandoffParams->magic[2] != 'N') ||
192 (ATFHandoffParams->magic[3] != 'X')) {
193 ERROR("BL31: invalid ATF handoff structure at %lx\n",
194 atf_handoff_addr);
195 panic();
196 }
197
198 VERBOSE("BL31: ATF handoff params at:0x%lx, entries:%u\n",
199 atf_handoff_addr, ATFHandoffParams->num_entries);
200 if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) {
201 ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n",
202 ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS);
203 panic();
204 }
205
206 /*
207 * we loop over all passed entries but only populate two image structs
208 * (bl32, bl33). I.e. the last applicable images in the handoff
209 * structure will be used for the hand off
210 */
211 for (size_t i = 0; i < ATFHandoffParams->num_entries; i++) {
212 entry_point_info_t *image;
213 int target_estate, target_secure;
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700214 int target_cpu, target_endianness, target_el;
Michal Simekb96f77c2015-06-15 14:22:50 +0200215
216 VERBOSE("BL31: %zd: entry:0x%lx, flags:0x%lx\n", i,
217 ATFHandoffParams->partition[i].entry_point,
218 ATFHandoffParams->partition[i].flags);
219
220 target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]);
221 if (target_cpu != FSBL_FLAGS_A53_0) {
222 WARN("BL31: invalid target CPU (%i)\n", target_cpu);
223 continue;
224 }
225
226 target_el = get_fsbl_el(&ATFHandoffParams->partition[i]);
227 if ((target_el == FSBL_FLAGS_EL3) ||
228 (target_el == FSBL_FLAGS_EL0)) {
229 WARN("BL31: invalid exception level (%i)\n", target_el);
230 continue;
231 }
232
233 target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]);
234 if (target_secure == FSBL_FLAGS_SECURE &&
235 target_el == FSBL_FLAGS_EL2) {
236 WARN("BL31: invalid security state (%i) for exception level (%i)\n",
237 target_secure, target_el);
238 continue;
239 }
240
241 target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]);
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700242 target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]);
Michal Simekb96f77c2015-06-15 14:22:50 +0200243
244 if (target_secure == FSBL_FLAGS_SECURE) {
245 image = bl32;
246
247 if (target_estate == FSBL_FLAGS_ESTATE_A32)
248 bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700249 target_endianness,
Michal Simekb96f77c2015-06-15 14:22:50 +0200250 DISABLE_ALL_EXCEPTIONS);
251 else
252 bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
253 DISABLE_ALL_EXCEPTIONS);
254 } else {
255 image = bl33;
256
257 if (target_estate == FSBL_FLAGS_ESTATE_A32) {
258 if (target_el == FSBL_FLAGS_EL2)
259 target_el = MODE32_hyp;
260 else
261 target_el = MODE32_sys;
262
263 bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM,
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700264 target_endianness,
Michal Simekb96f77c2015-06-15 14:22:50 +0200265 DISABLE_ALL_EXCEPTIONS);
266 } else {
267 if (target_el == FSBL_FLAGS_EL2)
268 target_el = MODE_EL2;
269 else
270 target_el = MODE_EL1;
271
272 bl33->spsr = SPSR_64(target_el, MODE_SP_ELX,
273 DISABLE_ALL_EXCEPTIONS);
274 }
275 }
276
277 VERBOSE("Setting up %s entry point to:%lx, el:%x\n",
278 target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33",
279 ATFHandoffParams->partition[i].entry_point,
280 target_el);
281 image->pc = ATFHandoffParams->partition[i].entry_point;
282
Soren Brinkmann55eae0d2016-05-29 09:48:26 -0700283 if (target_endianness == SPSR_E_BIG)
Michal Simekb96f77c2015-06-15 14:22:50 +0200284 EP_SET_EE(image->h.attr, EP_EE_BIG);
285 else
286 EP_SET_EE(image->h.attr, EP_EE_LITTLE);
287 }
288}