1 /*
2 * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <string.h>
9
10 #include <arch.h>
11 #include <arch_helpers.h>
12 #include <common/debug.h>
13 #include <common/fdt_wrappers.h>
14 #include <context.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/utils.h>
17 #include <lib/xlat_tables/xlat_tables_v2.h>
18 #include <libfdt.h>
19 #include <plat/common/common_def.h>
20 #include <plat/common/platform.h>
21 #include <services/ffa_svc.h>
22 #include "spm_common.h"
23 #include "spmc.h"
24 #include <tools_share/firmware_image_package.h>
25
26 #include <platform_def.h>
27
28 /*
29 * Statically allocate a page of memory for passing boot information to an SP.
30 */
31 static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE);
32
33 /*
34 * This function creates a initialization descriptor in the memory reserved
35 * for passing boot information to an SP. It then copies the partition manifest
36 * into this region and ensures that its reference in the initialization
37 * descriptor is updated.
38 */
spmc_create_boot_info(entry_point_info_t * ep_info,struct secure_partition_desc * sp)39 static void spmc_create_boot_info(entry_point_info_t *ep_info,
40 struct secure_partition_desc *sp)
41 {
42 struct ffa_boot_info_header *boot_header;
43 struct ffa_boot_info_desc *boot_descriptor;
44 uintptr_t manifest_addr;
45
46 /*
47 * Calculate the maximum size of the manifest that can be accommodated
48 * in the boot information memory region.
49 */
50 const unsigned int
51 max_manifest_sz = sizeof(ffa_boot_info_mem) -
52 (sizeof(struct ffa_boot_info_header) +
53 sizeof(struct ffa_boot_info_desc));
54
55 /*
56 * The current implementation only supports the FF-A v1.1
57 * implementation of the boot protocol, therefore check
58 * that a v1.0 SP has not requested use of the protocol.
59 */
60 if (sp->ffa_version == MAKE_FFA_VERSION(1, 0)) {
61 ERROR("FF-A boot protocol not supported for v1.0 clients\n");
62 return;
63 }
64
65 /*
66 * Check if the manifest will fit into the boot info memory region else
67 * bail.
68 */
69 if (ep_info->args.arg1 > max_manifest_sz) {
70 WARN("Unable to copy manifest into boot information. ");
71 WARN("Max sz = %u bytes. Manifest sz = %lu bytes\n",
72 max_manifest_sz, ep_info->args.arg1);
73 return;
74 }
75
76 /* Zero the memory region before populating. */
77 memset(ffa_boot_info_mem, 0, PAGE_SIZE);
78
79 /*
80 * Populate the ffa_boot_info_header at the start of the boot info
81 * region.
82 */
83 boot_header = (struct ffa_boot_info_header *) ffa_boot_info_mem;
84
85 /* Position the ffa_boot_info_desc after the ffa_boot_info_header. */
86 boot_header->offset_boot_info_desc =
87 sizeof(struct ffa_boot_info_header);
88 boot_descriptor = (struct ffa_boot_info_desc *)
89 (ffa_boot_info_mem +
90 boot_header->offset_boot_info_desc);
91
92 /*
93 * We must use the FF-A version coresponding to the version implemented
94 * by the SP. Currently this can only be v1.1.
95 */
96 boot_header->version = sp->ffa_version;
97
98 /* Populate the boot information header. */
99 boot_header->size_boot_info_desc = sizeof(struct ffa_boot_info_desc);
100
101 /* Set the signature "0xFFA". */
102 boot_header->signature = FFA_INIT_DESC_SIGNATURE;
103
104 /* Set the count. Currently 1 since only the manifest is specified. */
105 boot_header->count_boot_info_desc = 1;
106
107 /* Populate the boot information descriptor for the manifest. */
108 boot_descriptor->type =
109 FFA_BOOT_INFO_TYPE(FFA_BOOT_INFO_TYPE_STD) |
110 FFA_BOOT_INFO_TYPE_ID(FFA_BOOT_INFO_TYPE_ID_FDT);
111
112 boot_descriptor->flags =
113 FFA_BOOT_INFO_FLAG_NAME(FFA_BOOT_INFO_FLAG_NAME_UUID) |
114 FFA_BOOT_INFO_FLAG_CONTENT(FFA_BOOT_INFO_FLAG_CONTENT_ADR);
115
116 /*
117 * Copy the manifest into boot info region after the boot information
118 * descriptor.
119 */
120 boot_descriptor->size_boot_info = (uint32_t) ep_info->args.arg1;
121
122 manifest_addr = (uintptr_t) (ffa_boot_info_mem +
123 boot_header->offset_boot_info_desc +
124 boot_header->size_boot_info_desc);
125
126 memcpy((void *) manifest_addr, (void *) ep_info->args.arg0,
127 boot_descriptor->size_boot_info);
128
129 boot_descriptor->content = manifest_addr;
130
131 /* Calculate the size of the total boot info blob. */
132 boot_header->size_boot_info_blob = boot_header->offset_boot_info_desc +
133 boot_descriptor->size_boot_info +
134 (boot_header->count_boot_info_desc *
135 boot_header->size_boot_info_desc);
136
137 INFO("SP boot info @ 0x%lx, size: %u bytes.\n",
138 (uintptr_t) ffa_boot_info_mem,
139 boot_header->size_boot_info_blob);
140 INFO("SP manifest @ 0x%lx, size: %u bytes.\n",
141 boot_descriptor->content,
142 boot_descriptor->size_boot_info);
143 }
144
145 /*
146 * We are assuming that the index of the execution
147 * context used is the linear index of the current physical cpu.
148 */
get_ec_index(struct secure_partition_desc * sp)149 unsigned int get_ec_index(struct secure_partition_desc *sp)
150 {
151 return plat_my_core_pos();
152 }
153
154 /* S-EL1 partition specific initialisation. */
spmc_el1_sp_setup(struct secure_partition_desc * sp,entry_point_info_t * ep_info)155 void spmc_el1_sp_setup(struct secure_partition_desc *sp,
156 entry_point_info_t *ep_info)
157 {
158 /* Sanity check input arguments. */
159 assert(sp != NULL);
160 assert(ep_info != NULL);
161
162 /* Initialise the SPSR for S-EL1 SPs. */
163 ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
164 DISABLE_ALL_EXCEPTIONS);
165
166 /*
167 * TF-A Implementation defined behaviour to provide the linear
168 * core ID in the x4 register.
169 */
170 ep_info->args.arg4 = (uintptr_t) plat_my_core_pos();
171
172 /*
173 * Check whether setup is being performed for the primary or a secondary
174 * execution context. In the latter case, indicate to the SP that this
175 * is a warm boot.
176 * TODO: This check would need to be reworked if the same entry point is
177 * used for both primary and secondary initialisation.
178 */
179 if (sp->secondary_ep != 0U) {
180 /*
181 * Sanity check that the secondary entry point is still what was
182 * originally set.
183 */
184 assert(sp->secondary_ep == ep_info->pc);
185 ep_info->args.arg0 = FFA_WB_TYPE_S2RAM;
186 }
187 }
188
189 /* Common initialisation for all SPs. */
spmc_sp_common_setup(struct secure_partition_desc * sp,entry_point_info_t * ep_info,int32_t boot_info_reg)190 void spmc_sp_common_setup(struct secure_partition_desc *sp,
191 entry_point_info_t *ep_info,
192 int32_t boot_info_reg)
193 {
194 uint16_t sp_id;
195
196 /* Assign FF-A Partition ID if not already assigned. */
197 if (sp->sp_id == INV_SP_ID) {
198 sp_id = FFA_SP_ID_BASE + ACTIVE_SP_DESC_INDEX;
199 /*
200 * Ensure we don't clash with previously assigned partition
201 * IDs.
202 */
203 while (!is_ffa_secure_id_valid(sp_id)) {
204 sp_id++;
205
206 if (sp_id == FFA_SWD_ID_LIMIT) {
207 ERROR("Unable to determine valid SP ID.\n");
208 panic();
209 }
210 }
211 sp->sp_id = sp_id;
212 }
213
214 /*
215 * We currently only support S-EL1 partitions so ensure this is the
216 * case.
217 */
218 assert(sp->runtime_el == S_EL1);
219
220 /* Check if the SP wants to use the FF-A boot protocol. */
221 if (boot_info_reg >= 0) {
222 /*
223 * Create a boot information descriptor and copy the partition
224 * manifest into the reserved memory region for consumption by
225 * the SP.
226 */
227 spmc_create_boot_info(ep_info, sp);
228
229 /*
230 * We have consumed what we need from ep args so we can now
231 * zero them before we start populating with new information
232 * specifically for the SP.
233 */
234 zeromem(&ep_info->args, sizeof(ep_info->args));
235
236 /*
237 * Pass the address of the boot information in the
238 * boot_info_reg.
239 */
240 switch (boot_info_reg) {
241 case 0:
242 ep_info->args.arg0 = (uintptr_t) ffa_boot_info_mem;
243 break;
244 case 1:
245 ep_info->args.arg1 = (uintptr_t) ffa_boot_info_mem;
246 break;
247 case 2:
248 ep_info->args.arg2 = (uintptr_t) ffa_boot_info_mem;
249 break;
250 case 3:
251 ep_info->args.arg3 = (uintptr_t) ffa_boot_info_mem;
252 break;
253 default:
254 ERROR("Invalid value for \"gp-register-num\" %d.\n",
255 boot_info_reg);
256 }
257 } else {
258 /*
259 * We don't need any of the information that was populated
260 * in ep_args so we can clear them.
261 */
262 zeromem(&ep_info->args, sizeof(ep_info->args));
263 }
264 }
265
266 /*
267 * Initialise the SP context now we have populated the common and EL specific
268 * entrypoint information.
269 */
spmc_sp_common_ep_commit(struct secure_partition_desc * sp,entry_point_info_t * ep_info)270 void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
271 entry_point_info_t *ep_info)
272 {
273 cpu_context_t *cpu_ctx;
274
275 cpu_ctx = &(spmc_get_sp_ec(sp)->cpu_ctx);
276 print_entry_point_info(ep_info);
277 cm_setup_context(cpu_ctx, ep_info);
278 }
279