blob: cfd5a80ba75452ba572010411ba8fc4aad9a8f2b [file] [log] [blame]
Marc Bonnici8e1a7552021-12-01 17:57:04 +00001/*
2 * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <errno.h>
9
10#include <arch_helpers.h>
11#include <bl31/bl31.h>
12#include <bl31/ehf.h>
13#include <common/debug.h>
14#include <common/fdt_wrappers.h>
15#include <common/runtime_svc.h>
16#include <lib/el3_runtime/context_mgmt.h>
17#include <lib/smccc.h>
18#include <lib/utils.h>
19#include <lib/xlat_tables/xlat_tables_v2.h>
20#include <libfdt.h>
21#include <plat/common/platform.h>
22#include <services/ffa_svc.h>
23#include <services/spmc_svc.h>
24#include <services/spmd_svc.h>
25#include "spmc.h"
26
27#include <platform_def.h>
28
29/*
30 * Allocate a secure partition descriptor to describe each SP in the system that
31 * does not reside at EL3.
32 */
33static struct secure_partition_desc sp_desc[SECURE_PARTITION_COUNT];
34
35/*
36 * Allocate an NS endpoint descriptor to describe each VM and the Hypervisor in
37 * the system that interacts with a SP. It is used to track the Hypervisor
38 * buffer pair, version and ID for now. It could be extended to track VM
39 * properties when the SPMC supports indirect messaging.
40 */
41static struct ns_endpoint_desc ns_ep_desc[NS_PARTITION_COUNT];
42
43/*
44 * Helper function to obtain the descriptor of the last SP to whom control was
45 * handed to on this physical cpu. Currently, we assume there is only one SP.
46 * TODO: Expand to track multiple partitions when required.
47 */
48struct secure_partition_desc *spmc_get_current_sp_ctx(void)
49{
50 return &(sp_desc[ACTIVE_SP_DESC_INDEX]);
51}
52
53/*
54 * Helper function to obtain the execution context of an SP on the
55 * current physical cpu.
56 */
57struct sp_exec_ctx *spmc_get_sp_ec(struct secure_partition_desc *sp)
58{
59 return &(sp->ec[get_ec_index(sp)]);
60}
61
62/* Helper function to get pointer to SP context from its ID. */
63struct secure_partition_desc *spmc_get_sp_ctx(uint16_t id)
64{
65 /* Check for SWd Partitions. */
66 for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
67 if (sp_desc[i].sp_id == id) {
68 return &(sp_desc[i]);
69 }
70 }
71 return NULL;
72}
73
74/******************************************************************************
75 * This function returns to the place where spmc_sp_synchronous_entry() was
76 * called originally.
77 ******************************************************************************/
78__dead2 void spmc_sp_synchronous_exit(struct sp_exec_ctx *ec, uint64_t rc)
79{
80 /*
81 * The SPM must have initiated the original request through a
82 * synchronous entry into the secure partition. Jump back to the
83 * original C runtime context with the value of rc in x0;
84 */
85 spm_secure_partition_exit(ec->c_rt_ctx, rc);
86
87 panic();
88}
89
90/*******************************************************************************
91 * Return FFA_ERROR with specified error code.
92 ******************************************************************************/
93uint64_t spmc_ffa_error_return(void *handle, int error_code)
94{
95 SMC_RET8(handle, FFA_ERROR,
96 FFA_TARGET_INFO_MBZ, error_code,
97 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
98 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
99}
100
101/******************************************************************************
102 * Helper function to validate a secure partition ID to ensure it does not
103 * conflict with any other FF-A component and follows the convention to
104 * indicate it resides within the secure world.
105 ******************************************************************************/
106bool is_ffa_secure_id_valid(uint16_t partition_id)
107{
108 /* Ensure the ID is not the invalid partition ID. */
109 if (partition_id == INV_SP_ID) {
110 return false;
111 }
112
113 /* Ensure the ID is not the SPMD ID. */
114 if (partition_id == SPMD_DIRECT_MSG_ENDPOINT_ID) {
115 return false;
116 }
117
118 /*
119 * Ensure the ID follows the convention to indicate it resides
120 * in the secure world.
121 */
122 if (!ffa_is_secure_world_id(partition_id)) {
123 return false;
124 }
125
126 /* Ensure we don't conflict with the SPMC partition ID. */
127 if (partition_id == FFA_SPMC_ID) {
128 return false;
129 }
130
131 /* Ensure we do not already have an SP context with this ID. */
132 if (spmc_get_sp_ctx(partition_id)) {
133 return false;
134 }
135
136 return true;
137}
138
139/*******************************************************************************
Marc Bonnici7e19db82021-11-29 17:17:29 +0000140 * This function either forwards the request to the other world or returns
141 * with an ERET depending on the source of the call.
142 ******************************************************************************/
143static uint64_t spmc_smc_return(uint32_t smc_fid,
144 bool secure_origin,
145 uint64_t x1,
146 uint64_t x2,
147 uint64_t x3,
148 uint64_t x4,
149 void *handle,
150 void *cookie,
151 uint64_t flags,
152 uint16_t dst_id)
153{
154 /* If the destination is in the normal world always go via the SPMD. */
155 if (ffa_is_normal_world_id(dst_id)) {
156 return spmd_smc_handler(smc_fid, x1, x2, x3, x4,
157 cookie, handle, flags);
158 }
159 /*
160 * If the caller is secure and we want to return to the secure world,
161 * ERET directly.
162 */
163 else if (secure_origin && ffa_is_secure_world_id(dst_id)) {
164 SMC_RET5(handle, smc_fid, x1, x2, x3, x4);
165 }
166 /* If we originated in the normal world then switch contexts. */
167 else if (!secure_origin && ffa_is_secure_world_id(dst_id)) {
168 return spmd_smc_switch_state(smc_fid, secure_origin, x1, x2,
169 x3, x4, handle);
170 } else {
171 /* Unknown State. */
172 panic();
173 }
174
175 /* Shouldn't be Reached. */
176 return 0;
177}
178
179/*******************************************************************************
Marc Bonnici8eb15202021-11-29 17:05:33 +0000180 * FF-A ABI Handlers.
181 ******************************************************************************/
182/*******************************************************************************
183 * This function handles the FFA_MSG_WAIT SMC to allow an SP to relinquish its
184 * cycles.
185 ******************************************************************************/
186static uint64_t msg_wait_handler(uint32_t smc_fid,
187 bool secure_origin,
188 uint64_t x1,
189 uint64_t x2,
190 uint64_t x3,
191 uint64_t x4,
192 void *cookie,
193 void *handle,
194 uint64_t flags)
195{
196 struct secure_partition_desc *sp;
197 unsigned int idx;
198
199 /*
200 * Check that the response did not originate from the Normal world as
201 * only the secure world can call this ABI.
202 */
203 if (!secure_origin) {
204 VERBOSE("Normal world cannot call FFA_MSG_WAIT.\n");
205 return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
206 }
207
208 /* Get the descriptor of the SP that invoked FFA_MSG_WAIT. */
209 sp = spmc_get_current_sp_ctx();
210 if (sp == NULL) {
211 return spmc_ffa_error_return(handle,
212 FFA_ERROR_INVALID_PARAMETER);
213 }
214
215 /*
216 * Get the execution context of the SP that invoked FFA_MSG_WAIT.
217 */
218 idx = get_ec_index(sp);
219
220 /* Ensure SP execution context was in the right runtime model. */
221 if (sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
222 return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
223 }
224
225 /* Sanity check the state is being tracked correctly in the SPMC. */
226 assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
227
228 /*
229 * Perform a synchronous exit if the partition was initialising. The
230 * state is updated after the exit.
231 */
232 if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
233 spmc_sp_synchronous_exit(&sp->ec[idx], x4);
234 /* Should not get here */
235 panic();
236 }
237
238 /* Update the state of the SP execution context. */
239 sp->ec[idx].rt_state = RT_STATE_WAITING;
240
241 /* Resume normal world if a secure interrupt was handled. */
242 if (sp->ec[idx].rt_model == RT_MODEL_INTR) {
243 /* FFA_MSG_WAIT can only be called from the secure world. */
244 unsigned int secure_state_in = SECURE;
245 unsigned int secure_state_out = NON_SECURE;
246
247 cm_el1_sysregs_context_save(secure_state_in);
248 cm_el1_sysregs_context_restore(secure_state_out);
249 cm_set_next_eret_context(secure_state_out);
250 SMC_RET0(cm_get_context(secure_state_out));
251 }
252
253 /* Forward the response to the Normal world. */
254 return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
255 handle, cookie, flags, FFA_NWD_ID);
256}
257
Marc Bonnicib4e99842021-12-10 09:21:56 +0000258static uint64_t ffa_error_handler(uint32_t smc_fid,
259 bool secure_origin,
260 uint64_t x1,
261 uint64_t x2,
262 uint64_t x3,
263 uint64_t x4,
264 void *cookie,
265 void *handle,
266 uint64_t flags)
267{
268 struct secure_partition_desc *sp;
269 unsigned int idx;
270
271 /* Check that the response did not originate from the Normal world. */
272 if (!secure_origin) {
273 return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
274 }
275
276 /* Get the descriptor of the SP that invoked FFA_ERROR. */
277 sp = spmc_get_current_sp_ctx();
278 if (sp == NULL) {
279 return spmc_ffa_error_return(handle,
280 FFA_ERROR_INVALID_PARAMETER);
281 }
282
283 /* Get the execution context of the SP that invoked FFA_ERROR. */
284 idx = get_ec_index(sp);
285
286 /*
287 * We only expect FFA_ERROR to be received during SP initialisation
288 * otherwise this is an invalid call.
289 */
290 if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
291 ERROR("SP 0x%x failed to initialize.\n", sp->sp_id);
292 spmc_sp_synchronous_exit(&sp->ec[idx], x2);
293 /* Should not get here. */
294 panic();
295 }
296
297 return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
298}
299
Marc Bonnici8eb15202021-11-29 17:05:33 +0000300/*******************************************************************************
Marc Bonnici8e1a7552021-12-01 17:57:04 +0000301 * This function will parse the Secure Partition Manifest. From manifest, it
302 * will fetch details for preparing Secure partition image context and secure
303 * partition image boot arguments if any.
304 ******************************************************************************/
305static int sp_manifest_parse(void *sp_manifest, int offset,
306 struct secure_partition_desc *sp,
307 entry_point_info_t *ep_info)
308{
309 int32_t ret, node;
310 uint32_t config_32;
311
312 /*
313 * Look for the mandatory fields that are expected to be present in
314 * the SP manifests.
315 */
316 node = fdt_path_offset(sp_manifest, "/");
317 if (node < 0) {
318 ERROR("Did not find root node.\n");
319 return node;
320 }
321
322 ret = fdt_read_uint32(sp_manifest, node, "exception-level", &config_32);
323 if (ret != 0) {
324 ERROR("Missing SP Exception Level information.\n");
325 return ret;
326 }
327
328 sp->runtime_el = config_32;
329
330 ret = fdt_read_uint32(sp_manifest, node, "ffa-version", &config_32);
331 if (ret != 0) {
332 ERROR("Missing Secure Partition FF-A Version.\n");
333 return ret;
334 }
335
336 sp->ffa_version = config_32;
337
338 ret = fdt_read_uint32(sp_manifest, node, "execution-state", &config_32);
339 if (ret != 0) {
340 ERROR("Missing Secure Partition Execution State.\n");
341 return ret;
342 }
343
344 sp->execution_state = config_32;
345
346 /*
347 * Look for the optional fields that are expected to be present in
348 * an SP manifest.
349 */
350 ret = fdt_read_uint32(sp_manifest, node, "id", &config_32);
351 if (ret != 0) {
352 WARN("Missing Secure Partition ID.\n");
353 } else {
354 if (!is_ffa_secure_id_valid(config_32)) {
355 ERROR("Invalid Secure Partition ID (0x%x).\n",
356 config_32);
357 return -EINVAL;
358 }
359 sp->sp_id = config_32;
360 }
361
362 return 0;
363}
364
365/*******************************************************************************
366 * This function gets the Secure Partition Manifest base and maps the manifest
367 * region.
368 * Currently only one Secure Partition manifest is considered which is used to
369 * prepare the context for the single Secure Partition.
370 ******************************************************************************/
371static int find_and_prepare_sp_context(void)
372{
373 void *sp_manifest;
374 uintptr_t manifest_base;
375 uintptr_t manifest_base_align;
376 entry_point_info_t *next_image_ep_info;
377 int32_t ret;
378 struct secure_partition_desc *sp;
379
380 next_image_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
381 if (next_image_ep_info == NULL) {
382 WARN("No Secure Partition image provided by BL2.\n");
383 return -ENOENT;
384 }
385
386 sp_manifest = (void *)next_image_ep_info->args.arg0;
387 if (sp_manifest == NULL) {
388 WARN("Secure Partition manifest absent.\n");
389 return -ENOENT;
390 }
391
392 manifest_base = (uintptr_t)sp_manifest;
393 manifest_base_align = page_align(manifest_base, DOWN);
394
395 /*
396 * Map the secure partition manifest region in the EL3 translation
397 * regime.
398 * Map an area equal to (2 * PAGE_SIZE) for now. During manifest base
399 * alignment the region of 1 PAGE_SIZE from manifest align base may
400 * not completely accommodate the secure partition manifest region.
401 */
402 ret = mmap_add_dynamic_region((unsigned long long)manifest_base_align,
403 manifest_base_align,
404 PAGE_SIZE * 2,
405 MT_RO_DATA);
406 if (ret != 0) {
407 ERROR("Error while mapping SP manifest (%d).\n", ret);
408 return ret;
409 }
410
411 ret = fdt_node_offset_by_compatible(sp_manifest, -1,
412 "arm,ffa-manifest-1.0");
413 if (ret < 0) {
414 ERROR("Error happened in SP manifest reading.\n");
415 return -EINVAL;
416 }
417
418 /*
419 * Store the size of the manifest so that it can be used later to pass
420 * the manifest as boot information later.
421 */
422 next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest);
423 INFO("Manifest size = %lu bytes.\n", next_image_ep_info->args.arg1);
424
425 /*
426 * Select an SP descriptor for initialising the partition's execution
427 * context on the primary CPU.
428 */
429 sp = spmc_get_current_sp_ctx();
430
431 /* Initialize entry point information for the SP */
432 SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1,
433 SECURE | EP_ST_ENABLE);
434
435 /* Parse the SP manifest. */
436 ret = sp_manifest_parse(sp_manifest, ret, sp, next_image_ep_info);
437 if (ret != 0) {
438 ERROR("Error in Secure Partition manifest parsing.\n");
439 return ret;
440 }
441
442 /* Check that the runtime EL in the manifest was correct. */
443 if (sp->runtime_el != S_EL1) {
444 ERROR("Unexpected runtime EL: %d\n", sp->runtime_el);
445 return -EINVAL;
446 }
447
448 /* Perform any common initialisation. */
449 spmc_sp_common_setup(sp, next_image_ep_info);
450
451 /* Perform any initialisation specific to S-EL1 SPs. */
452 spmc_el1_sp_setup(sp, next_image_ep_info);
453
454 /* Initialize the SP context with the required ep info. */
455 spmc_sp_common_ep_commit(sp, next_image_ep_info);
456
457 return 0;
458}
459
460/*******************************************************************************
461 * This function takes an SP context pointer and performs a synchronous entry
462 * into it.
463 ******************************************************************************/
464uint64_t spmc_sp_synchronous_entry(struct sp_exec_ctx *ec)
465{
466 uint64_t rc;
467
468 assert(ec != NULL);
469
470 /* Assign the context of the SP to this CPU */
471 cm_set_context(&(ec->cpu_ctx), SECURE);
472
473 /* Restore the context assigned above */
474 cm_el1_sysregs_context_restore(SECURE);
475 cm_set_next_eret_context(SECURE);
476
477 /* Invalidate TLBs at EL1. */
478 tlbivmalle1();
479 dsbish();
480
481 /* Enter Secure Partition */
482 rc = spm_secure_partition_enter(&ec->c_rt_ctx);
483
484 /* Save secure state */
485 cm_el1_sysregs_context_save(SECURE);
486
487 return rc;
488}
489
490/*******************************************************************************
491 * SPMC Helper Functions.
492 ******************************************************************************/
493static int32_t sp_init(void)
494{
495 uint64_t rc;
496 struct secure_partition_desc *sp;
497 struct sp_exec_ctx *ec;
498
499 sp = spmc_get_current_sp_ctx();
500 ec = spmc_get_sp_ec(sp);
501 ec->rt_model = RT_MODEL_INIT;
502 ec->rt_state = RT_STATE_RUNNING;
503
504 INFO("Secure Partition (0x%x) init start.\n", sp->sp_id);
505
506 rc = spmc_sp_synchronous_entry(ec);
507 if (rc != 0) {
508 /* Indicate SP init was not successful. */
509 ERROR("SP (0x%x) failed to initialize (%lu).\n",
510 sp->sp_id, rc);
511 return 0;
512 }
513
514 ec->rt_state = RT_STATE_WAITING;
515 INFO("Secure Partition initialized.\n");
516
517 return 1;
518}
519
520static void initalize_sp_descs(void)
521{
522 struct secure_partition_desc *sp;
523
524 for (unsigned int i = 0U; i < SECURE_PARTITION_COUNT; i++) {
525 sp = &sp_desc[i];
526 sp->sp_id = INV_SP_ID;
527 sp->secondary_ep = 0;
528 }
529}
530
531static void initalize_ns_ep_descs(void)
532{
533 struct ns_endpoint_desc *ns_ep;
534
535 for (unsigned int i = 0U; i < NS_PARTITION_COUNT; i++) {
536 ns_ep = &ns_ep_desc[i];
537 /*
538 * Clashes with the Hypervisor ID but will not be a
539 * problem in practice.
540 */
541 ns_ep->ns_ep_id = 0;
542 ns_ep->ffa_version = 0;
543 }
544}
545
546/*******************************************************************************
Marc Bonnici1c33cc32021-11-29 17:57:03 +0000547 * Initialize SPMC attributes for the SPMD.
548 ******************************************************************************/
549void spmc_populate_attrs(spmc_manifest_attribute_t *spmc_attrs)
550{
551 spmc_attrs->major_version = FFA_VERSION_MAJOR;
552 spmc_attrs->minor_version = FFA_VERSION_MINOR;
553 spmc_attrs->exec_state = MODE_RW_64;
554 spmc_attrs->spmc_id = FFA_SPMC_ID;
555}
556
557/*******************************************************************************
Marc Bonnici8e1a7552021-12-01 17:57:04 +0000558 * Initialize contexts of all Secure Partitions.
559 ******************************************************************************/
560int32_t spmc_setup(void)
561{
562 int32_t ret;
563
564 /* Initialize endpoint descriptors */
565 initalize_sp_descs();
566 initalize_ns_ep_descs();
567
568 /* Perform physical SP setup. */
569
570 /* Disable MMU at EL1 (initialized by BL2) */
571 disable_mmu_icache_el1();
572
573 /* Initialize context of the SP */
574 INFO("Secure Partition context setup start.\n");
575
576 ret = find_and_prepare_sp_context();
577 if (ret != 0) {
578 ERROR("Error in SP finding and context preparation.\n");
579 return ret;
580 }
581
582 /* Register init function for deferred init. */
583 bl31_register_bl32_init(&sp_init);
584
585 INFO("Secure Partition setup done.\n");
586
587 return 0;
588}
589
590/*******************************************************************************
591 * Secure Partition Manager SMC handler.
592 ******************************************************************************/
593uint64_t spmc_smc_handler(uint32_t smc_fid,
594 bool secure_origin,
595 uint64_t x1,
596 uint64_t x2,
597 uint64_t x3,
598 uint64_t x4,
599 void *cookie,
600 void *handle,
601 uint64_t flags)
602{
603 switch (smc_fid) {
604
Marc Bonnici8eb15202021-11-29 17:05:33 +0000605 case FFA_MSG_WAIT:
606 return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
607 cookie, handle, flags);
608
Marc Bonnicib4e99842021-12-10 09:21:56 +0000609 case FFA_ERROR:
610 return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4,
611 cookie, handle, flags);
612
Marc Bonnici8e1a7552021-12-01 17:57:04 +0000613 default:
614 WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
615 break;
616 }
617 return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
618}