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