blob: cc1c1f2863f9cb4dcf2d1fbf541c42c21394ed57 [file] [log] [blame]
Florian Lugou71d33be2021-09-08 12:42:54 +02001/*
2 * Copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*******************************************************************************
8 * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a
9 * plug-in component to the Secure Monitor, registered as a runtime service. The
10 * SPD is expected to be a functional extension of the Secure Payload (SP) that
11 * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting
12 * the Trusted OS/Applications range to the dispatcher. The SPD will either
13 * handle the request locally or delegate it to the Secure Payload. It is also
14 * responsible for initialising and maintaining communication with the SP.
15 ******************************************************************************/
16
17#include <assert.h>
18#include <errno.h>
19#include <stddef.h>
20#include <string.h>
21
22#include <arch_helpers.h>
23#include <bl31/bl31.h>
24#include <bl31/interrupt_mgmt.h>
25#include <bl_common.h>
26#include <common/debug.h>
27#include <common/ep_info.h>
28#include <drivers/arm/gic_common.h>
29#include <lib/el3_runtime/context_mgmt.h>
30#include <lib/spinlock.h>
31#include <plat/common/platform.h>
32#include <pnc.h>
33#include "pncd_private.h"
34#include <runtime_svc.h>
35#include <tools_share/uuid.h>
36
37/*******************************************************************************
38 * Structure to keep track of ProvenCore state
39 ******************************************************************************/
40static pnc_context_t pncd_sp_context;
41
42static bool ree_info;
43static uint64_t ree_base_addr;
44static uint64_t ree_length;
45static uint64_t ree_tag;
46
47static bool pnc_initialized;
48
49static spinlock_t smc_handler_lock;
50
51static int pncd_init(void);
52
53static void context_save(unsigned long security_state)
54{
55 assert(sec_state_is_valid(security_state));
56
57 cm_el1_sysregs_context_save((uint32_t) security_state);
Madhukar Pappireddy8eb7e802024-04-25 22:56:29 -050058
Florian Lugou71d33be2021-09-08 12:42:54 +020059#if CTX_INCLUDE_FPREGS
Madhukar Pappireddy8eb7e802024-04-25 22:56:29 -050060 simd_ctx_save((uint32_t)security_state, false);
Florian Lugou71d33be2021-09-08 12:42:54 +020061#endif
62}
63
64static void *context_restore(unsigned long security_state)
65{
66 void *handle;
67
68 assert(sec_state_is_valid(security_state));
69
70 /* Get a reference to the next context */
71 handle = cm_get_context((uint32_t) security_state);
72 assert(handle);
73
74 /* Restore state */
75 cm_el1_sysregs_context_restore((uint32_t) security_state);
Madhukar Pappireddy8eb7e802024-04-25 22:56:29 -050076
Florian Lugou71d33be2021-09-08 12:42:54 +020077#if CTX_INCLUDE_FPREGS
Madhukar Pappireddy8eb7e802024-04-25 22:56:29 -050078 simd_ctx_restore((uint32_t)security_state);
Florian Lugou71d33be2021-09-08 12:42:54 +020079#endif
80
81 cm_set_next_eret_context((uint32_t) security_state);
82
83 return handle;
84}
85
86static uint64_t pncd_sel1_interrupt_handler(uint32_t id,
87 uint32_t flags, void *handle, void *cookie);
88
89/*******************************************************************************
90 * Switch context to the specified security state and return the targeted
91 * handle. Note that the context may remain unchanged if the switch is not
92 * allowed.
93 ******************************************************************************/
94void *pncd_context_switch_to(unsigned long security_state)
95{
96 unsigned long sec_state_from =
97 security_state == SECURE ? NON_SECURE : SECURE;
98
99 assert(sec_state_is_valid(security_state));
100
101 /* Check if this is the first world switch */
102 if (!pnc_initialized) {
103 int rc;
104 uint32_t flags;
105
106 assert(sec_state_from == SECURE);
107
108 INFO("PnC initialization done\n");
109
110 /*
111 * Register an interrupt handler for S-EL1 interrupts
112 * when generated during code executing in the
113 * non-secure state.
114 */
115 flags = 0U;
116 set_interrupt_rm_flag(flags, NON_SECURE);
117 rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
118 pncd_sel1_interrupt_handler,
119 flags);
120 if (rc != 0) {
121 ERROR("Failed to register S-EL1 interrupt handler (%d)\n",
122 rc);
123 panic();
124 }
125
126 context_save(SECURE);
127
128 pnc_initialized = true;
129
130 /*
131 * Release the lock before restoring the EL3 context to
132 * bl31_main.
133 */
134 spin_unlock(&smc_handler_lock);
135
136 /*
137 * SP reports completion. The SPD must have initiated
138 * the original request through a synchronous entry
139 * into the SP. Jump back to the original C runtime
140 * context.
141 */
142 pncd_synchronous_sp_exit(&pncd_sp_context, (uint64_t) 0x0);
143
144 /* Unreachable */
145 ERROR("Returned from pncd_synchronous_sp_exit... Should not happen\n");
146 panic();
147 }
148
149 /* Check that the world switch is allowed */
150 if (read_mpidr() != pncd_sp_context.mpidr) {
151 if (sec_state_from == SECURE) {
152 /*
153 * Secure -> Non-Secure world switch initiated on a CPU where there
154 * should be no Trusted OS running
155 */
156 WARN("Secure to Non-Secure switch requested on CPU where ProvenCore is not supposed to be running...\n");
157 }
158
159 /*
160 * Secure or Non-Secure world wants to switch world but there is no Secure
161 * software on this core
162 */
163 return cm_get_context((uint32_t) sec_state_from);
164 }
165
166 context_save(sec_state_from);
167
168 return context_restore(security_state);
169}
170
171/*******************************************************************************
172 * This function is the handler registered for S-EL1 interrupts by the PNCD. It
173 * validates the interrupt and upon success arranges entry into the PNC at
174 * 'pnc_sel1_intr_entry()' for handling the interrupt.
175 ******************************************************************************/
176static uint64_t pncd_sel1_interrupt_handler(uint32_t id,
177 uint32_t flags,
178 void *handle,
179 void *cookie)
180{
181 /* Check the security state when the exception was generated */
182 assert(get_interrupt_src_ss(flags) == NON_SECURE);
183
184 /* Sanity check the pointer to this cpu's context */
185 assert(handle == cm_get_context(NON_SECURE));
186
187 /* switch to PnC */
188 handle = pncd_context_switch_to(SECURE);
189
190 assert(handle != NULL);
191
192 SMC_RET0(handle);
193}
194
195#pragma weak plat_pncd_setup
196int plat_pncd_setup(void)
197{
198 return 0;
199}
200
201/*******************************************************************************
202 * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type
203 * (aarch32/aarch64) if not already known and initialises the context for entry
204 * into the SP for its initialisation.
205 ******************************************************************************/
206static int pncd_setup(void)
207{
208 entry_point_info_t *pnc_ep_info;
209
210 /*
211 * Get information about the Secure Payload (BL32) image. Its
212 * absence is a critical failure.
213 *
214 * TODO: Add support to conditionally include the SPD service
215 */
216 pnc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
217 if (!pnc_ep_info) {
218 WARN("No PNC provided by BL2 boot loader, Booting device without PNC initialization. SMC`s destined for PNC will return SMC_UNK\n");
219 return 1;
220 }
221
222 /*
223 * If there's no valid entry point for SP, we return a non-zero value
224 * signalling failure initializing the service. We bail out without
225 * registering any handlers
226 */
227 if (!pnc_ep_info->pc) {
228 return 1;
229 }
230
231 pncd_init_pnc_ep_state(pnc_ep_info,
232 pnc_ep_info->pc,
233 &pncd_sp_context);
234
235 /*
236 * All PNCD initialization done. Now register our init function with
237 * BL31 for deferred invocation
238 */
239 bl31_register_bl32_init(&pncd_init);
240 bl31_set_next_image_type(NON_SECURE);
241
242 return plat_pncd_setup();
243}
244
245/*******************************************************************************
246 * This function passes control to the Secure Payload image (BL32) for the first
247 * time on the primary cpu after a cold boot. It assumes that a valid secure
248 * context has already been created by pncd_setup() which can be directly used.
249 * It also assumes that a valid non-secure context has been initialised by PSCI
250 * so it does not need to save and restore any non-secure state. This function
251 * performs a synchronous entry into the Secure payload. The SP passes control
252 * back to this routine through a SMC.
253 ******************************************************************************/
254static int32_t pncd_init(void)
255{
256 entry_point_info_t *pnc_entry_point;
257 uint64_t rc = 0;
258
259 /*
260 * Get information about the Secure Payload (BL32) image. Its
261 * absence is a critical failure.
262 */
263 pnc_entry_point = bl31_plat_get_next_image_ep_info(SECURE);
264 assert(pnc_entry_point);
265
266 cm_init_my_context(pnc_entry_point);
267
268 /*
269 * Arrange for an entry into the test secure payload. It will be
270 * returned via PNC_ENTRY_DONE case
271 */
272 rc = pncd_synchronous_sp_entry(&pncd_sp_context);
273
274 /*
275 * If everything went well at this point, the return value should be 0.
276 */
277 return rc == 0;
278}
279
280#pragma weak plat_pncd_smc_handler
281/*******************************************************************************
282 * This function is responsible for handling the platform-specific SMCs in the
283 * Trusted OS/App range as defined in the SMC Calling Convention Document.
284 ******************************************************************************/
285uintptr_t plat_pncd_smc_handler(uint32_t smc_fid,
286 u_register_t x1,
287 u_register_t x2,
288 u_register_t x3,
289 u_register_t x4,
290 void *cookie,
291 void *handle,
292 u_register_t flags)
293{
294 (void) smc_fid;
295 (void) x1;
296 (void) x2;
297 (void) x3;
298 (void) x4;
299 (void) cookie;
300 (void) flags;
301
302 SMC_RET1(handle, SMC_UNK);
303}
304
305/*******************************************************************************
306 * This function is responsible for handling all SMCs in the Trusted OS/App
307 * range as defined in the SMC Calling Convention Document. It is also
308 * responsible for communicating with the Secure payload to delegate work and
309 * return results back to the non-secure state. Lastly it will also return any
310 * information that the secure payload needs to do the work assigned to it.
311 *
312 * It should only be called with the smc_handler_lock held.
313 ******************************************************************************/
314static uintptr_t pncd_smc_handler_unsafe(uint32_t smc_fid,
315 u_register_t x1,
316 u_register_t x2,
317 u_register_t x3,
318 u_register_t x4,
319 void *cookie,
320 void *handle,
321 u_register_t flags)
322{
323 uint32_t ns;
324
325 /* Determine which security state this SMC originated from */
326 ns = is_caller_non_secure(flags);
327
328 assert(ns != 0 || read_mpidr() == pncd_sp_context.mpidr);
329
330 switch (smc_fid) {
331 case SMC_CONFIG_SHAREDMEM:
332 if (ree_info) {
333 /* Do not Yield */
334 SMC_RET0(handle);
335 }
336
337 /*
338 * Fetch the physical base address (x1) and size (x2) of the
339 * shared memory allocated by the Non-Secure world. This memory
340 * will be used by PNC to communicate with the Non-Secure world.
341 * Verifying the validity of these values is up to the Trusted
342 * OS.
343 */
344 ree_base_addr = x1 | (x2 << 32);
345 ree_length = x3;
346 ree_tag = x4;
347
348 INFO("IN SMC_CONFIG_SHAREDMEM: addr=%lx, length=%lx, tag=%lx\n",
349 (unsigned long) ree_base_addr,
350 (unsigned long) ree_length,
351 (unsigned long) ree_tag);
352
353 if ((ree_base_addr % 0x200000) != 0) {
354 SMC_RET1(handle, SMC_UNK);
355 }
356
357 if ((ree_length % 0x200000) != 0) {
358 SMC_RET1(handle, SMC_UNK);
359 }
360
361 ree_info = true;
362
363 /* Do not Yield */
364 SMC_RET4(handle, 0, 0, 0, 0);
365
366 break;
367
368 case SMC_GET_SHAREDMEM:
369 if (ree_info) {
370 x1 = (1U << 16) | ree_tag;
371 x2 = ree_base_addr & 0xFFFFFFFF;
372 x3 = (ree_base_addr >> 32) & 0xFFFFFFFF;
373 x4 = ree_length & 0xFFFFFFFF;
374 SMC_RET4(handle, x1, x2, x3, x4);
375 } else {
376 SMC_RET4(handle, 0, 0, 0, 0);
377 }
378
379 break;
380
381 case SMC_ACTION_FROM_NS:
382 if (ns == 0) {
383 SMC_RET1(handle, SMC_UNK);
384 }
385
386 if (SPD_PNCD_S_IRQ < MIN_PPI_ID) {
387 plat_ic_raise_s_el1_sgi(SPD_PNCD_S_IRQ,
388 pncd_sp_context.mpidr);
389 } else {
390 plat_ic_set_interrupt_pending(SPD_PNCD_S_IRQ);
391 }
392
393 SMC_RET0(handle);
394
395 break;
396
397 case SMC_ACTION_FROM_S:
398 if (ns != 0) {
399 SMC_RET1(handle, SMC_UNK);
400 }
401
402 if (SPD_PNCD_NS_IRQ < MIN_PPI_ID) {
403 /*
404 * NS SGI is sent to the same core as the one running
405 * PNC
406 */
407 plat_ic_raise_ns_sgi(SPD_PNCD_NS_IRQ, read_mpidr());
408 } else {
409 plat_ic_set_interrupt_pending(SPD_PNCD_NS_IRQ);
410 }
411
412 SMC_RET0(handle);
413
414 break;
415
416 case SMC_YIELD:
417 assert(handle == cm_get_context(ns != 0 ? NON_SECURE : SECURE));
418 handle = pncd_context_switch_to(ns != 0 ? SECURE : NON_SECURE);
419
420 assert(handle != NULL);
421
422 SMC_RET0(handle);
423
424 break;
425
426 default:
427 INFO("Unknown smc: %x\n", smc_fid);
428 break;
429 }
430
431 return plat_pncd_smc_handler(smc_fid, x1, x2, x3, x4,
432 cookie, handle, flags);
433}
434
435static uintptr_t pncd_smc_handler(uint32_t smc_fid,
436 u_register_t x1,
437 u_register_t x2,
438 u_register_t x3,
439 u_register_t x4,
440 void *cookie,
441 void *handle,
442 u_register_t flags)
443{
444 uintptr_t ret;
445
446 /* SMC handling is serialized */
447 spin_lock(&smc_handler_lock);
448 ret = pncd_smc_handler_unsafe(smc_fid, x1, x2, x3, x4, cookie, handle,
449 flags);
450 spin_unlock(&smc_handler_lock);
451
452 return ret;
453}
454
455/* Define a SPD runtime service descriptor for fast SMC calls */
456DECLARE_RT_SVC(
457 pncd_fast,
458 OEN_TOS_START,
459 OEN_TOS_END,
460 SMC_TYPE_FAST,
461 pncd_setup,
462 pncd_smc_handler
463);
464
465/* Define a SPD runtime service descriptor for standard SMC calls */
466DECLARE_RT_SVC(
467 pncd_std,
468 OEN_TOS_START,
469 OEN_TOS_END,
470 SMC_TYPE_YIELD,
471 NULL,
472 pncd_smc_handler
473);