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