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