xref: /arm-trusted-firmware/bl32/tsp/tsp_ffa_main.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2013-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 <inttypes.h>
9*91f16700Schasinglulu #include <stdint.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include "../../services/std_svc/spm/el3_spmc/spmc.h"
12*91f16700Schasinglulu #include "../../services/std_svc/spm/el3_spmc/spmc_shared_mem.h"
13*91f16700Schasinglulu #include <arch_features.h>
14*91f16700Schasinglulu #include <arch_helpers.h>
15*91f16700Schasinglulu #include <bl32/tsp/tsp.h>
16*91f16700Schasinglulu #include <common/bl_common.h>
17*91f16700Schasinglulu #include <common/debug.h>
18*91f16700Schasinglulu #include "ffa_helpers.h"
19*91f16700Schasinglulu #include <lib/psci/psci.h>
20*91f16700Schasinglulu #include <lib/spinlock.h>
21*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_defs.h>
22*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
23*91f16700Schasinglulu #include <plat/common/platform.h>
24*91f16700Schasinglulu #include <platform_tsp.h>
25*91f16700Schasinglulu #include <services/ffa_svc.h>
26*91f16700Schasinglulu #include "tsp_private.h"
27*91f16700Schasinglulu 
28*91f16700Schasinglulu #include <platform_def.h>
29*91f16700Schasinglulu 
30*91f16700Schasinglulu static ffa_endpoint_id16_t tsp_id, spmc_id;
31*91f16700Schasinglulu uint8_t mem_region_buffer[4096 * 2]  __aligned(PAGE_SIZE);
32*91f16700Schasinglulu 
33*91f16700Schasinglulu /* Partition Mailbox. */
34*91f16700Schasinglulu static uint8_t send_page[PAGE_SIZE] __aligned(PAGE_SIZE);
35*91f16700Schasinglulu static uint8_t recv_page[PAGE_SIZE] __aligned(PAGE_SIZE);
36*91f16700Schasinglulu 
37*91f16700Schasinglulu /*
38*91f16700Schasinglulu  * Declare a global mailbox for use within the TSP.
39*91f16700Schasinglulu  * This will be initialized appropriately when the buffers
40*91f16700Schasinglulu  * are mapped with the SPMC.
41*91f16700Schasinglulu  */
42*91f16700Schasinglulu static struct mailbox mailbox;
43*91f16700Schasinglulu 
44*91f16700Schasinglulu /*******************************************************************************
45*91f16700Schasinglulu  * This enum is used to handle test cases driven from the FF-A Test Driver.
46*91f16700Schasinglulu  ******************************************************************************/
47*91f16700Schasinglulu /* Keep in Sync with FF-A Test Driver. */
48*91f16700Schasinglulu enum message_t {
49*91f16700Schasinglulu 	/* Partition Only Messages. */
50*91f16700Schasinglulu 	FF_A_RELAY_MESSAGE = 0,
51*91f16700Schasinglulu 
52*91f16700Schasinglulu 	/* Basic Functionality. */
53*91f16700Schasinglulu 	FF_A_ECHO_MESSAGE,
54*91f16700Schasinglulu 	FF_A_RELAY_MESSAGE_EL3,
55*91f16700Schasinglulu 
56*91f16700Schasinglulu 	/* Memory Sharing. */
57*91f16700Schasinglulu 	FF_A_MEMORY_SHARE,
58*91f16700Schasinglulu 	FF_A_MEMORY_SHARE_FRAGMENTED,
59*91f16700Schasinglulu 	FF_A_MEMORY_LEND,
60*91f16700Schasinglulu 	FF_A_MEMORY_LEND_FRAGMENTED,
61*91f16700Schasinglulu 
62*91f16700Schasinglulu 	FF_A_MEMORY_SHARE_MULTI_ENDPOINT,
63*91f16700Schasinglulu 	FF_A_MEMORY_LEND_MULTI_ENDPOINT,
64*91f16700Schasinglulu 
65*91f16700Schasinglulu 	LAST,
66*91f16700Schasinglulu 	FF_A_RUN_ALL = 255,
67*91f16700Schasinglulu 	FF_A_OP_MAX = 256
68*91f16700Schasinglulu };
69*91f16700Schasinglulu 
70*91f16700Schasinglulu #if SPMC_AT_EL3
71*91f16700Schasinglulu extern void tsp_cpu_on_entry(void);
72*91f16700Schasinglulu #endif
73*91f16700Schasinglulu 
74*91f16700Schasinglulu /*******************************************************************************
75*91f16700Schasinglulu  * Test Functions.
76*91f16700Schasinglulu  ******************************************************************************/
77*91f16700Schasinglulu 
78*91f16700Schasinglulu /*******************************************************************************
79*91f16700Schasinglulu  * Enable the TSP to forward the received message to another partition and ask
80*91f16700Schasinglulu  * it to echo the value back in order to validate direct messages functionality.
81*91f16700Schasinglulu  ******************************************************************************/
82*91f16700Schasinglulu static int ffa_test_relay(uint64_t arg0,
83*91f16700Schasinglulu 			  uint64_t arg1,
84*91f16700Schasinglulu 			  uint64_t arg2,
85*91f16700Schasinglulu 			  uint64_t arg3,
86*91f16700Schasinglulu 			  uint64_t arg4,
87*91f16700Schasinglulu 			  uint64_t arg5,
88*91f16700Schasinglulu 			  uint64_t arg6,
89*91f16700Schasinglulu 			  uint64_t arg7)
90*91f16700Schasinglulu {
91*91f16700Schasinglulu 	smc_args_t ffa_forward_result;
92*91f16700Schasinglulu 	ffa_endpoint_id16_t receiver = arg5;
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	ffa_forward_result = ffa_msg_send_direct_req(tsp_id,
95*91f16700Schasinglulu 						     receiver,
96*91f16700Schasinglulu 						     FF_A_ECHO_MESSAGE, arg4,
97*91f16700Schasinglulu 						     0, 0, 0);
98*91f16700Schasinglulu 	return ffa_forward_result._regs[3];
99*91f16700Schasinglulu }
100*91f16700Schasinglulu 
101*91f16700Schasinglulu /*******************************************************************************
102*91f16700Schasinglulu  * This function handles memory management tests, currently share and lend.
103*91f16700Schasinglulu  * This test supports the use of FRAG_RX to use memory descriptors that do not
104*91f16700Schasinglulu  * fit in a single 4KB buffer.
105*91f16700Schasinglulu  ******************************************************************************/
106*91f16700Schasinglulu static int test_memory_send(ffa_endpoint_id16_t sender, uint64_t handle,
107*91f16700Schasinglulu 			    ffa_mtd_flag32_t flags, bool multi_endpoint)
108*91f16700Schasinglulu {
109*91f16700Schasinglulu 	struct ffa_mtd *m;
110*91f16700Schasinglulu 	struct ffa_emad_v1_0 *receivers;
111*91f16700Schasinglulu 	struct ffa_comp_mrd *composite;
112*91f16700Schasinglulu 	int ret, status = 0;
113*91f16700Schasinglulu 	unsigned int mem_attrs;
114*91f16700Schasinglulu 	char *ptr;
115*91f16700Schasinglulu 	ffa_endpoint_id16_t source = sender;
116*91f16700Schasinglulu 	uint32_t total_length, recv_length = 0;
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	/*
119*91f16700Schasinglulu 	 * In the case that we're testing multiple endpoints choose a partition
120*91f16700Schasinglulu 	 * ID that resides in the normal world so the SPMC won't detect it as
121*91f16700Schasinglulu 	 * invalid.
122*91f16700Schasinglulu 	 * TODO: Should get endpoint receiver id and flag as input from NWd.
123*91f16700Schasinglulu 	 */
124*91f16700Schasinglulu 	uint32_t receiver_count = multi_endpoint ? 2 : 1;
125*91f16700Schasinglulu 	ffa_endpoint_id16_t test_receivers[2] = { tsp_id, 0x10 };
126*91f16700Schasinglulu 
127*91f16700Schasinglulu 	/* Ensure that the sender ID resides in the normal world. */
128*91f16700Schasinglulu 	if (ffa_is_secure_world_id(sender)) {
129*91f16700Schasinglulu 		ERROR("Invalid sender ID 0x%x.\n", sender);
130*91f16700Schasinglulu 		return FFA_ERROR_DENIED;
131*91f16700Schasinglulu 	}
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 	if (!memory_retrieve(&mailbox, &m, handle, source, test_receivers,
134*91f16700Schasinglulu 			     receiver_count, flags, &recv_length,
135*91f16700Schasinglulu 			     &total_length)) {
136*91f16700Schasinglulu 		return FFA_ERROR_INVALID_PARAMETER;
137*91f16700Schasinglulu 	}
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	receivers = (struct ffa_emad_v1_0 *)
140*91f16700Schasinglulu 		    ((uint8_t *) m + m->emad_offset);
141*91f16700Schasinglulu 	while (total_length != recv_length) {
142*91f16700Schasinglulu 		smc_args_t ffa_return;
143*91f16700Schasinglulu 		uint32_t frag_length;
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 		ffa_return = ffa_mem_frag_rx(handle, recv_length);
146*91f16700Schasinglulu 
147*91f16700Schasinglulu 		if (ffa_return._regs[0] == FFA_ERROR) {
148*91f16700Schasinglulu 			WARN("TSP: failed to resume mem with handle %lx\n",
149*91f16700Schasinglulu 			     handle);
150*91f16700Schasinglulu 			return ffa_return._regs[2];
151*91f16700Schasinglulu 		}
152*91f16700Schasinglulu 		frag_length = ffa_return._regs[3];
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 		/* Validate frag_length is less than total_length and mailbox size. */
155*91f16700Schasinglulu 		if (frag_length > total_length ||
156*91f16700Schasinglulu 				frag_length > (mailbox.rxtx_page_count * PAGE_SIZE)) {
157*91f16700Schasinglulu 			ERROR("Invalid parameters!\n");
158*91f16700Schasinglulu 			return FFA_ERROR_INVALID_PARAMETER;
159*91f16700Schasinglulu 		}
160*91f16700Schasinglulu 
161*91f16700Schasinglulu 		/* Validate frag_length is less than remaining mem_region_buffer size. */
162*91f16700Schasinglulu 		if (frag_length + recv_length >= REGION_BUF_SIZE) {
163*91f16700Schasinglulu 			ERROR("Out of memory!\n");
164*91f16700Schasinglulu 			return FFA_ERROR_INVALID_PARAMETER;
165*91f16700Schasinglulu 		}
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 		memcpy(&mem_region_buffer[recv_length], mailbox.rx_buffer,
168*91f16700Schasinglulu 		       frag_length);
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 		if (ffa_rx_release()) {
171*91f16700Schasinglulu 			ERROR("Failed to release buffer!\n");
172*91f16700Schasinglulu 			return FFA_ERROR_DENIED;
173*91f16700Schasinglulu 		}
174*91f16700Schasinglulu 
175*91f16700Schasinglulu 		recv_length += frag_length;
176*91f16700Schasinglulu 
177*91f16700Schasinglulu 		assert(recv_length <= total_length);
178*91f16700Schasinglulu 	}
179*91f16700Schasinglulu 
180*91f16700Schasinglulu 	composite = ffa_memory_region_get_composite(m, 0);
181*91f16700Schasinglulu 	if (composite == NULL) {
182*91f16700Schasinglulu 		WARN("Failed to get composite descriptor!\n");
183*91f16700Schasinglulu 		return FFA_ERROR_INVALID_PARAMETER;
184*91f16700Schasinglulu 	}
185*91f16700Schasinglulu 
186*91f16700Schasinglulu 	VERBOSE("Address: %p; page_count: %x %lx\n",
187*91f16700Schasinglulu 		(void *)composite->address_range_array[0].address,
188*91f16700Schasinglulu 		composite->address_range_array[0].page_count, PAGE_SIZE);
189*91f16700Schasinglulu 
190*91f16700Schasinglulu 	/* This test is only concerned with RW permissions. */
191*91f16700Schasinglulu 	if (ffa_get_data_access_attr(
192*91f16700Schasinglulu 	    receivers[0].mapd.memory_access_permissions) != FFA_MEM_PERM_RW) {
193*91f16700Schasinglulu 		ERROR("Data permission in retrieve response %x does not match share/lend %x!\n",
194*91f16700Schasinglulu 		      ffa_get_data_access_attr(receivers[0].mapd.memory_access_permissions),
195*91f16700Schasinglulu 		      FFA_MEM_PERM_RW);
196*91f16700Schasinglulu 		return FFA_ERROR_INVALID_PARAMETER;
197*91f16700Schasinglulu 	}
198*91f16700Schasinglulu 
199*91f16700Schasinglulu 	mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER;
200*91f16700Schasinglulu 
201*91f16700Schasinglulu 	/* Only expecting to be sent memory from NWd so map accordingly. */
202*91f16700Schasinglulu 	mem_attrs |= MT_NS;
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	for (int32_t i = 0; i < (int32_t)composite->address_range_count; i++) {
205*91f16700Schasinglulu 		size_t size = composite->address_range_array[i].page_count * PAGE_SIZE;
206*91f16700Schasinglulu 
207*91f16700Schasinglulu 		ptr = (char *) composite->address_range_array[i].address;
208*91f16700Schasinglulu 		ret = mmap_add_dynamic_region(
209*91f16700Schasinglulu 				(uint64_t)ptr,
210*91f16700Schasinglulu 				(uint64_t)ptr,
211*91f16700Schasinglulu 				size, mem_attrs);
212*91f16700Schasinglulu 
213*91f16700Schasinglulu 		if (ret != 0) {
214*91f16700Schasinglulu 			ERROR("Failed [%d] mmap_add_dynamic_region %u (%lx) (%lx) (%x)!\n",
215*91f16700Schasinglulu 				i, ret,
216*91f16700Schasinglulu 				(uint64_t)composite->address_range_array[i].address,
217*91f16700Schasinglulu 				size, mem_attrs);
218*91f16700Schasinglulu 
219*91f16700Schasinglulu 			/* Remove mappings previously created in this transaction. */
220*91f16700Schasinglulu 			for (i--; i >= 0; i--) {
221*91f16700Schasinglulu 				ret = mmap_remove_dynamic_region(
222*91f16700Schasinglulu 					(uint64_t)composite->address_range_array[i].address,
223*91f16700Schasinglulu 					composite->address_range_array[i].page_count * PAGE_SIZE);
224*91f16700Schasinglulu 
225*91f16700Schasinglulu 				if (ret != 0) {
226*91f16700Schasinglulu 					ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
227*91f16700Schasinglulu 					panic();
228*91f16700Schasinglulu 				}
229*91f16700Schasinglulu 			}
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 			return FFA_ERROR_NO_MEMORY;
232*91f16700Schasinglulu 		}
233*91f16700Schasinglulu 
234*91f16700Schasinglulu 		/* Increment memory region for validation purposes. */
235*91f16700Schasinglulu 		++(*ptr);
236*91f16700Schasinglulu 
237*91f16700Schasinglulu 		/*
238*91f16700Schasinglulu 		 * Read initial magic number from memory region for
239*91f16700Schasinglulu 		 * validation purposes.
240*91f16700Schasinglulu 		 */
241*91f16700Schasinglulu 		if (!i) {
242*91f16700Schasinglulu 			status = *ptr;
243*91f16700Schasinglulu 		}
244*91f16700Schasinglulu 	}
245*91f16700Schasinglulu 
246*91f16700Schasinglulu 	for (uint32_t i = 0U; i < composite->address_range_count; i++) {
247*91f16700Schasinglulu 		ret = mmap_remove_dynamic_region(
248*91f16700Schasinglulu 			(uint64_t)composite->address_range_array[i].address,
249*91f16700Schasinglulu 			composite->address_range_array[i].page_count * PAGE_SIZE);
250*91f16700Schasinglulu 
251*91f16700Schasinglulu 		if (ret != 0) {
252*91f16700Schasinglulu 			ERROR("Failed [%d] mmap_remove_dynamic_region!\n", i);
253*91f16700Schasinglulu 			return FFA_ERROR_NO_MEMORY;
254*91f16700Schasinglulu 		}
255*91f16700Schasinglulu 	}
256*91f16700Schasinglulu 
257*91f16700Schasinglulu 	if (!memory_relinquish((struct ffa_mem_relinquish_descriptor *)mailbox.tx_buffer,
258*91f16700Schasinglulu 				m->handle, tsp_id)) {
259*91f16700Schasinglulu 		ERROR("Failed to relinquish memory region!\n");
260*91f16700Schasinglulu 		return FFA_ERROR_INVALID_PARAMETER;
261*91f16700Schasinglulu 	}
262*91f16700Schasinglulu 	return status;
263*91f16700Schasinglulu }
264*91f16700Schasinglulu 
265*91f16700Schasinglulu static smc_args_t *send_ffa_pm_success(void)
266*91f16700Schasinglulu {
267*91f16700Schasinglulu 	return set_smc_args(FFA_MSG_SEND_DIRECT_RESP_SMC32,
268*91f16700Schasinglulu 			    ((tsp_id & FFA_DIRECT_MSG_ENDPOINT_ID_MASK)
269*91f16700Schasinglulu 			    << FFA_DIRECT_MSG_SOURCE_SHIFT) | spmc_id,
270*91f16700Schasinglulu 			    FFA_FWK_MSG_BIT |
271*91f16700Schasinglulu 			    (FFA_PM_MSG_PM_RESP & FFA_FWK_MSG_MASK),
272*91f16700Schasinglulu 			    0, 0, 0, 0, 0);
273*91f16700Schasinglulu }
274*91f16700Schasinglulu 
275*91f16700Schasinglulu /*******************************************************************************
276*91f16700Schasinglulu  * This function performs any remaining book keeping in the test secure payload
277*91f16700Schasinglulu  * before this cpu is turned off in response to a psci cpu_off request.
278*91f16700Schasinglulu  ******************************************************************************/
279*91f16700Schasinglulu smc_args_t *tsp_cpu_off_main(uint64_t arg0,
280*91f16700Schasinglulu 			     uint64_t arg1,
281*91f16700Schasinglulu 			     uint64_t arg2,
282*91f16700Schasinglulu 			     uint64_t arg3,
283*91f16700Schasinglulu 			     uint64_t arg4,
284*91f16700Schasinglulu 			     uint64_t arg5,
285*91f16700Schasinglulu 			     uint64_t arg6,
286*91f16700Schasinglulu 			     uint64_t arg7)
287*91f16700Schasinglulu {
288*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
289*91f16700Schasinglulu 
290*91f16700Schasinglulu 	/*
291*91f16700Schasinglulu 	 * This cpu is being turned off, so disable the timer to prevent the
292*91f16700Schasinglulu 	 * secure timer interrupt from interfering with power down. A pending
293*91f16700Schasinglulu 	 * interrupt will be lost but we do not care as we are turning off.
294*91f16700Schasinglulu 	 */
295*91f16700Schasinglulu 	tsp_generic_timer_stop();
296*91f16700Schasinglulu 
297*91f16700Schasinglulu 	/* Update this cpu's statistics. */
298*91f16700Schasinglulu 	tsp_stats[linear_id].smc_count++;
299*91f16700Schasinglulu 	tsp_stats[linear_id].eret_count++;
300*91f16700Schasinglulu 	tsp_stats[linear_id].cpu_off_count++;
301*91f16700Schasinglulu 
302*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx off request\n", read_mpidr());
303*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n",
304*91f16700Schasinglulu 		read_mpidr(),
305*91f16700Schasinglulu 		tsp_stats[linear_id].smc_count,
306*91f16700Schasinglulu 		tsp_stats[linear_id].eret_count,
307*91f16700Schasinglulu 		tsp_stats[linear_id].cpu_off_count);
308*91f16700Schasinglulu 
309*91f16700Schasinglulu 	return send_ffa_pm_success();
310*91f16700Schasinglulu }
311*91f16700Schasinglulu 
312*91f16700Schasinglulu /*******************************************************************************
313*91f16700Schasinglulu  * This function performs any book keeping in the test secure payload before
314*91f16700Schasinglulu  * this cpu's architectural state is saved in response to an earlier psci
315*91f16700Schasinglulu  * cpu_suspend request.
316*91f16700Schasinglulu  ******************************************************************************/
317*91f16700Schasinglulu smc_args_t *tsp_cpu_suspend_main(uint64_t arg0,
318*91f16700Schasinglulu 				 uint64_t arg1,
319*91f16700Schasinglulu 				 uint64_t arg2,
320*91f16700Schasinglulu 				 uint64_t arg3,
321*91f16700Schasinglulu 				 uint64_t arg4,
322*91f16700Schasinglulu 				 uint64_t arg5,
323*91f16700Schasinglulu 				 uint64_t arg6,
324*91f16700Schasinglulu 				 uint64_t arg7)
325*91f16700Schasinglulu {
326*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
327*91f16700Schasinglulu 
328*91f16700Schasinglulu 	/*
329*91f16700Schasinglulu 	 * Save the time context and disable it to prevent the secure timer
330*91f16700Schasinglulu 	 * interrupt from interfering with wakeup from the suspend state.
331*91f16700Schasinglulu 	 */
332*91f16700Schasinglulu 	tsp_generic_timer_save();
333*91f16700Schasinglulu 	tsp_generic_timer_stop();
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	/* Update this cpu's statistics. */
336*91f16700Schasinglulu 	tsp_stats[linear_id].smc_count++;
337*91f16700Schasinglulu 	tsp_stats[linear_id].eret_count++;
338*91f16700Schasinglulu 	tsp_stats[linear_id].cpu_suspend_count++;
339*91f16700Schasinglulu 
340*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
341*91f16700Schasinglulu 		read_mpidr(),
342*91f16700Schasinglulu 		tsp_stats[linear_id].smc_count,
343*91f16700Schasinglulu 		tsp_stats[linear_id].eret_count,
344*91f16700Schasinglulu 		tsp_stats[linear_id].cpu_suspend_count);
345*91f16700Schasinglulu 
346*91f16700Schasinglulu 	return send_ffa_pm_success();
347*91f16700Schasinglulu }
348*91f16700Schasinglulu 
349*91f16700Schasinglulu /*******************************************************************************
350*91f16700Schasinglulu  * This function performs any bookkeeping in the test secure payload after this
351*91f16700Schasinglulu  * cpu's architectural state has been restored after wakeup from an earlier psci
352*91f16700Schasinglulu  * cpu_suspend request.
353*91f16700Schasinglulu  ******************************************************************************/
354*91f16700Schasinglulu smc_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl,
355*91f16700Schasinglulu 				uint64_t arg1,
356*91f16700Schasinglulu 				uint64_t arg2,
357*91f16700Schasinglulu 				uint64_t arg3,
358*91f16700Schasinglulu 				uint64_t arg4,
359*91f16700Schasinglulu 				uint64_t arg5,
360*91f16700Schasinglulu 				uint64_t arg6,
361*91f16700Schasinglulu 				uint64_t arg7)
362*91f16700Schasinglulu {
363*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
364*91f16700Schasinglulu 
365*91f16700Schasinglulu 	/* Restore the generic timer context. */
366*91f16700Schasinglulu 	tsp_generic_timer_restore();
367*91f16700Schasinglulu 
368*91f16700Schasinglulu 	/* Update this cpu's statistics. */
369*91f16700Schasinglulu 	tsp_stats[linear_id].smc_count++;
370*91f16700Schasinglulu 	tsp_stats[linear_id].eret_count++;
371*91f16700Schasinglulu 	tsp_stats[linear_id].cpu_resume_count++;
372*91f16700Schasinglulu 
373*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx resumed. maximum off power level %" PRId64 "\n",
374*91f16700Schasinglulu 	     read_mpidr(), max_off_pwrlvl);
375*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu resume requests\n",
376*91f16700Schasinglulu 		read_mpidr(),
377*91f16700Schasinglulu 		tsp_stats[linear_id].smc_count,
378*91f16700Schasinglulu 		tsp_stats[linear_id].eret_count,
379*91f16700Schasinglulu 		tsp_stats[linear_id].cpu_resume_count);
380*91f16700Schasinglulu 
381*91f16700Schasinglulu 	return send_ffa_pm_success();
382*91f16700Schasinglulu }
383*91f16700Schasinglulu 
384*91f16700Schasinglulu /*******************************************************************************
385*91f16700Schasinglulu  * This function handles framework messages. Currently only PM.
386*91f16700Schasinglulu  ******************************************************************************/
387*91f16700Schasinglulu static smc_args_t *handle_framework_message(uint64_t arg0,
388*91f16700Schasinglulu 					    uint64_t arg1,
389*91f16700Schasinglulu 					    uint64_t arg2,
390*91f16700Schasinglulu 					    uint64_t arg3,
391*91f16700Schasinglulu 					    uint64_t arg4,
392*91f16700Schasinglulu 					    uint64_t arg5,
393*91f16700Schasinglulu 					    uint64_t arg6,
394*91f16700Schasinglulu 					    uint64_t arg7)
395*91f16700Schasinglulu {
396*91f16700Schasinglulu 	/* Check if it is a power management message from the SPMC. */
397*91f16700Schasinglulu 	if (ffa_endpoint_source(arg1) != spmc_id) {
398*91f16700Schasinglulu 		goto err;
399*91f16700Schasinglulu 	}
400*91f16700Schasinglulu 
401*91f16700Schasinglulu 	/* Check if it is a PM request message. */
402*91f16700Schasinglulu 	if ((arg2 & FFA_FWK_MSG_MASK) == FFA_FWK_MSG_PSCI) {
403*91f16700Schasinglulu 		/* Check if it is a PSCI CPU_OFF request. */
404*91f16700Schasinglulu 		if (arg3 == PSCI_CPU_OFF) {
405*91f16700Schasinglulu 			return tsp_cpu_off_main(arg0, arg1, arg2, arg3,
406*91f16700Schasinglulu 						arg4, arg5, arg6, arg7);
407*91f16700Schasinglulu 		} else if (arg3 == PSCI_CPU_SUSPEND_AARCH64) {
408*91f16700Schasinglulu 			return tsp_cpu_suspend_main(arg0, arg1, arg2, arg3,
409*91f16700Schasinglulu 						arg4, arg5, arg6, arg7);
410*91f16700Schasinglulu 		}
411*91f16700Schasinglulu 	} else if ((arg2 & FFA_FWK_MSG_MASK) == FFA_PM_MSG_WB_REQ) {
412*91f16700Schasinglulu 		/* Check it is a PSCI Warm Boot request. */
413*91f16700Schasinglulu 		if (arg3 == FFA_WB_TYPE_NOTS2RAM) {
414*91f16700Schasinglulu 			return tsp_cpu_resume_main(arg0, arg1, arg2, arg3,
415*91f16700Schasinglulu 						arg4, arg5, arg6, arg7);
416*91f16700Schasinglulu 		}
417*91f16700Schasinglulu 	}
418*91f16700Schasinglulu 
419*91f16700Schasinglulu err:
420*91f16700Schasinglulu 	ERROR("%s: Unknown framework message!\n", __func__);
421*91f16700Schasinglulu 	panic();
422*91f16700Schasinglulu }
423*91f16700Schasinglulu 
424*91f16700Schasinglulu /*******************************************************************************
425*91f16700Schasinglulu  * Handles partition messages. Exercised from the FF-A Test Driver.
426*91f16700Schasinglulu  ******************************************************************************/
427*91f16700Schasinglulu static smc_args_t *handle_partition_message(uint64_t arg0,
428*91f16700Schasinglulu 					    uint64_t arg1,
429*91f16700Schasinglulu 					    uint64_t arg2,
430*91f16700Schasinglulu 					    uint64_t arg3,
431*91f16700Schasinglulu 					    uint64_t arg4,
432*91f16700Schasinglulu 					    uint64_t arg5,
433*91f16700Schasinglulu 					    uint64_t arg6,
434*91f16700Schasinglulu 					    uint64_t arg7)
435*91f16700Schasinglulu {
436*91f16700Schasinglulu 	uint16_t sender = ffa_endpoint_source(arg1);
437*91f16700Schasinglulu 	uint16_t receiver = ffa_endpoint_destination(arg1);
438*91f16700Schasinglulu 	int status = -1;
439*91f16700Schasinglulu 	const bool multi_endpoint = true;
440*91f16700Schasinglulu 
441*91f16700Schasinglulu 	switch (arg3) {
442*91f16700Schasinglulu 	case FF_A_MEMORY_SHARE:
443*91f16700Schasinglulu 		INFO("TSP Tests: Memory Share Request--\n");
444*91f16700Schasinglulu 		status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, !multi_endpoint);
445*91f16700Schasinglulu 		break;
446*91f16700Schasinglulu 
447*91f16700Schasinglulu 	case FF_A_MEMORY_LEND:
448*91f16700Schasinglulu 		INFO("TSP Tests: Memory Lend Request--\n");
449*91f16700Schasinglulu 		status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, !multi_endpoint);
450*91f16700Schasinglulu 		break;
451*91f16700Schasinglulu 
452*91f16700Schasinglulu 	case FF_A_MEMORY_SHARE_MULTI_ENDPOINT:
453*91f16700Schasinglulu 		INFO("TSP Tests: Multi Endpoint Memory Share Request--\n");
454*91f16700Schasinglulu 		status = test_memory_send(sender, arg4, FFA_FLAG_SHARE_MEMORY, multi_endpoint);
455*91f16700Schasinglulu 		break;
456*91f16700Schasinglulu 
457*91f16700Schasinglulu 	case FF_A_MEMORY_LEND_MULTI_ENDPOINT:
458*91f16700Schasinglulu 		INFO("TSP Tests: Multi Endpoint Memory Lend Request--\n");
459*91f16700Schasinglulu 		status = test_memory_send(sender, arg4, FFA_FLAG_LEND_MEMORY, multi_endpoint);
460*91f16700Schasinglulu 		break;
461*91f16700Schasinglulu 	case FF_A_RELAY_MESSAGE:
462*91f16700Schasinglulu 		INFO("TSP Tests: Relaying message--\n");
463*91f16700Schasinglulu 		status = ffa_test_relay(arg0, arg1, arg2, arg3, arg4,
464*91f16700Schasinglulu 					arg5, arg6, arg7);
465*91f16700Schasinglulu 		break;
466*91f16700Schasinglulu 
467*91f16700Schasinglulu 	case FF_A_ECHO_MESSAGE:
468*91f16700Schasinglulu 		INFO("TSP Tests: echo message--\n");
469*91f16700Schasinglulu 		status = arg4;
470*91f16700Schasinglulu 		break;
471*91f16700Schasinglulu 
472*91f16700Schasinglulu 	default:
473*91f16700Schasinglulu 		INFO("TSP Tests: Unknown request ID %d--\n", (int) arg3);
474*91f16700Schasinglulu 	}
475*91f16700Schasinglulu 
476*91f16700Schasinglulu 	/* Swap the sender and receiver in the response. */
477*91f16700Schasinglulu 	return ffa_msg_send_direct_resp(receiver, sender, status, 0, 0, 0, 0);
478*91f16700Schasinglulu }
479*91f16700Schasinglulu 
480*91f16700Schasinglulu /*******************************************************************************
481*91f16700Schasinglulu  * This function implements the event loop for handling FF-A ABI invocations.
482*91f16700Schasinglulu  ******************************************************************************/
483*91f16700Schasinglulu static smc_args_t *tsp_event_loop(uint64_t smc_fid,
484*91f16700Schasinglulu 				  uint64_t arg1,
485*91f16700Schasinglulu 				  uint64_t arg2,
486*91f16700Schasinglulu 				  uint64_t arg3,
487*91f16700Schasinglulu 				  uint64_t arg4,
488*91f16700Schasinglulu 				  uint64_t arg5,
489*91f16700Schasinglulu 				  uint64_t arg6,
490*91f16700Schasinglulu 				  uint64_t arg7)
491*91f16700Schasinglulu {
492*91f16700Schasinglulu 	/* Panic if the SPMC did not forward an FF-A call. */
493*91f16700Schasinglulu 	if (!is_ffa_fid(smc_fid)) {
494*91f16700Schasinglulu 		ERROR("%s: Unknown SMC FID (0x%lx)\n", __func__, smc_fid);
495*91f16700Schasinglulu 		panic();
496*91f16700Schasinglulu 	}
497*91f16700Schasinglulu 
498*91f16700Schasinglulu 	switch (smc_fid) {
499*91f16700Schasinglulu 	case FFA_INTERRUPT:
500*91f16700Schasinglulu 		/*
501*91f16700Schasinglulu 		 * IRQs were enabled upon re-entry into the TSP. The interrupt
502*91f16700Schasinglulu 		 * must have been handled by now. Return to the SPMC indicating
503*91f16700Schasinglulu 		 * the same.
504*91f16700Schasinglulu 		 */
505*91f16700Schasinglulu 		return set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0);
506*91f16700Schasinglulu 
507*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
508*91f16700Schasinglulu 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
509*91f16700Schasinglulu 		/* Check if a framework message, handle accordingly. */
510*91f16700Schasinglulu 		if ((arg2 & FFA_FWK_MSG_BIT)) {
511*91f16700Schasinglulu 			return handle_framework_message(smc_fid, arg1, arg2, arg3,
512*91f16700Schasinglulu 							arg4, arg5, arg6, arg7);
513*91f16700Schasinglulu 		}
514*91f16700Schasinglulu 		return handle_partition_message(smc_fid, arg1, arg2, arg3,
515*91f16700Schasinglulu 							arg4, arg5, arg6, arg7);
516*91f16700Schasinglulu 	}
517*91f16700Schasinglulu 
518*91f16700Schasinglulu 	ERROR("%s: Unsupported FF-A FID (0x%lx)\n", __func__, smc_fid);
519*91f16700Schasinglulu 	panic();
520*91f16700Schasinglulu }
521*91f16700Schasinglulu 
522*91f16700Schasinglulu static smc_args_t *tsp_loop(smc_args_t *args)
523*91f16700Schasinglulu {
524*91f16700Schasinglulu 	smc_args_t ret;
525*91f16700Schasinglulu 
526*91f16700Schasinglulu 	do {
527*91f16700Schasinglulu 		/* --------------------------------------------
528*91f16700Schasinglulu 		 * Mask FIQ interrupts to avoid preemption
529*91f16700Schasinglulu 		 * in case EL3 SPMC delegates an IRQ next or a
530*91f16700Schasinglulu 		 * managed exit. Lastly, unmask IRQs so that
531*91f16700Schasinglulu 		 * they can be handled immediately upon re-entry.
532*91f16700Schasinglulu 		 *  ---------------------------------------------
533*91f16700Schasinglulu 		 */
534*91f16700Schasinglulu 		write_daifset(DAIF_FIQ_BIT);
535*91f16700Schasinglulu 		write_daifclr(DAIF_IRQ_BIT);
536*91f16700Schasinglulu 		ret = smc_helper(args->_regs[0], args->_regs[1], args->_regs[2],
537*91f16700Schasinglulu 			       args->_regs[3], args->_regs[4], args->_regs[5],
538*91f16700Schasinglulu 			       args->_regs[6], args->_regs[7]);
539*91f16700Schasinglulu 		args = tsp_event_loop(ret._regs[0], ret._regs[1], ret._regs[2],
540*91f16700Schasinglulu 				ret._regs[3], ret._regs[4], ret._regs[5],
541*91f16700Schasinglulu 				ret._regs[6], ret._regs[7]);
542*91f16700Schasinglulu 	} while (1);
543*91f16700Schasinglulu 
544*91f16700Schasinglulu 	/* Not Reached. */
545*91f16700Schasinglulu 	return NULL;
546*91f16700Schasinglulu }
547*91f16700Schasinglulu 
548*91f16700Schasinglulu /*******************************************************************************
549*91f16700Schasinglulu  * TSP main entry point where it gets the opportunity to initialize its secure
550*91f16700Schasinglulu  * state/applications. Once the state is initialized, it must return to the
551*91f16700Schasinglulu  * SPD with a pointer to the 'tsp_vector_table' jump table.
552*91f16700Schasinglulu  ******************************************************************************/
553*91f16700Schasinglulu uint64_t tsp_main(void)
554*91f16700Schasinglulu {
555*91f16700Schasinglulu 	smc_args_t smc_args = {0};
556*91f16700Schasinglulu 
557*91f16700Schasinglulu 	NOTICE("TSP: %s\n", version_string);
558*91f16700Schasinglulu 	NOTICE("TSP: %s\n", build_message);
559*91f16700Schasinglulu 	INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE);
560*91f16700Schasinglulu 	INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE);
561*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
562*91f16700Schasinglulu 
563*91f16700Schasinglulu 	/* Initialize the platform. */
564*91f16700Schasinglulu 	tsp_platform_setup();
565*91f16700Schasinglulu 
566*91f16700Schasinglulu 	/* Initialize secure/applications state here. */
567*91f16700Schasinglulu 	tsp_generic_timer_start();
568*91f16700Schasinglulu 
569*91f16700Schasinglulu 	/* Register secondary entrypoint with the SPMC. */
570*91f16700Schasinglulu 	smc_args = smc_helper(FFA_SECONDARY_EP_REGISTER_SMC64,
571*91f16700Schasinglulu 			(uint64_t) tsp_cpu_on_entry,
572*91f16700Schasinglulu 			0, 0, 0, 0, 0, 0);
573*91f16700Schasinglulu 	if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
574*91f16700Schasinglulu 		ERROR("TSP could not register secondary ep (0x%lx)\n",
575*91f16700Schasinglulu 				smc_args._regs[2]);
576*91f16700Schasinglulu 		panic();
577*91f16700Schasinglulu 	}
578*91f16700Schasinglulu 	/* Get TSP's endpoint id. */
579*91f16700Schasinglulu 	smc_args = smc_helper(FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
580*91f16700Schasinglulu 	if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
581*91f16700Schasinglulu 		ERROR("TSP could not get own ID (0x%lx) on core%d\n",
582*91f16700Schasinglulu 				smc_args._regs[2], linear_id);
583*91f16700Schasinglulu 		panic();
584*91f16700Schasinglulu 	}
585*91f16700Schasinglulu 
586*91f16700Schasinglulu 	tsp_id = smc_args._regs[2];
587*91f16700Schasinglulu 	INFO("TSP FF-A endpoint id = 0x%x\n", tsp_id);
588*91f16700Schasinglulu 
589*91f16700Schasinglulu 	/* Get the SPMC ID. */
590*91f16700Schasinglulu 	smc_args = smc_helper(FFA_SPM_ID_GET, 0, 0, 0, 0, 0, 0, 0);
591*91f16700Schasinglulu 	if (smc_args._regs[SMC_ARG0] != FFA_SUCCESS_SMC32) {
592*91f16700Schasinglulu 		ERROR("TSP could not get SPMC ID (0x%lx) on core%d\n",
593*91f16700Schasinglulu 				smc_args._regs[2], linear_id);
594*91f16700Schasinglulu 		panic();
595*91f16700Schasinglulu 	}
596*91f16700Schasinglulu 
597*91f16700Schasinglulu 	spmc_id = smc_args._regs[2];
598*91f16700Schasinglulu 
599*91f16700Schasinglulu 	/* Call RXTX_MAP to map a 4k RX and TX buffer. */
600*91f16700Schasinglulu 	if (ffa_rxtx_map((uintptr_t) send_page,
601*91f16700Schasinglulu 			 (uintptr_t) recv_page, 1)) {
602*91f16700Schasinglulu 		ERROR("TSP could not map it's RX/TX Buffers\n");
603*91f16700Schasinglulu 		panic();
604*91f16700Schasinglulu 	}
605*91f16700Schasinglulu 
606*91f16700Schasinglulu 	mailbox.tx_buffer = send_page;
607*91f16700Schasinglulu 	mailbox.rx_buffer = recv_page;
608*91f16700Schasinglulu 	mailbox.rxtx_page_count = 1;
609*91f16700Schasinglulu 
610*91f16700Schasinglulu 	/* Update this cpu's statistics. */
611*91f16700Schasinglulu 	tsp_stats[linear_id].smc_count++;
612*91f16700Schasinglulu 	tsp_stats[linear_id].eret_count++;
613*91f16700Schasinglulu 	tsp_stats[linear_id].cpu_on_count++;
614*91f16700Schasinglulu 
615*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
616*91f16700Schasinglulu 			read_mpidr(),
617*91f16700Schasinglulu 			tsp_stats[linear_id].smc_count,
618*91f16700Schasinglulu 			tsp_stats[linear_id].eret_count,
619*91f16700Schasinglulu 			tsp_stats[linear_id].cpu_on_count);
620*91f16700Schasinglulu 
621*91f16700Schasinglulu 	/* Tell SPMD that we are done initialising. */
622*91f16700Schasinglulu 	tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
623*91f16700Schasinglulu 
624*91f16700Schasinglulu 	/* Not reached. */
625*91f16700Schasinglulu 	return 0;
626*91f16700Schasinglulu }
627*91f16700Schasinglulu 
628*91f16700Schasinglulu /*******************************************************************************
629*91f16700Schasinglulu  * This function performs any remaining book keeping in the test secure payload
630*91f16700Schasinglulu  * after this cpu's architectural state has been setup in response to an earlier
631*91f16700Schasinglulu  * psci cpu_on request.
632*91f16700Schasinglulu  ******************************************************************************/
633*91f16700Schasinglulu smc_args_t *tsp_cpu_on_main(void)
634*91f16700Schasinglulu {
635*91f16700Schasinglulu 	uint32_t linear_id = plat_my_core_pos();
636*91f16700Schasinglulu 
637*91f16700Schasinglulu 	/* Initialize secure/applications state here. */
638*91f16700Schasinglulu 	tsp_generic_timer_start();
639*91f16700Schasinglulu 
640*91f16700Schasinglulu 	/* Update this cpu's statistics. */
641*91f16700Schasinglulu 	tsp_stats[linear_id].smc_count++;
642*91f16700Schasinglulu 	tsp_stats[linear_id].eret_count++;
643*91f16700Schasinglulu 	tsp_stats[linear_id].cpu_on_count++;
644*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx turned on\n", read_mpidr());
645*91f16700Schasinglulu 	VERBOSE("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n",
646*91f16700Schasinglulu 			read_mpidr(),
647*91f16700Schasinglulu 			tsp_stats[linear_id].smc_count,
648*91f16700Schasinglulu 			tsp_stats[linear_id].eret_count,
649*91f16700Schasinglulu 			tsp_stats[linear_id].cpu_on_count);
650*91f16700Schasinglulu 	/* ---------------------------------------------
651*91f16700Schasinglulu 	 * Jump to the main event loop to return to EL3
652*91f16700Schasinglulu 	 * and be ready for the next request on this cpu.
653*91f16700Schasinglulu 	 * ---------------------------------------------
654*91f16700Schasinglulu 	 */
655*91f16700Schasinglulu 	return tsp_loop(set_smc_args(FFA_MSG_WAIT, 0, 0, 0, 0, 0, 0, 0));
656*91f16700Schasinglulu }
657