1 /*
2 * Reference to the ARM TF Project,
3 * plat/arm/common/arm_bl2_setup.c
4 * Portions copyright (c) 2013-2016, ARM Limited and Contributors. All rights
5 * reserved.
6 * Copyright (C) 2016 Rockchip Electronic Co.,Ltd
7 * Written by Kever Yang <kever.yang@rock-chips.com>
8 * Copyright (C) 2017 Theobroma Systems Design und Consulting GmbH
9 *
10 * SPDX-License-Identifier: BSD-3-Clause
11 */
12
13 #include <common.h>
14 #include <atf_common.h>
15 #include <errno.h>
16 #include <spl.h>
17
18 static struct bl2_to_bl31_params_mem bl31_params_mem;
19 static struct bl31_params *bl2_to_bl31_params;
20
21 /**
22 * bl2_plat_get_bl31_params() - prepare params for bl31.
23 *
24 * This function assigns a pointer to the memory that the platform has kept
25 * aside to pass platform specific and trusted firmware related information
26 * to BL31. This memory is allocated by allocating memory to
27 * bl2_to_bl31_params_mem structure which is a superset of all the
28 * structure whose information is passed to BL31
29 * NOTE: This function should be called only once and should be done
30 * before generating params to BL31
31 *
32 * @return bl31 params structure pointer
33 */
bl2_plat_get_bl31_params(struct spl_image_info * spl_image,uintptr_t bl32_entry,uintptr_t bl33_entry)34 static struct bl31_params *bl2_plat_get_bl31_params(struct spl_image_info *spl_image,
35 uintptr_t bl32_entry,
36 uintptr_t bl33_entry)
37 {
38 struct entry_point_info *bl32_ep_info;
39 struct entry_point_info *bl33_ep_info;
40
41 /*
42 * Initialise the memory for all the arguments that needs to
43 * be passed to BL31
44 */
45 memset(&bl31_params_mem, 0, sizeof(struct bl2_to_bl31_params_mem));
46
47 /* Assign memory for TF related information */
48 bl2_to_bl31_params = &bl31_params_mem.bl31_params;
49 SET_PARAM_HEAD(bl2_to_bl31_params, ATF_PARAM_BL31, ATF_VERSION_1, 0);
50
51 /* Fill BL31 related information */
52 SET_PARAM_HEAD(bl2_to_bl31_params->bl31_image_info,
53 ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
54
55 /* Fill BL32 related information */
56 bl2_to_bl31_params->bl32_ep_info = &bl31_params_mem.bl32_ep_info;
57 bl32_ep_info = &bl31_params_mem.bl32_ep_info;
58 SET_PARAM_HEAD(bl32_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
59 ATF_EP_SECURE);
60
61 bl32_ep_info->pc = bl32_entry == -1 ? 0 : bl32_entry;
62 bl32_ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
63 DISABLE_ALL_EXECPTIONS);
64
65 bl2_to_bl31_params->bl32_image_info = &bl31_params_mem.bl32_image_info;
66 SET_PARAM_HEAD(bl2_to_bl31_params->bl32_image_info,
67 ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
68
69 /* Fill BL33 related information */
70 bl2_to_bl31_params->bl33_ep_info = &bl31_params_mem.bl33_ep_info;
71 bl33_ep_info = &bl31_params_mem.bl33_ep_info;
72 SET_PARAM_HEAD(bl33_ep_info, ATF_PARAM_EP, ATF_VERSION_1,
73 ATF_EP_NON_SECURE);
74
75 /* BL33 expects to receive the primary CPU MPID (through x0) */
76 bl33_ep_info->args.arg0 = 0xffff & read_mpidr();
77 bl33_ep_info->pc = bl33_entry;
78
79 if (spl_image->flags & SPL_ATF_AARCH32_BL33) {
80 bl33_ep_info->spsr = SPSR_32(MODE32_svc, SPSR_T_ARM, EP_EE_LITTLE,
81 DISABLE_ALL_EXECPTIONS_32);
82
83 /*
84 * r1 - machine type
85 * r2 - boot data (atags/dt) pointer
86 */
87 if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL) {
88 bl33_ep_info->args.arg0 = 0;
89 bl33_ep_info->args.arg1 = 0xffffffff;
90 bl33_ep_info->args.arg2 = (unsigned long)spl_image->fdt_addr;
91 }
92 } else {
93 bl33_ep_info->spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
94 DISABLE_ALL_EXECPTIONS);
95
96 /*
97 * Reference: arch/arm/lib/bootm.c
98 * boot_jump_linux(bootm_headers_t *images, int flag)
99 * {
100 * ......
101 * armv8_switch_to_el2((u64)images->ft_addr, 0, 0, 0,
102 * images->ep, ES_TO_AARCH64);
103 * }
104 */
105 if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL)
106 bl33_ep_info->args.arg0 = (unsigned long)spl_image->fdt_addr;
107 }
108
109 bl2_to_bl31_params->bl33_image_info = &bl31_params_mem.bl33_image_info;
110 SET_PARAM_HEAD(bl2_to_bl31_params->bl33_image_info,
111 ATF_PARAM_IMAGE_BINARY, ATF_VERSION_1, 0);
112
113 return bl2_to_bl31_params;
114 }
115
raw_write_daif(unsigned int daif)116 static inline void raw_write_daif(unsigned int daif)
117 {
118 __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory");
119 }
120
121 typedef void (*atf_entry_t)(struct bl31_params *params, void *plat_params);
122
bl31_entry(struct spl_image_info * spl_image,uintptr_t bl31_entry,uintptr_t bl32_entry,uintptr_t bl33_entry,uintptr_t fdt_addr)123 void bl31_entry(struct spl_image_info *spl_image,
124 uintptr_t bl31_entry, uintptr_t bl32_entry,
125 uintptr_t bl33_entry, uintptr_t fdt_addr)
126 {
127 struct bl31_params *bl31_params;
128 atf_entry_t atf_entry = (atf_entry_t)bl31_entry;
129
130 bl31_params = bl2_plat_get_bl31_params(spl_image, bl32_entry, bl33_entry);
131
132 atf_entry((void *)bl31_params, (void *)fdt_addr);
133 }
134
spl_fit_images_find(void * blob,int os)135 static int spl_fit_images_find(void *blob, int os)
136 {
137 int parent, node;
138 const void *data;
139
140 if (!blob)
141 return -FDT_ERR_BADMAGIC;
142
143 parent = fdt_path_offset(blob, "/fit-images");
144 if (parent < 0)
145 return -FDT_ERR_NOTFOUND;
146
147 fdt_for_each_subnode(node, blob, parent) {
148 data = fdt_getprop(blob, node, FIT_OS_PROP, NULL);
149 if (!data)
150 continue;
151
152 if (genimg_get_os_id(data) == os)
153 return node;
154 }
155
156 return -FDT_ERR_NOTFOUND;
157 }
158
spl_fit_images_get_entry(void * blob,int node)159 uintptr_t spl_fit_images_get_entry(void *blob, int node)
160 {
161 ulong val;
162
163 val = fdt_getprop_u32(blob, node, "entry-point");
164 if (val == FDT_ERROR)
165 val = fdt_getprop_u32(blob, node, "load-addr");
166
167 debug("%s: entry point 0x%lx\n", __func__, val);
168 return val;
169 }
170
spl_invoke_atf(struct spl_image_info * spl_image)171 void spl_invoke_atf(struct spl_image_info *spl_image)
172 {
173 uintptr_t bl32_entry, bl33_entry;
174 void *blob = spl_image->fdt_addr;
175 uintptr_t platform_param = (uintptr_t)blob;
176 int node;
177
178 /*
179 * Find the OP-TEE binary (in /fit-images) load address or
180 * entry point (if different) and pass it as the BL3-2 entry
181 * point, this is optional.
182 * This will need to be extended to support Falcon mode.
183 */
184 node = spl_fit_images_find(blob, IH_OS_OP_TEE);
185 if (node >= 0)
186 bl32_entry = spl_fit_images_get_entry(blob, node);
187 else
188 bl32_entry = spl_image->entry_point_bl32; /* optional */
189
190 /*
191 * Find the U-Boot binary (in /fit-images) load addreess or
192 * entry point (if different) and pass it as the BL3-3 entry
193 * point.
194 * This will need to be extended to support Falcon mode.
195 */
196 node = spl_fit_images_find(blob, IH_OS_U_BOOT);
197 if (node >= 0)
198 bl33_entry = spl_fit_images_get_entry(blob, node);
199 else
200 bl33_entry = spl_image->entry_point_bl33;
201
202 /*
203 * If ATF_NO_PLATFORM_PARAM is set, we override the platform
204 * parameter and always pass 0. This is a workaround for
205 * older ATF versions that have insufficiently robust (or
206 * overzealous) argument validation.
207 */
208 if (CONFIG_IS_ENABLED(ATF_NO_PLATFORM_PARAM))
209 platform_param = 0;
210
211 /* do cleanup */
212 spl_cleanup_before_jump(spl_image);
213
214 /*
215 * We don't provide a BL3-2 entry yet, but this will be possible
216 * using similar logic.
217 */
218 bl31_entry(spl_image, spl_image->entry_point, bl32_entry,
219 bl33_entry, platform_param);
220 }
221