xref: /aosp_15_r20/external/arm-trusted-firmware/services/spd/tspd/tspd_main.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park 
8*54fd6939SJiyong Park /*******************************************************************************
9*54fd6939SJiyong Park  * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a
10*54fd6939SJiyong Park  * plug-in component to the Secure Monitor, registered as a runtime service. The
11*54fd6939SJiyong Park  * SPD is expected to be a functional extension of the Secure Payload (SP) that
12*54fd6939SJiyong Park  * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting
13*54fd6939SJiyong Park  * the Trusted OS/Applications range to the dispatcher. The SPD will either
14*54fd6939SJiyong Park  * handle the request locally or delegate it to the Secure Payload. It is also
15*54fd6939SJiyong Park  * responsible for initialising and maintaining communication with the SP.
16*54fd6939SJiyong Park  ******************************************************************************/
17*54fd6939SJiyong Park #include <assert.h>
18*54fd6939SJiyong Park #include <errno.h>
19*54fd6939SJiyong Park #include <stddef.h>
20*54fd6939SJiyong Park #include <string.h>
21*54fd6939SJiyong Park 
22*54fd6939SJiyong Park #include <arch_helpers.h>
23*54fd6939SJiyong Park #include <bl31/bl31.h>
24*54fd6939SJiyong Park #include <bl31/ehf.h>
25*54fd6939SJiyong Park #include <bl32/tsp/tsp.h>
26*54fd6939SJiyong Park #include <common/bl_common.h>
27*54fd6939SJiyong Park #include <common/debug.h>
28*54fd6939SJiyong Park #include <common/runtime_svc.h>
29*54fd6939SJiyong Park #include <lib/el3_runtime/context_mgmt.h>
30*54fd6939SJiyong Park #include <plat/common/platform.h>
31*54fd6939SJiyong Park #include <tools_share/uuid.h>
32*54fd6939SJiyong Park 
33*54fd6939SJiyong Park #include "tspd_private.h"
34*54fd6939SJiyong Park 
35*54fd6939SJiyong Park /*******************************************************************************
36*54fd6939SJiyong Park  * Address of the entrypoint vector table in the Secure Payload. It is
37*54fd6939SJiyong Park  * initialised once on the primary core after a cold boot.
38*54fd6939SJiyong Park  ******************************************************************************/
39*54fd6939SJiyong Park tsp_vectors_t *tsp_vectors;
40*54fd6939SJiyong Park 
41*54fd6939SJiyong Park /*******************************************************************************
42*54fd6939SJiyong Park  * Array to keep track of per-cpu Secure Payload state
43*54fd6939SJiyong Park  ******************************************************************************/
44*54fd6939SJiyong Park tsp_context_t tspd_sp_context[TSPD_CORE_COUNT];
45*54fd6939SJiyong Park 
46*54fd6939SJiyong Park 
47*54fd6939SJiyong Park /* TSP UID */
48*54fd6939SJiyong Park DEFINE_SVC_UUID2(tsp_uuid,
49*54fd6939SJiyong Park 	0xa056305b, 0x9132, 0x7b42, 0x98, 0x11,
50*54fd6939SJiyong Park 	0x71, 0x68, 0xca, 0x50, 0xf3, 0xfa);
51*54fd6939SJiyong Park 
52*54fd6939SJiyong Park int32_t tspd_init(void);
53*54fd6939SJiyong Park 
54*54fd6939SJiyong Park /*
55*54fd6939SJiyong Park  * This helper function handles Secure EL1 preemption. The preemption could be
56*54fd6939SJiyong Park  * due Non Secure interrupts or EL3 interrupts. In both the cases we context
57*54fd6939SJiyong Park  * switch to the normal world and in case of EL3 interrupts, it will again be
58*54fd6939SJiyong Park  * routed to EL3 which will get handled at the exception vectors.
59*54fd6939SJiyong Park  */
tspd_handle_sp_preemption(void * handle)60*54fd6939SJiyong Park uint64_t tspd_handle_sp_preemption(void *handle)
61*54fd6939SJiyong Park {
62*54fd6939SJiyong Park 	cpu_context_t *ns_cpu_context;
63*54fd6939SJiyong Park 
64*54fd6939SJiyong Park 	assert(handle == cm_get_context(SECURE));
65*54fd6939SJiyong Park 	cm_el1_sysregs_context_save(SECURE);
66*54fd6939SJiyong Park 	/* Get a reference to the non-secure context */
67*54fd6939SJiyong Park 	ns_cpu_context = cm_get_context(NON_SECURE);
68*54fd6939SJiyong Park 	assert(ns_cpu_context);
69*54fd6939SJiyong Park 
70*54fd6939SJiyong Park 	/*
71*54fd6939SJiyong Park 	 * To allow Secure EL1 interrupt handler to re-enter TSP while TSP
72*54fd6939SJiyong Park 	 * is preempted, the secure system register context which will get
73*54fd6939SJiyong Park 	 * overwritten must be additionally saved. This is currently done
74*54fd6939SJiyong Park 	 * by the TSPD S-EL1 interrupt handler.
75*54fd6939SJiyong Park 	 */
76*54fd6939SJiyong Park 
77*54fd6939SJiyong Park 	/*
78*54fd6939SJiyong Park 	 * Restore non-secure state.
79*54fd6939SJiyong Park 	 */
80*54fd6939SJiyong Park 	cm_el1_sysregs_context_restore(NON_SECURE);
81*54fd6939SJiyong Park 	cm_set_next_eret_context(NON_SECURE);
82*54fd6939SJiyong Park 
83*54fd6939SJiyong Park 	/*
84*54fd6939SJiyong Park 	 * The TSP was preempted during execution of a Yielding SMC Call.
85*54fd6939SJiyong Park 	 * Return back to the normal world with SMC_PREEMPTED as error
86*54fd6939SJiyong Park 	 * code in x0.
87*54fd6939SJiyong Park 	 */
88*54fd6939SJiyong Park 	SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
89*54fd6939SJiyong Park }
90*54fd6939SJiyong Park 
91*54fd6939SJiyong Park /*******************************************************************************
92*54fd6939SJiyong Park  * This function is the handler registered for S-EL1 interrupts by the TSPD. It
93*54fd6939SJiyong Park  * validates the interrupt and upon success arranges entry into the TSP at
94*54fd6939SJiyong Park  * 'tsp_sel1_intr_entry()' for handling the interrupt.
95*54fd6939SJiyong Park  * Typically, interrupts for a specific security state get handled in the same
96*54fd6939SJiyong Park  * security execption level if the execution is in the same security state. For
97*54fd6939SJiyong Park  * example, if a non-secure interrupt gets fired when CPU is executing in NS-EL2
98*54fd6939SJiyong Park  * it gets handled in the non-secure world.
99*54fd6939SJiyong Park  * However, interrupts belonging to the opposite security state typically demand
100*54fd6939SJiyong Park  * a world(context) switch. This is inline with the security principle which
101*54fd6939SJiyong Park  * states a secure interrupt has to be handled in the secure world.
102*54fd6939SJiyong Park  * Hence, the TSPD in EL3 expects the context(handle) for a secure interrupt to
103*54fd6939SJiyong Park  * be non-secure and vice versa.
104*54fd6939SJiyong Park  * However, a race condition between non-secure and secure interrupts can lead to
105*54fd6939SJiyong Park  * a scenario where the above assumptions do not hold true. This is demonstrated
106*54fd6939SJiyong Park  * below through Note 1.
107*54fd6939SJiyong Park  ******************************************************************************/
tspd_sel1_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)108*54fd6939SJiyong Park static uint64_t tspd_sel1_interrupt_handler(uint32_t id,
109*54fd6939SJiyong Park 					    uint32_t flags,
110*54fd6939SJiyong Park 					    void *handle,
111*54fd6939SJiyong Park 					    void *cookie)
112*54fd6939SJiyong Park {
113*54fd6939SJiyong Park 	uint32_t linear_id;
114*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx;
115*54fd6939SJiyong Park 
116*54fd6939SJiyong Park 	/* Get a reference to this cpu's TSP context */
117*54fd6939SJiyong Park 	linear_id = plat_my_core_pos();
118*54fd6939SJiyong Park 	tsp_ctx = &tspd_sp_context[linear_id];
119*54fd6939SJiyong Park 
120*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
121*54fd6939SJiyong Park 
122*54fd6939SJiyong Park 	/*
123*54fd6939SJiyong Park 	 * Note 1:
124*54fd6939SJiyong Park 	 * Under the current interrupt routing model, interrupts from other
125*54fd6939SJiyong Park 	 * world are routed to EL3 when TSP_NS_INTR_ASYNC_PREEMPT is enabled.
126*54fd6939SJiyong Park 	 * Consider the following scenario:
127*54fd6939SJiyong Park 	 * 1/ A non-secure payload(like tftf) requests a secure service from
128*54fd6939SJiyong Park 	 *    TSP by invoking a yielding SMC call.
129*54fd6939SJiyong Park 	 * 2/ Later, execution jumps to TSP in S-EL1 with the help of TSP
130*54fd6939SJiyong Park 	 *    Dispatcher in Secure Monitor(EL3).
131*54fd6939SJiyong Park 	 * 3/ While CPU is executing TSP, a Non-secure interrupt gets fired.
132*54fd6939SJiyong Park 	 *    this demands a context switch to the non-secure world through
133*54fd6939SJiyong Park 	 *    secure monitor.
134*54fd6939SJiyong Park 	 * 4/ Consequently, TSP in S-EL1 get asynchronously pre-empted and
135*54fd6939SJiyong Park 	 *    execution switches to secure monitor(EL3).
136*54fd6939SJiyong Park 	 * 5/ EL3 tries to triage the (Non-secure) interrupt based on the
137*54fd6939SJiyong Park 	 *    highest pending interrupt.
138*54fd6939SJiyong Park 	 * 6/ However, while the NS Interrupt was pending, secure timer gets
139*54fd6939SJiyong Park 	 *    fired which makes a S-EL1 interrupt to be pending.
140*54fd6939SJiyong Park 	 * 7/ Hence, execution jumps to this companion handler of S-EL1
141*54fd6939SJiyong Park 	 *    interrupt (i.e., tspd_sel1_interrupt_handler) even though the TSP
142*54fd6939SJiyong Park 	 *    was pre-empted due to non-secure interrupt.
143*54fd6939SJiyong Park 	 * 8/ The above sequence of events explain how TSP was pre-empted by
144*54fd6939SJiyong Park 	 *    S-EL1 interrupt indirectly in an asynchronous way.
145*54fd6939SJiyong Park 	 * 9/ Hence, we track the TSP pre-emption by S-EL1 interrupt using a
146*54fd6939SJiyong Park 	 *    boolean variable per each core.
147*54fd6939SJiyong Park 	 * 10/ This helps us to indicate that SMC call for TSP service was
148*54fd6939SJiyong Park 	 *    pre-empted when execution resumes in non-secure world.
149*54fd6939SJiyong Park 	 */
150*54fd6939SJiyong Park 
151*54fd6939SJiyong Park 	/* Check the security state when the exception was generated */
152*54fd6939SJiyong Park 	if (get_interrupt_src_ss(flags) == NON_SECURE) {
153*54fd6939SJiyong Park 		/* Sanity check the pointer to this cpu's context */
154*54fd6939SJiyong Park 		assert(handle == cm_get_context(NON_SECURE));
155*54fd6939SJiyong Park 
156*54fd6939SJiyong Park 		/* Save the non-secure context before entering the TSP */
157*54fd6939SJiyong Park 		cm_el1_sysregs_context_save(NON_SECURE);
158*54fd6939SJiyong Park 		tsp_ctx->preempted_by_sel1_intr = false;
159*54fd6939SJiyong Park 	} else {
160*54fd6939SJiyong Park 		/* Sanity check the pointer to this cpu's context */
161*54fd6939SJiyong Park 		assert(handle == cm_get_context(SECURE));
162*54fd6939SJiyong Park 
163*54fd6939SJiyong Park 		/* Save the secure context before entering the TSP for S-EL1
164*54fd6939SJiyong Park 		 * interrupt handling
165*54fd6939SJiyong Park 		 */
166*54fd6939SJiyong Park 		cm_el1_sysregs_context_save(SECURE);
167*54fd6939SJiyong Park 		tsp_ctx->preempted_by_sel1_intr = true;
168*54fd6939SJiyong Park 	}
169*54fd6939SJiyong Park #else
170*54fd6939SJiyong Park 	/* Check the security state when the exception was generated */
171*54fd6939SJiyong Park 	assert(get_interrupt_src_ss(flags) == NON_SECURE);
172*54fd6939SJiyong Park 
173*54fd6939SJiyong Park 	/* Sanity check the pointer to this cpu's context */
174*54fd6939SJiyong Park 	assert(handle == cm_get_context(NON_SECURE));
175*54fd6939SJiyong Park 
176*54fd6939SJiyong Park 	/* Save the non-secure context before entering the TSP */
177*54fd6939SJiyong Park 	cm_el1_sysregs_context_save(NON_SECURE);
178*54fd6939SJiyong Park #endif
179*54fd6939SJiyong Park 
180*54fd6939SJiyong Park 	assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE));
181*54fd6939SJiyong Park 
182*54fd6939SJiyong Park 	/*
183*54fd6939SJiyong Park 	 * Determine if the TSP was previously preempted. Its last known
184*54fd6939SJiyong Park 	 * context has to be preserved in this case.
185*54fd6939SJiyong Park 	 * The TSP should return control to the TSPD after handling this
186*54fd6939SJiyong Park 	 * S-EL1 interrupt. Preserve essential EL3 context to allow entry into
187*54fd6939SJiyong Park 	 * the TSP at the S-EL1 interrupt entry point using the 'cpu_context'
188*54fd6939SJiyong Park 	 * structure. There is no need to save the secure system register
189*54fd6939SJiyong Park 	 * context since the TSP is supposed to preserve it during S-EL1
190*54fd6939SJiyong Park 	 * interrupt handling.
191*54fd6939SJiyong Park 	 */
192*54fd6939SJiyong Park 	if (get_yield_smc_active_flag(tsp_ctx->state)) {
193*54fd6939SJiyong Park 		tsp_ctx->saved_spsr_el3 = (uint32_t)SMC_GET_EL3(&tsp_ctx->cpu_ctx,
194*54fd6939SJiyong Park 						      CTX_SPSR_EL3);
195*54fd6939SJiyong Park 		tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx,
196*54fd6939SJiyong Park 						     CTX_ELR_EL3);
197*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
198*54fd6939SJiyong Park 		memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE);
199*54fd6939SJiyong Park #endif
200*54fd6939SJiyong Park 	}
201*54fd6939SJiyong Park 
202*54fd6939SJiyong Park 	cm_el1_sysregs_context_restore(SECURE);
203*54fd6939SJiyong Park 	cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry,
204*54fd6939SJiyong Park 		    SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS));
205*54fd6939SJiyong Park 
206*54fd6939SJiyong Park 	cm_set_next_eret_context(SECURE);
207*54fd6939SJiyong Park 
208*54fd6939SJiyong Park 	/*
209*54fd6939SJiyong Park 	 * Tell the TSP that it has to handle a S-EL1 interrupt synchronously.
210*54fd6939SJiyong Park 	 * Also the instruction in normal world where the interrupt was
211*54fd6939SJiyong Park 	 * generated is passed for debugging purposes. It is safe to retrieve
212*54fd6939SJiyong Park 	 * this address from ELR_EL3 as the secure context will not take effect
213*54fd6939SJiyong Park 	 * until el3_exit().
214*54fd6939SJiyong Park 	 */
215*54fd6939SJiyong Park 	SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3());
216*54fd6939SJiyong Park }
217*54fd6939SJiyong Park 
218*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
219*54fd6939SJiyong Park /*******************************************************************************
220*54fd6939SJiyong Park  * This function is the handler registered for Non secure interrupts by the
221*54fd6939SJiyong Park  * TSPD. It validates the interrupt and upon success arranges entry into the
222*54fd6939SJiyong Park  * normal world for handling the interrupt.
223*54fd6939SJiyong Park  ******************************************************************************/
tspd_ns_interrupt_handler(uint32_t id,uint32_t flags,void * handle,void * cookie)224*54fd6939SJiyong Park static uint64_t tspd_ns_interrupt_handler(uint32_t id,
225*54fd6939SJiyong Park 					    uint32_t flags,
226*54fd6939SJiyong Park 					    void *handle,
227*54fd6939SJiyong Park 					    void *cookie)
228*54fd6939SJiyong Park {
229*54fd6939SJiyong Park 	/* Check the security state when the exception was generated */
230*54fd6939SJiyong Park 	assert(get_interrupt_src_ss(flags) == SECURE);
231*54fd6939SJiyong Park 
232*54fd6939SJiyong Park 	/*
233*54fd6939SJiyong Park 	 * Disable the routing of NS interrupts from secure world to EL3 while
234*54fd6939SJiyong Park 	 * interrupted on this core.
235*54fd6939SJiyong Park 	 */
236*54fd6939SJiyong Park 	disable_intr_rm_local(INTR_TYPE_NS, SECURE);
237*54fd6939SJiyong Park 
238*54fd6939SJiyong Park 	return tspd_handle_sp_preemption(handle);
239*54fd6939SJiyong Park }
240*54fd6939SJiyong Park #endif
241*54fd6939SJiyong Park 
242*54fd6939SJiyong Park /*******************************************************************************
243*54fd6939SJiyong Park  * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
244*54fd6939SJiyong Park  * (aarch32/aarch64) if not already known and initialises the context for entry
245*54fd6939SJiyong Park  * into the SP for its initialisation.
246*54fd6939SJiyong Park  ******************************************************************************/
tspd_setup(void)247*54fd6939SJiyong Park static int32_t tspd_setup(void)
248*54fd6939SJiyong Park {
249*54fd6939SJiyong Park 	entry_point_info_t *tsp_ep_info;
250*54fd6939SJiyong Park 	uint32_t linear_id;
251*54fd6939SJiyong Park 
252*54fd6939SJiyong Park 	linear_id = plat_my_core_pos();
253*54fd6939SJiyong Park 
254*54fd6939SJiyong Park 	/*
255*54fd6939SJiyong Park 	 * Get information about the Secure Payload (BL32) image. Its
256*54fd6939SJiyong Park 	 * absence is a critical failure.  TODO: Add support to
257*54fd6939SJiyong Park 	 * conditionally include the SPD service
258*54fd6939SJiyong Park 	 */
259*54fd6939SJiyong Park 	tsp_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
260*54fd6939SJiyong Park 	if (!tsp_ep_info) {
261*54fd6939SJiyong Park 		WARN("No TSP provided by BL2 boot loader, Booting device"
262*54fd6939SJiyong Park 			" without TSP initialization. SMC`s destined for TSP"
263*54fd6939SJiyong Park 			" will return SMC_UNK\n");
264*54fd6939SJiyong Park 		return 1;
265*54fd6939SJiyong Park 	}
266*54fd6939SJiyong Park 
267*54fd6939SJiyong Park 	/*
268*54fd6939SJiyong Park 	 * If there's no valid entry point for SP, we return a non-zero value
269*54fd6939SJiyong Park 	 * signalling failure initializing the service. We bail out without
270*54fd6939SJiyong Park 	 * registering any handlers
271*54fd6939SJiyong Park 	 */
272*54fd6939SJiyong Park 	if (!tsp_ep_info->pc)
273*54fd6939SJiyong Park 		return 1;
274*54fd6939SJiyong Park 
275*54fd6939SJiyong Park 	/*
276*54fd6939SJiyong Park 	 * We could inspect the SP image and determine its execution
277*54fd6939SJiyong Park 	 * state i.e whether AArch32 or AArch64. Assuming it's AArch64
278*54fd6939SJiyong Park 	 * for the time being.
279*54fd6939SJiyong Park 	 */
280*54fd6939SJiyong Park 	tspd_init_tsp_ep_state(tsp_ep_info,
281*54fd6939SJiyong Park 				TSP_AARCH64,
282*54fd6939SJiyong Park 				tsp_ep_info->pc,
283*54fd6939SJiyong Park 				&tspd_sp_context[linear_id]);
284*54fd6939SJiyong Park 
285*54fd6939SJiyong Park #if TSP_INIT_ASYNC
286*54fd6939SJiyong Park 	bl31_set_next_image_type(SECURE);
287*54fd6939SJiyong Park #else
288*54fd6939SJiyong Park 	/*
289*54fd6939SJiyong Park 	 * All TSPD initialization done. Now register our init function with
290*54fd6939SJiyong Park 	 * BL31 for deferred invocation
291*54fd6939SJiyong Park 	 */
292*54fd6939SJiyong Park 	bl31_register_bl32_init(&tspd_init);
293*54fd6939SJiyong Park #endif
294*54fd6939SJiyong Park 	return 0;
295*54fd6939SJiyong Park }
296*54fd6939SJiyong Park 
297*54fd6939SJiyong Park /*******************************************************************************
298*54fd6939SJiyong Park  * This function passes control to the Secure Payload image (BL32) for the first
299*54fd6939SJiyong Park  * time on the primary cpu after a cold boot. It assumes that a valid secure
300*54fd6939SJiyong Park  * context has already been created by tspd_setup() which can be directly used.
301*54fd6939SJiyong Park  * It also assumes that a valid non-secure context has been initialised by PSCI
302*54fd6939SJiyong Park  * so it does not need to save and restore any non-secure state. This function
303*54fd6939SJiyong Park  * performs a synchronous entry into the Secure payload. The SP passes control
304*54fd6939SJiyong Park  * back to this routine through a SMC.
305*54fd6939SJiyong Park  ******************************************************************************/
tspd_init(void)306*54fd6939SJiyong Park int32_t tspd_init(void)
307*54fd6939SJiyong Park {
308*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
309*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
310*54fd6939SJiyong Park 	entry_point_info_t *tsp_entry_point;
311*54fd6939SJiyong Park 	uint64_t rc;
312*54fd6939SJiyong Park 
313*54fd6939SJiyong Park 	/*
314*54fd6939SJiyong Park 	 * Get information about the Secure Payload (BL32) image. Its
315*54fd6939SJiyong Park 	 * absence is a critical failure.
316*54fd6939SJiyong Park 	 */
317*54fd6939SJiyong Park 	tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
318*54fd6939SJiyong Park 	assert(tsp_entry_point);
319*54fd6939SJiyong Park 
320*54fd6939SJiyong Park 	cm_init_my_context(tsp_entry_point);
321*54fd6939SJiyong Park 
322*54fd6939SJiyong Park 	/*
323*54fd6939SJiyong Park 	 * Arrange for an entry into the test secure payload. It will be
324*54fd6939SJiyong Park 	 * returned via TSP_ENTRY_DONE case
325*54fd6939SJiyong Park 	 */
326*54fd6939SJiyong Park 	rc = tspd_synchronous_sp_entry(tsp_ctx);
327*54fd6939SJiyong Park 	assert(rc != 0);
328*54fd6939SJiyong Park 
329*54fd6939SJiyong Park 	return rc;
330*54fd6939SJiyong Park }
331*54fd6939SJiyong Park 
332*54fd6939SJiyong Park 
333*54fd6939SJiyong Park /*******************************************************************************
334*54fd6939SJiyong Park  * This function is responsible for handling all SMCs in the Trusted OS/App
335*54fd6939SJiyong Park  * range from the non-secure state as defined in the SMC Calling Convention
336*54fd6939SJiyong Park  * Document. It is also responsible for communicating with the Secure payload
337*54fd6939SJiyong Park  * to delegate work and return results back to the non-secure state. Lastly it
338*54fd6939SJiyong Park  * will also return any information that the secure payload needs to do the
339*54fd6939SJiyong Park  * work assigned to it.
340*54fd6939SJiyong Park  ******************************************************************************/
tspd_smc_handler(uint32_t smc_fid,u_register_t x1,u_register_t x2,u_register_t x3,u_register_t x4,void * cookie,void * handle,u_register_t flags)341*54fd6939SJiyong Park static uintptr_t tspd_smc_handler(uint32_t smc_fid,
342*54fd6939SJiyong Park 			 u_register_t x1,
343*54fd6939SJiyong Park 			 u_register_t x2,
344*54fd6939SJiyong Park 			 u_register_t x3,
345*54fd6939SJiyong Park 			 u_register_t x4,
346*54fd6939SJiyong Park 			 void *cookie,
347*54fd6939SJiyong Park 			 void *handle,
348*54fd6939SJiyong Park 			 u_register_t flags)
349*54fd6939SJiyong Park {
350*54fd6939SJiyong Park 	cpu_context_t *ns_cpu_context;
351*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos(), ns;
352*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
353*54fd6939SJiyong Park 	uint64_t rc;
354*54fd6939SJiyong Park #if TSP_INIT_ASYNC
355*54fd6939SJiyong Park 	entry_point_info_t *next_image_info;
356*54fd6939SJiyong Park #endif
357*54fd6939SJiyong Park 
358*54fd6939SJiyong Park 	/* Determine which security state this SMC originated from */
359*54fd6939SJiyong Park 	ns = is_caller_non_secure(flags);
360*54fd6939SJiyong Park 
361*54fd6939SJiyong Park 	switch (smc_fid) {
362*54fd6939SJiyong Park 
363*54fd6939SJiyong Park 	/*
364*54fd6939SJiyong Park 	 * This function ID is used by TSP to indicate that it was
365*54fd6939SJiyong Park 	 * preempted by a normal world IRQ.
366*54fd6939SJiyong Park 	 *
367*54fd6939SJiyong Park 	 */
368*54fd6939SJiyong Park 	case TSP_PREEMPTED:
369*54fd6939SJiyong Park 		if (ns)
370*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
371*54fd6939SJiyong Park 
372*54fd6939SJiyong Park 		return tspd_handle_sp_preemption(handle);
373*54fd6939SJiyong Park 
374*54fd6939SJiyong Park 	/*
375*54fd6939SJiyong Park 	 * This function ID is used only by the TSP to indicate that it has
376*54fd6939SJiyong Park 	 * finished handling a S-EL1 interrupt or was preempted by a higher
377*54fd6939SJiyong Park 	 * priority pending EL3 interrupt. Execution should resume
378*54fd6939SJiyong Park 	 * in the normal world.
379*54fd6939SJiyong Park 	 */
380*54fd6939SJiyong Park 	case TSP_HANDLED_S_EL1_INTR:
381*54fd6939SJiyong Park 		if (ns)
382*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
383*54fd6939SJiyong Park 
384*54fd6939SJiyong Park 		assert(handle == cm_get_context(SECURE));
385*54fd6939SJiyong Park 
386*54fd6939SJiyong Park 		/*
387*54fd6939SJiyong Park 		 * Restore the relevant EL3 state which saved to service
388*54fd6939SJiyong Park 		 * this SMC.
389*54fd6939SJiyong Park 		 */
390*54fd6939SJiyong Park 		if (get_yield_smc_active_flag(tsp_ctx->state)) {
391*54fd6939SJiyong Park 			SMC_SET_EL3(&tsp_ctx->cpu_ctx,
392*54fd6939SJiyong Park 				    CTX_SPSR_EL3,
393*54fd6939SJiyong Park 				    tsp_ctx->saved_spsr_el3);
394*54fd6939SJiyong Park 			SMC_SET_EL3(&tsp_ctx->cpu_ctx,
395*54fd6939SJiyong Park 				    CTX_ELR_EL3,
396*54fd6939SJiyong Park 				    tsp_ctx->saved_elr_el3);
397*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
398*54fd6939SJiyong Park 			/*
399*54fd6939SJiyong Park 			 * Need to restore the previously interrupted
400*54fd6939SJiyong Park 			 * secure context.
401*54fd6939SJiyong Park 			 */
402*54fd6939SJiyong Park 			memcpy(&tsp_ctx->cpu_ctx, &tsp_ctx->sp_ctx,
403*54fd6939SJiyong Park 				TSPD_SP_CTX_SIZE);
404*54fd6939SJiyong Park #endif
405*54fd6939SJiyong Park 		}
406*54fd6939SJiyong Park 
407*54fd6939SJiyong Park 		/* Get a reference to the non-secure context */
408*54fd6939SJiyong Park 		ns_cpu_context = cm_get_context(NON_SECURE);
409*54fd6939SJiyong Park 		assert(ns_cpu_context);
410*54fd6939SJiyong Park 
411*54fd6939SJiyong Park 		/*
412*54fd6939SJiyong Park 		 * Restore non-secure state. There is no need to save the
413*54fd6939SJiyong Park 		 * secure system register context since the TSP was supposed
414*54fd6939SJiyong Park 		 * to preserve it during S-EL1 interrupt handling.
415*54fd6939SJiyong Park 		 */
416*54fd6939SJiyong Park 		cm_el1_sysregs_context_restore(NON_SECURE);
417*54fd6939SJiyong Park 		cm_set_next_eret_context(NON_SECURE);
418*54fd6939SJiyong Park 
419*54fd6939SJiyong Park 		/* Refer to Note 1 in function tspd_sel1_interrupt_handler()*/
420*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
421*54fd6939SJiyong Park 		if (tsp_ctx->preempted_by_sel1_intr) {
422*54fd6939SJiyong Park 			/* Reset the flag */
423*54fd6939SJiyong Park 			tsp_ctx->preempted_by_sel1_intr = false;
424*54fd6939SJiyong Park 
425*54fd6939SJiyong Park 			SMC_RET1(ns_cpu_context, SMC_PREEMPTED);
426*54fd6939SJiyong Park 		} else {
427*54fd6939SJiyong Park 			SMC_RET0((uint64_t) ns_cpu_context);
428*54fd6939SJiyong Park 		}
429*54fd6939SJiyong Park #else
430*54fd6939SJiyong Park 		SMC_RET0((uint64_t) ns_cpu_context);
431*54fd6939SJiyong Park #endif
432*54fd6939SJiyong Park 
433*54fd6939SJiyong Park 
434*54fd6939SJiyong Park 	/*
435*54fd6939SJiyong Park 	 * This function ID is used only by the SP to indicate it has
436*54fd6939SJiyong Park 	 * finished initialising itself after a cold boot
437*54fd6939SJiyong Park 	 */
438*54fd6939SJiyong Park 	case TSP_ENTRY_DONE:
439*54fd6939SJiyong Park 		if (ns)
440*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
441*54fd6939SJiyong Park 
442*54fd6939SJiyong Park 		/*
443*54fd6939SJiyong Park 		 * Stash the SP entry points information. This is done
444*54fd6939SJiyong Park 		 * only once on the primary cpu
445*54fd6939SJiyong Park 		 */
446*54fd6939SJiyong Park 		assert(tsp_vectors == NULL);
447*54fd6939SJiyong Park 		tsp_vectors = (tsp_vectors_t *) x1;
448*54fd6939SJiyong Park 
449*54fd6939SJiyong Park 		if (tsp_vectors) {
450*54fd6939SJiyong Park 			set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
451*54fd6939SJiyong Park 
452*54fd6939SJiyong Park 			/*
453*54fd6939SJiyong Park 			 * TSP has been successfully initialized. Register power
454*54fd6939SJiyong Park 			 * management hooks with PSCI
455*54fd6939SJiyong Park 			 */
456*54fd6939SJiyong Park 			psci_register_spd_pm_hook(&tspd_pm);
457*54fd6939SJiyong Park 
458*54fd6939SJiyong Park 			/*
459*54fd6939SJiyong Park 			 * Register an interrupt handler for S-EL1 interrupts
460*54fd6939SJiyong Park 			 * when generated during code executing in the
461*54fd6939SJiyong Park 			 * non-secure state.
462*54fd6939SJiyong Park 			 */
463*54fd6939SJiyong Park 			flags = 0;
464*54fd6939SJiyong Park 			set_interrupt_rm_flag(flags, NON_SECURE);
465*54fd6939SJiyong Park 			rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
466*54fd6939SJiyong Park 						tspd_sel1_interrupt_handler,
467*54fd6939SJiyong Park 						flags);
468*54fd6939SJiyong Park 			if (rc)
469*54fd6939SJiyong Park 				panic();
470*54fd6939SJiyong Park 
471*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
472*54fd6939SJiyong Park 			/*
473*54fd6939SJiyong Park 			 * Register an interrupt handler for NS interrupts when
474*54fd6939SJiyong Park 			 * generated during code executing in secure state are
475*54fd6939SJiyong Park 			 * routed to EL3.
476*54fd6939SJiyong Park 			 */
477*54fd6939SJiyong Park 			flags = 0;
478*54fd6939SJiyong Park 			set_interrupt_rm_flag(flags, SECURE);
479*54fd6939SJiyong Park 
480*54fd6939SJiyong Park 			rc = register_interrupt_type_handler(INTR_TYPE_NS,
481*54fd6939SJiyong Park 						tspd_ns_interrupt_handler,
482*54fd6939SJiyong Park 						flags);
483*54fd6939SJiyong Park 			if (rc)
484*54fd6939SJiyong Park 				panic();
485*54fd6939SJiyong Park 
486*54fd6939SJiyong Park 			/*
487*54fd6939SJiyong Park 			 * Disable the NS interrupt locally.
488*54fd6939SJiyong Park 			 */
489*54fd6939SJiyong Park 			disable_intr_rm_local(INTR_TYPE_NS, SECURE);
490*54fd6939SJiyong Park #endif
491*54fd6939SJiyong Park 		}
492*54fd6939SJiyong Park 
493*54fd6939SJiyong Park 
494*54fd6939SJiyong Park #if TSP_INIT_ASYNC
495*54fd6939SJiyong Park 		/* Save the Secure EL1 system register context */
496*54fd6939SJiyong Park 		assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx);
497*54fd6939SJiyong Park 		cm_el1_sysregs_context_save(SECURE);
498*54fd6939SJiyong Park 
499*54fd6939SJiyong Park 		/* Program EL3 registers to enable entry into the next EL */
500*54fd6939SJiyong Park 		next_image_info = bl31_plat_get_next_image_ep_info(NON_SECURE);
501*54fd6939SJiyong Park 		assert(next_image_info);
502*54fd6939SJiyong Park 		assert(NON_SECURE ==
503*54fd6939SJiyong Park 				GET_SECURITY_STATE(next_image_info->h.attr));
504*54fd6939SJiyong Park 
505*54fd6939SJiyong Park 		cm_init_my_context(next_image_info);
506*54fd6939SJiyong Park 		cm_prepare_el3_exit(NON_SECURE);
507*54fd6939SJiyong Park 		SMC_RET0(cm_get_context(NON_SECURE));
508*54fd6939SJiyong Park #else
509*54fd6939SJiyong Park 		/*
510*54fd6939SJiyong Park 		 * SP reports completion. The SPD must have initiated
511*54fd6939SJiyong Park 		 * the original request through a synchronous entry
512*54fd6939SJiyong Park 		 * into the SP. Jump back to the original C runtime
513*54fd6939SJiyong Park 		 * context.
514*54fd6939SJiyong Park 		 */
515*54fd6939SJiyong Park 		tspd_synchronous_sp_exit(tsp_ctx, x1);
516*54fd6939SJiyong Park 		break;
517*54fd6939SJiyong Park #endif
518*54fd6939SJiyong Park 	/*
519*54fd6939SJiyong Park 	 * This function ID is used only by the SP to indicate it has finished
520*54fd6939SJiyong Park 	 * aborting a preempted Yielding SMC Call.
521*54fd6939SJiyong Park 	 */
522*54fd6939SJiyong Park 	case TSP_ABORT_DONE:
523*54fd6939SJiyong Park 
524*54fd6939SJiyong Park 	/*
525*54fd6939SJiyong Park 	 * These function IDs are used only by the SP to indicate it has
526*54fd6939SJiyong Park 	 * finished:
527*54fd6939SJiyong Park 	 * 1. turning itself on in response to an earlier psci
528*54fd6939SJiyong Park 	 *    cpu_on request
529*54fd6939SJiyong Park 	 * 2. resuming itself after an earlier psci cpu_suspend
530*54fd6939SJiyong Park 	 *    request.
531*54fd6939SJiyong Park 	 */
532*54fd6939SJiyong Park 	case TSP_ON_DONE:
533*54fd6939SJiyong Park 	case TSP_RESUME_DONE:
534*54fd6939SJiyong Park 
535*54fd6939SJiyong Park 	/*
536*54fd6939SJiyong Park 	 * These function IDs are used only by the SP to indicate it has
537*54fd6939SJiyong Park 	 * finished:
538*54fd6939SJiyong Park 	 * 1. suspending itself after an earlier psci cpu_suspend
539*54fd6939SJiyong Park 	 *    request.
540*54fd6939SJiyong Park 	 * 2. turning itself off in response to an earlier psci
541*54fd6939SJiyong Park 	 *    cpu_off request.
542*54fd6939SJiyong Park 	 */
543*54fd6939SJiyong Park 	case TSP_OFF_DONE:
544*54fd6939SJiyong Park 	case TSP_SUSPEND_DONE:
545*54fd6939SJiyong Park 	case TSP_SYSTEM_OFF_DONE:
546*54fd6939SJiyong Park 	case TSP_SYSTEM_RESET_DONE:
547*54fd6939SJiyong Park 		if (ns)
548*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
549*54fd6939SJiyong Park 
550*54fd6939SJiyong Park 		/*
551*54fd6939SJiyong Park 		 * SP reports completion. The SPD must have initiated the
552*54fd6939SJiyong Park 		 * original request through a synchronous entry into the SP.
553*54fd6939SJiyong Park 		 * Jump back to the original C runtime context, and pass x1 as
554*54fd6939SJiyong Park 		 * return value to the caller
555*54fd6939SJiyong Park 		 */
556*54fd6939SJiyong Park 		tspd_synchronous_sp_exit(tsp_ctx, x1);
557*54fd6939SJiyong Park 		break;
558*54fd6939SJiyong Park 
559*54fd6939SJiyong Park 		/*
560*54fd6939SJiyong Park 		 * Request from non-secure client to perform an
561*54fd6939SJiyong Park 		 * arithmetic operation or response from secure
562*54fd6939SJiyong Park 		 * payload to an earlier request.
563*54fd6939SJiyong Park 		 */
564*54fd6939SJiyong Park 	case TSP_FAST_FID(TSP_ADD):
565*54fd6939SJiyong Park 	case TSP_FAST_FID(TSP_SUB):
566*54fd6939SJiyong Park 	case TSP_FAST_FID(TSP_MUL):
567*54fd6939SJiyong Park 	case TSP_FAST_FID(TSP_DIV):
568*54fd6939SJiyong Park 
569*54fd6939SJiyong Park 	case TSP_YIELD_FID(TSP_ADD):
570*54fd6939SJiyong Park 	case TSP_YIELD_FID(TSP_SUB):
571*54fd6939SJiyong Park 	case TSP_YIELD_FID(TSP_MUL):
572*54fd6939SJiyong Park 	case TSP_YIELD_FID(TSP_DIV):
573*54fd6939SJiyong Park 		if (ns) {
574*54fd6939SJiyong Park 			/*
575*54fd6939SJiyong Park 			 * This is a fresh request from the non-secure client.
576*54fd6939SJiyong Park 			 * The parameters are in x1 and x2. Figure out which
577*54fd6939SJiyong Park 			 * registers need to be preserved, save the non-secure
578*54fd6939SJiyong Park 			 * state and send the request to the secure payload.
579*54fd6939SJiyong Park 			 */
580*54fd6939SJiyong Park 			assert(handle == cm_get_context(NON_SECURE));
581*54fd6939SJiyong Park 
582*54fd6939SJiyong Park 			/* Check if we are already preempted */
583*54fd6939SJiyong Park 			if (get_yield_smc_active_flag(tsp_ctx->state))
584*54fd6939SJiyong Park 				SMC_RET1(handle, SMC_UNK);
585*54fd6939SJiyong Park 
586*54fd6939SJiyong Park 			cm_el1_sysregs_context_save(NON_SECURE);
587*54fd6939SJiyong Park 
588*54fd6939SJiyong Park 			/* Save x1 and x2 for use by TSP_GET_ARGS call below */
589*54fd6939SJiyong Park 			store_tsp_args(tsp_ctx, x1, x2);
590*54fd6939SJiyong Park 
591*54fd6939SJiyong Park 			/*
592*54fd6939SJiyong Park 			 * We are done stashing the non-secure context. Ask the
593*54fd6939SJiyong Park 			 * secure payload to do the work now.
594*54fd6939SJiyong Park 			 */
595*54fd6939SJiyong Park 
596*54fd6939SJiyong Park 			/*
597*54fd6939SJiyong Park 			 * Verify if there is a valid context to use, copy the
598*54fd6939SJiyong Park 			 * operation type and parameters to the secure context
599*54fd6939SJiyong Park 			 * and jump to the fast smc entry point in the secure
600*54fd6939SJiyong Park 			 * payload. Entry into S-EL1 will take place upon exit
601*54fd6939SJiyong Park 			 * from this function.
602*54fd6939SJiyong Park 			 */
603*54fd6939SJiyong Park 			assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE));
604*54fd6939SJiyong Park 
605*54fd6939SJiyong Park 			/* Set appropriate entry for SMC.
606*54fd6939SJiyong Park 			 * We expect the TSP to manage the PSTATE.I and PSTATE.F
607*54fd6939SJiyong Park 			 * flags as appropriate.
608*54fd6939SJiyong Park 			 */
609*54fd6939SJiyong Park 			if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) {
610*54fd6939SJiyong Park 				cm_set_elr_el3(SECURE, (uint64_t)
611*54fd6939SJiyong Park 						&tsp_vectors->fast_smc_entry);
612*54fd6939SJiyong Park 			} else {
613*54fd6939SJiyong Park 				set_yield_smc_active_flag(tsp_ctx->state);
614*54fd6939SJiyong Park 				cm_set_elr_el3(SECURE, (uint64_t)
615*54fd6939SJiyong Park 						&tsp_vectors->yield_smc_entry);
616*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
617*54fd6939SJiyong Park 				/*
618*54fd6939SJiyong Park 				 * Enable the routing of NS interrupts to EL3
619*54fd6939SJiyong Park 				 * during processing of a Yielding SMC Call on
620*54fd6939SJiyong Park 				 * this core.
621*54fd6939SJiyong Park 				 */
622*54fd6939SJiyong Park 				enable_intr_rm_local(INTR_TYPE_NS, SECURE);
623*54fd6939SJiyong Park #endif
624*54fd6939SJiyong Park 
625*54fd6939SJiyong Park #if EL3_EXCEPTION_HANDLING
626*54fd6939SJiyong Park 				/*
627*54fd6939SJiyong Park 				 * With EL3 exception handling, while an SMC is
628*54fd6939SJiyong Park 				 * being processed, Non-secure interrupts can't
629*54fd6939SJiyong Park 				 * preempt Secure execution. However, for
630*54fd6939SJiyong Park 				 * yielding SMCs, we want preemption to happen;
631*54fd6939SJiyong Park 				 * so explicitly allow NS preemption in this
632*54fd6939SJiyong Park 				 * case, and supply the preemption return code
633*54fd6939SJiyong Park 				 * for TSP.
634*54fd6939SJiyong Park 				 */
635*54fd6939SJiyong Park 				ehf_allow_ns_preemption(TSP_PREEMPTED);
636*54fd6939SJiyong Park #endif
637*54fd6939SJiyong Park 			}
638*54fd6939SJiyong Park 
639*54fd6939SJiyong Park 			cm_el1_sysregs_context_restore(SECURE);
640*54fd6939SJiyong Park 			cm_set_next_eret_context(SECURE);
641*54fd6939SJiyong Park 			SMC_RET3(&tsp_ctx->cpu_ctx, smc_fid, x1, x2);
642*54fd6939SJiyong Park 		} else {
643*54fd6939SJiyong Park 			/*
644*54fd6939SJiyong Park 			 * This is the result from the secure client of an
645*54fd6939SJiyong Park 			 * earlier request. The results are in x1-x3. Copy it
646*54fd6939SJiyong Park 			 * into the non-secure context, save the secure state
647*54fd6939SJiyong Park 			 * and return to the non-secure state.
648*54fd6939SJiyong Park 			 */
649*54fd6939SJiyong Park 			assert(handle == cm_get_context(SECURE));
650*54fd6939SJiyong Park 			cm_el1_sysregs_context_save(SECURE);
651*54fd6939SJiyong Park 
652*54fd6939SJiyong Park 			/* Get a reference to the non-secure context */
653*54fd6939SJiyong Park 			ns_cpu_context = cm_get_context(NON_SECURE);
654*54fd6939SJiyong Park 			assert(ns_cpu_context);
655*54fd6939SJiyong Park 
656*54fd6939SJiyong Park 			/* Restore non-secure state */
657*54fd6939SJiyong Park 			cm_el1_sysregs_context_restore(NON_SECURE);
658*54fd6939SJiyong Park 			cm_set_next_eret_context(NON_SECURE);
659*54fd6939SJiyong Park 			if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_YIELD) {
660*54fd6939SJiyong Park 				clr_yield_smc_active_flag(tsp_ctx->state);
661*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
662*54fd6939SJiyong Park 				/*
663*54fd6939SJiyong Park 				 * Disable the routing of NS interrupts to EL3
664*54fd6939SJiyong Park 				 * after processing of a Yielding SMC Call on
665*54fd6939SJiyong Park 				 * this core is finished.
666*54fd6939SJiyong Park 				 */
667*54fd6939SJiyong Park 				disable_intr_rm_local(INTR_TYPE_NS, SECURE);
668*54fd6939SJiyong Park #endif
669*54fd6939SJiyong Park 			}
670*54fd6939SJiyong Park 
671*54fd6939SJiyong Park 			SMC_RET3(ns_cpu_context, x1, x2, x3);
672*54fd6939SJiyong Park 		}
673*54fd6939SJiyong Park 		assert(0); /* Unreachable */
674*54fd6939SJiyong Park 
675*54fd6939SJiyong Park 	/*
676*54fd6939SJiyong Park 	 * Request from the non-secure world to abort a preempted Yielding SMC
677*54fd6939SJiyong Park 	 * Call.
678*54fd6939SJiyong Park 	 */
679*54fd6939SJiyong Park 	case TSP_FID_ABORT:
680*54fd6939SJiyong Park 		/* ABORT should only be invoked by normal world */
681*54fd6939SJiyong Park 		if (!ns) {
682*54fd6939SJiyong Park 			assert(0);
683*54fd6939SJiyong Park 			break;
684*54fd6939SJiyong Park 		}
685*54fd6939SJiyong Park 
686*54fd6939SJiyong Park 		assert(handle == cm_get_context(NON_SECURE));
687*54fd6939SJiyong Park 		cm_el1_sysregs_context_save(NON_SECURE);
688*54fd6939SJiyong Park 
689*54fd6939SJiyong Park 		/* Abort the preempted SMC request */
690*54fd6939SJiyong Park 		if (!tspd_abort_preempted_smc(tsp_ctx)) {
691*54fd6939SJiyong Park 			/*
692*54fd6939SJiyong Park 			 * If there was no preempted SMC to abort, return
693*54fd6939SJiyong Park 			 * SMC_UNK.
694*54fd6939SJiyong Park 			 *
695*54fd6939SJiyong Park 			 * Restoring the NON_SECURE context is not necessary as
696*54fd6939SJiyong Park 			 * the synchronous entry did not take place if the
697*54fd6939SJiyong Park 			 * return code of tspd_abort_preempted_smc is zero.
698*54fd6939SJiyong Park 			 */
699*54fd6939SJiyong Park 			cm_set_next_eret_context(NON_SECURE);
700*54fd6939SJiyong Park 			break;
701*54fd6939SJiyong Park 		}
702*54fd6939SJiyong Park 
703*54fd6939SJiyong Park 		cm_el1_sysregs_context_restore(NON_SECURE);
704*54fd6939SJiyong Park 		cm_set_next_eret_context(NON_SECURE);
705*54fd6939SJiyong Park 		SMC_RET1(handle, SMC_OK);
706*54fd6939SJiyong Park 
707*54fd6939SJiyong Park 		/*
708*54fd6939SJiyong Park 		 * Request from non secure world to resume the preempted
709*54fd6939SJiyong Park 		 * Yielding SMC Call.
710*54fd6939SJiyong Park 		 */
711*54fd6939SJiyong Park 	case TSP_FID_RESUME:
712*54fd6939SJiyong Park 		/* RESUME should be invoked only by normal world */
713*54fd6939SJiyong Park 		if (!ns) {
714*54fd6939SJiyong Park 			assert(0);
715*54fd6939SJiyong Park 			break;
716*54fd6939SJiyong Park 		}
717*54fd6939SJiyong Park 
718*54fd6939SJiyong Park 		/*
719*54fd6939SJiyong Park 		 * This is a resume request from the non-secure client.
720*54fd6939SJiyong Park 		 * save the non-secure state and send the request to
721*54fd6939SJiyong Park 		 * the secure payload.
722*54fd6939SJiyong Park 		 */
723*54fd6939SJiyong Park 		assert(handle == cm_get_context(NON_SECURE));
724*54fd6939SJiyong Park 
725*54fd6939SJiyong Park 		/* Check if we are already preempted before resume */
726*54fd6939SJiyong Park 		if (!get_yield_smc_active_flag(tsp_ctx->state))
727*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
728*54fd6939SJiyong Park 
729*54fd6939SJiyong Park 		cm_el1_sysregs_context_save(NON_SECURE);
730*54fd6939SJiyong Park 
731*54fd6939SJiyong Park 		/*
732*54fd6939SJiyong Park 		 * We are done stashing the non-secure context. Ask the
733*54fd6939SJiyong Park 		 * secure payload to do the work now.
734*54fd6939SJiyong Park 		 */
735*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
736*54fd6939SJiyong Park 		/*
737*54fd6939SJiyong Park 		 * Enable the routing of NS interrupts to EL3 during resumption
738*54fd6939SJiyong Park 		 * of a Yielding SMC Call on this core.
739*54fd6939SJiyong Park 		 */
740*54fd6939SJiyong Park 		enable_intr_rm_local(INTR_TYPE_NS, SECURE);
741*54fd6939SJiyong Park #endif
742*54fd6939SJiyong Park 
743*54fd6939SJiyong Park #if EL3_EXCEPTION_HANDLING
744*54fd6939SJiyong Park 		/*
745*54fd6939SJiyong Park 		 * Allow the resumed yielding SMC processing to be preempted by
746*54fd6939SJiyong Park 		 * Non-secure interrupts. Also, supply the preemption return
747*54fd6939SJiyong Park 		 * code for TSP.
748*54fd6939SJiyong Park 		 */
749*54fd6939SJiyong Park 		ehf_allow_ns_preemption(TSP_PREEMPTED);
750*54fd6939SJiyong Park #endif
751*54fd6939SJiyong Park 
752*54fd6939SJiyong Park 		/* We just need to return to the preempted point in
753*54fd6939SJiyong Park 		 * TSP and the execution will resume as normal.
754*54fd6939SJiyong Park 		 */
755*54fd6939SJiyong Park 		cm_el1_sysregs_context_restore(SECURE);
756*54fd6939SJiyong Park 		cm_set_next_eret_context(SECURE);
757*54fd6939SJiyong Park 		SMC_RET0(&tsp_ctx->cpu_ctx);
758*54fd6939SJiyong Park 
759*54fd6939SJiyong Park 		/*
760*54fd6939SJiyong Park 		 * This is a request from the secure payload for more arguments
761*54fd6939SJiyong Park 		 * for an ongoing arithmetic operation requested by the
762*54fd6939SJiyong Park 		 * non-secure world. Simply return the arguments from the non-
763*54fd6939SJiyong Park 		 * secure client in the original call.
764*54fd6939SJiyong Park 		 */
765*54fd6939SJiyong Park 	case TSP_GET_ARGS:
766*54fd6939SJiyong Park 		if (ns)
767*54fd6939SJiyong Park 			SMC_RET1(handle, SMC_UNK);
768*54fd6939SJiyong Park 
769*54fd6939SJiyong Park 		get_tsp_args(tsp_ctx, x1, x2);
770*54fd6939SJiyong Park 		SMC_RET2(handle, x1, x2);
771*54fd6939SJiyong Park 
772*54fd6939SJiyong Park 	case TOS_CALL_COUNT:
773*54fd6939SJiyong Park 		/*
774*54fd6939SJiyong Park 		 * Return the number of service function IDs implemented to
775*54fd6939SJiyong Park 		 * provide service to non-secure
776*54fd6939SJiyong Park 		 */
777*54fd6939SJiyong Park 		SMC_RET1(handle, TSP_NUM_FID);
778*54fd6939SJiyong Park 
779*54fd6939SJiyong Park 	case TOS_UID:
780*54fd6939SJiyong Park 		/* Return TSP UID to the caller */
781*54fd6939SJiyong Park 		SMC_UUID_RET(handle, tsp_uuid);
782*54fd6939SJiyong Park 
783*54fd6939SJiyong Park 	case TOS_CALL_VERSION:
784*54fd6939SJiyong Park 		/* Return the version of current implementation */
785*54fd6939SJiyong Park 		SMC_RET2(handle, TSP_VERSION_MAJOR, TSP_VERSION_MINOR);
786*54fd6939SJiyong Park 
787*54fd6939SJiyong Park 	default:
788*54fd6939SJiyong Park 		break;
789*54fd6939SJiyong Park 	}
790*54fd6939SJiyong Park 
791*54fd6939SJiyong Park 	SMC_RET1(handle, SMC_UNK);
792*54fd6939SJiyong Park }
793*54fd6939SJiyong Park 
794*54fd6939SJiyong Park /* Define a SPD runtime service descriptor for fast SMC calls */
795*54fd6939SJiyong Park DECLARE_RT_SVC(
796*54fd6939SJiyong Park 	tspd_fast,
797*54fd6939SJiyong Park 
798*54fd6939SJiyong Park 	OEN_TOS_START,
799*54fd6939SJiyong Park 	OEN_TOS_END,
800*54fd6939SJiyong Park 	SMC_TYPE_FAST,
801*54fd6939SJiyong Park 	tspd_setup,
802*54fd6939SJiyong Park 	tspd_smc_handler
803*54fd6939SJiyong Park );
804*54fd6939SJiyong Park 
805*54fd6939SJiyong Park /* Define a SPD runtime service descriptor for Yielding SMC Calls */
806*54fd6939SJiyong Park DECLARE_RT_SVC(
807*54fd6939SJiyong Park 	tspd_std,
808*54fd6939SJiyong Park 
809*54fd6939SJiyong Park 	OEN_TOS_START,
810*54fd6939SJiyong Park 	OEN_TOS_END,
811*54fd6939SJiyong Park 	SMC_TYPE_YIELD,
812*54fd6939SJiyong Park 	NULL,
813*54fd6939SJiyong Park 	tspd_smc_handler
814*54fd6939SJiyong Park );
815