spmd_main.c 18.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
/*
 * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>
#include <errno.h>
#include <string.h>

#include <arch_helpers.h>
Olivier Deprez's avatar
Olivier Deprez committed
12
#include <arch/aarch64/arch_features.h>
13
14
15
16
17
18
19
20
21
22
#include <bl31/bl31.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/smccc.h>
#include <lib/spinlock.h>
#include <lib/utils.h>
#include <plat/common/common_def.h>
#include <plat/common/platform.h>
#include <platform_def.h>
J-Alves's avatar
J-Alves committed
23
#include <services/ffa_svc.h>
24
25
26
27
28
29
30
#include <services/spmd_svc.h>
#include <smccc_helpers.h>
#include "spmd_private.h"

/*******************************************************************************
 * SPM Core context information.
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
31
static spmd_spm_core_context_t spm_core_context[PLATFORM_CORE_COUNT];
32
33
34
35

/*******************************************************************************
 * SPM Core attribute information read from its manifest.
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
36
static spmc_manifest_attribute_t spmc_attrs;
37
38
39
40
41
42
43

/*******************************************************************************
 * SPM Core entry point information. Discovered on the primary core and reused
 * on secondary cores.
 ******************************************************************************/
static entry_point_info_t *spmc_ep_info;

Olivier Deprez's avatar
Olivier Deprez committed
44
45
46
47
48
49
50
51
52
53
/*******************************************************************************
 * SPM Core context on current CPU get helper.
 ******************************************************************************/
spmd_spm_core_context_t *spmd_get_context(void)
{
	unsigned int linear_id = plat_my_core_pos();

	return &spm_core_context[linear_id];
}

54
55
56
57
58
59
60
61
/*******************************************************************************
 * SPM Core entry point information get helper.
 ******************************************************************************/
entry_point_info_t *spmd_spmc_ep_info_get(void)
{
	return spmc_ep_info;
}

62
63
64
65
66
67
68
69
/*******************************************************************************
 * SPM Core ID getter.
 ******************************************************************************/
uint16_t spmd_spmc_id_get(void)
{
	return spmc_attrs.spmc_id;
}

70
71
72
/*******************************************************************************
 * Static function declaration.
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
73
static int32_t spmd_init(void);
74
static int spmd_spmc_init(void *pm_addr);
J-Alves's avatar
J-Alves committed
75
static uint64_t spmd_ffa_error_return(void *handle,
Olivier Deprez's avatar
Olivier Deprez committed
76
77
78
79
80
81
82
83
				       int error_code);
static uint64_t spmd_smc_forward(uint32_t smc_fid,
				 bool secure_origin,
				 uint64_t x1,
				 uint64_t x2,
				 uint64_t x3,
				 uint64_t x4,
				 void *handle);
84
85

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
86
87
 * This function takes an SPMC context pointer and performs a synchronous
 * SPMC entry.
88
89
90
91
92
93
94
95
96
97
98
 ******************************************************************************/
uint64_t spmd_spm_core_sync_entry(spmd_spm_core_context_t *spmc_ctx)
{
	uint64_t rc;

	assert(spmc_ctx != NULL);

	cm_set_context(&(spmc_ctx->cpu_ctx), SECURE);

	/* Restore the context assigned above */
	cm_el1_sysregs_context_restore(SECURE);
99
#if SPMD_SPM_AT_SEL2
100
	cm_el2_sysregs_context_restore(SECURE);
101
#endif
102
103
	cm_set_next_eret_context(SECURE);

104
	/* Enter SPMC */
105
106
107
108
	rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);

	/* Save secure state */
	cm_el1_sysregs_context_save(SECURE);
109
#if SPMD_SPM_AT_SEL2
110
	cm_el2_sysregs_context_save(SECURE);
111
#endif
112
113
114
115
116

	return rc;
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
117
 * This function returns to the place where spmd_spm_core_sync_entry() was
118
119
120
121
 * called originally.
 ******************************************************************************/
__dead2 void spmd_spm_core_sync_exit(uint64_t rc)
{
Olivier Deprez's avatar
Olivier Deprez committed
122
	spmd_spm_core_context_t *ctx = spmd_get_context();
123

Olivier Deprez's avatar
Olivier Deprez committed
124
	/* Get current CPU context from SPMC context */
125
126
127
128
129
130
131
132
133
134
135
136
137
	assert(cm_get_context(SECURE) == &(ctx->cpu_ctx));

	/*
	 * The SPMD must have initiated the original request through a
	 * synchronous entry into SPMC. Jump back to the original C runtime
	 * context with the value of rc in x0;
	 */
	spmd_spm_core_exit(ctx->c_rt_ctx, rc);

	panic();
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
138
 * Jump to the SPM Core for the first time.
139
140
141
 ******************************************************************************/
static int32_t spmd_init(void)
{
Olivier Deprez's avatar
Olivier Deprez committed
142
143
	spmd_spm_core_context_t *ctx = spmd_get_context();
	uint64_t rc;
144
145
	unsigned int linear_id = plat_my_core_pos();
	unsigned int core_id;
146

Olivier Deprez's avatar
Olivier Deprez committed
147
	VERBOSE("SPM Core init start.\n");
148
149
150
	ctx->state = SPMC_STATE_ON_PENDING;

	/* Set the SPMC context state on other CPUs to OFF */
151
	for (core_id = 0U; core_id < PLATFORM_CORE_COUNT; core_id++) {
152
153
154
155
		if (core_id != linear_id) {
			spm_core_context[core_id].state = SPMC_STATE_OFF;
		}
	}
156
157

	rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez's avatar
Olivier Deprez committed
158
	if (rc != 0ULL) {
159
		ERROR("SPMC initialisation failed 0x%llx\n", rc);
Olivier Deprez's avatar
Olivier Deprez committed
160
		return 0;
161
162
	}

163
164
	ctx->state = SPMC_STATE_ON;

Olivier Deprez's avatar
Olivier Deprez committed
165
	VERBOSE("SPM Core init end.\n");
166
167
168
169
170

	return 1;
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
171
 * Loads SPMC manifest and inits SPMC.
172
 ******************************************************************************/
173
static int spmd_spmc_init(void *pm_addr)
174
{
Olivier Deprez's avatar
Olivier Deprez committed
175
	spmd_spm_core_context_t *spm_ctx = spmd_get_context();
176
	uint32_t ep_attr;
Olivier Deprez's avatar
Olivier Deprez committed
177
	int rc;
178

Olivier Deprez's avatar
Olivier Deprez committed
179
	/* Load the SPM Core manifest */
180
	rc = plat_spm_core_manifest_load(&spmc_attrs, pm_addr);
181
	if (rc != 0) {
Olivier Deprez's avatar
Olivier Deprez committed
182
183
		WARN("No or invalid SPM Core manifest image provided by BL2\n");
		return rc;
184
185
186
	}

	/*
Olivier Deprez's avatar
Olivier Deprez committed
187
188
	 * Ensure that the SPM Core version is compatible with the SPM
	 * Dispatcher version.
189
	 */
J-Alves's avatar
J-Alves committed
190
191
192
	if ((spmc_attrs.major_version != FFA_VERSION_MAJOR) ||
	    (spmc_attrs.minor_version > FFA_VERSION_MINOR)) {
		WARN("Unsupported FFA version (%u.%u)\n",
193
		     spmc_attrs.major_version, spmc_attrs.minor_version);
Olivier Deprez's avatar
Olivier Deprez committed
194
		return -EINVAL;
195
196
	}

J-Alves's avatar
J-Alves committed
197
	VERBOSE("FFA version (%u.%u)\n", spmc_attrs.major_version,
198
199
	     spmc_attrs.minor_version);

Olivier Deprez's avatar
Olivier Deprez committed
200
	VERBOSE("SPM Core run time EL%x.\n",
201
	     SPMD_SPM_AT_SEL2 ? MODE_EL2 : MODE_EL1);
202

203
	/* Validate the SPMC ID, Ensure high bit is set */
Olivier Deprez's avatar
Olivier Deprez committed
204
205
206
207
	if (((spmc_attrs.spmc_id >> SPMC_SECURE_ID_SHIFT) &
			SPMC_SECURE_ID_MASK) == 0U) {
		WARN("Invalid ID (0x%x) for SPMC.\n", spmc_attrs.spmc_id);
		return -EINVAL;
208
209
	}

Olivier Deprez's avatar
Olivier Deprez committed
210
	/* Validate the SPM Core execution state */
211
212
	if ((spmc_attrs.exec_state != MODE_RW_64) &&
	    (spmc_attrs.exec_state != MODE_RW_32)) {
213
		WARN("Unsupported %s%x.\n", "SPM Core execution state 0x",
214
		     spmc_attrs.exec_state);
Olivier Deprez's avatar
Olivier Deprez committed
215
		return -EINVAL;
216
217
	}

218
219
	VERBOSE("%s%x.\n", "SPM Core execution state 0x",
		spmc_attrs.exec_state);
220

221
222
223
224
#if SPMD_SPM_AT_SEL2
	/* Ensure manifest has not requested AArch32 state in S-EL2 */
	if (spmc_attrs.exec_state == MODE_RW_32) {
		WARN("AArch32 state at S-EL2 is not supported.\n");
Olivier Deprez's avatar
Olivier Deprez committed
225
		return -EINVAL;
226
227
228
229
230
231
	}

	/*
	 * Check if S-EL2 is supported on this system if S-EL2
	 * is required for SPM
	 */
Olivier Deprez's avatar
Olivier Deprez committed
232
233
234
	if (!is_armv8_4_sel2_present()) {
		WARN("SPM Core run time S-EL2 is not supported.\n");
		return -EINVAL;
235
	}
236
#endif /* SPMD_SPM_AT_SEL2 */
237
238
239

	/* Initialise an entrypoint to set up the CPU context */
	ep_attr = SECURE | EP_ST_ENABLE;
Olivier Deprez's avatar
Olivier Deprez committed
240
	if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0ULL) {
241
		ep_attr |= EP_EE_BIG;
242
243
	}

244
245
246
247
	SET_PARAM_HEAD(spmc_ep_info, PARAM_EP, VERSION_1, ep_attr);
	assert(spmc_ep_info->pc == BL32_BASE);

	/*
Olivier Deprez's avatar
Olivier Deprez committed
248
249
	 * Populate SPSR for SPM Core based upon validated parameters from the
	 * manifest.
250
251
252
253
254
255
256
257
	 */
	if (spmc_attrs.exec_state == MODE_RW_32) {
		spmc_ep_info->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
						 SPSR_E_LITTLE,
						 DAIF_FIQ_BIT |
						 DAIF_IRQ_BIT |
						 DAIF_ABT_BIT);
	} else {
258
259
260
261
262
263
264

#if SPMD_SPM_AT_SEL2
		static const uint32_t runtime_el = MODE_EL2;
#else
		static const uint32_t runtime_el = MODE_EL1;
#endif
		spmc_ep_info->spsr = SPSR_64(runtime_el,
265
266
267
268
					     MODE_SP_ELX,
					     DISABLE_ALL_EXCEPTIONS);
	}

Olivier Deprez's avatar
Olivier Deprez committed
269
	/* Initialise SPM Core context with this entry point information */
270
271
272
273
	cm_setup_context(&spm_ctx->cpu_ctx, spmc_ep_info);

	/* Reuse PSCI affinity states to mark this SPMC context as off */
	spm_ctx->state = AFF_STATE_OFF;
274

Olivier Deprez's avatar
Olivier Deprez committed
275
	INFO("SPM Core setup done.\n");
276

277
278
279
	/* Register power management hooks with PSCI */
	psci_register_spd_pm_hook(&spmd_pm);

Olivier Deprez's avatar
Olivier Deprez committed
280
	/* Register init function for deferred init. */
281
282
283
	bl31_register_bl32_init(&spmd_init);

	return 0;
284
}
285

286
/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
287
 * Initialize context of SPM Core.
288
289
290
 ******************************************************************************/
int spmd_setup(void)
{
291
	void *spmc_manifest;
292
	int rc;
293

294
	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
Olivier Deprez's avatar
Olivier Deprez committed
295
296
297
	if (spmc_ep_info == NULL) {
		WARN("No SPM Core image provided by BL2 boot loader.\n");
		return -EINVAL;
298
299
300
	}

	/* Under no circumstances will this parameter be 0 */
Olivier Deprez's avatar
Olivier Deprez committed
301
	assert(spmc_ep_info->pc != 0ULL);
302
303
304

	/*
	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
Olivier Deprez's avatar
Olivier Deprez committed
305
	 * be used as a manifest for the SPM Core at the next lower EL/mode.
306
	 */
307
308
309
310
	spmc_manifest = (void *)spmc_ep_info->args.arg0;
	if (spmc_manifest == NULL) {
		ERROR("Invalid or absent SPM Core manifest.\n");
		return -EINVAL;
311
312
313
	}

	/* Load manifest, init SPMC */
314
	rc = spmd_spmc_init(spmc_manifest);
315
	if (rc != 0) {
Olivier Deprez's avatar
Olivier Deprez committed
316
		WARN("Booting device without SPM initialization.\n");
317
318
	}

319
	return rc;
320
321
322
323
324
}

/*******************************************************************************
 * Forward SMC to the other security state
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
325
326
327
328
329
330
331
static uint64_t spmd_smc_forward(uint32_t smc_fid,
				 bool secure_origin,
				 uint64_t x1,
				 uint64_t x2,
				 uint64_t x3,
				 uint64_t x4,
				 void *handle)
332
{
333
334
	unsigned int secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
	unsigned int secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
335

336
	/* Save incoming security state */
337
	cm_el1_sysregs_context_save(secure_state_in);
338
#if SPMD_SPM_AT_SEL2
339
	cm_el2_sysregs_context_save(secure_state_in);
340
#endif
341
342

	/* Restore outgoing security state */
343
	cm_el1_sysregs_context_restore(secure_state_out);
344
#if SPMD_SPM_AT_SEL2
345
	cm_el2_sysregs_context_restore(secure_state_out);
346
#endif
347
	cm_set_next_eret_context(secure_state_out);
348

349
	SMC_RET8(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
350
351
352
353
354
355
			SMC_GET_GP(handle, CTX_GPREG_X5),
			SMC_GET_GP(handle, CTX_GPREG_X6),
			SMC_GET_GP(handle, CTX_GPREG_X7));
}

/*******************************************************************************
J-Alves's avatar
J-Alves committed
356
 * Return FFA_ERROR with specified error code
357
 ******************************************************************************/
J-Alves's avatar
J-Alves committed
358
static uint64_t spmd_ffa_error_return(void *handle, int error_code)
359
{
J-Alves's avatar
J-Alves committed
360
361
362
363
	SMC_RET8(handle, FFA_ERROR,
		 FFA_TARGET_INFO_MBZ, error_code,
		 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
		 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
364
365
}

366
367
368
369
370
371
372
373
374
375
376
/*******************************************************************************
 * spmd_check_address_in_binary_image
 ******************************************************************************/
bool spmd_check_address_in_binary_image(uint64_t address)
{
	assert(!check_uptr_overflow(spmc_attrs.load_address, spmc_attrs.binary_size));

	return ((address >= spmc_attrs.load_address) &&
		(address < (spmc_attrs.load_address + spmc_attrs.binary_size)));
}

377
378
379
380
381
382
383
384
385
/******************************************************************************
 * spmd_is_spmc_message
 *****************************************************************************/
static bool spmd_is_spmc_message(unsigned int ep)
{
	return ((ffa_endpoint_destination(ep) == SPMD_DIRECT_MSG_ENDPOINT_ID)
		&& (ffa_endpoint_source(ep) == spmc_attrs.spmc_id));
}

386
387
388
/******************************************************************************
 * spmd_handle_spmc_message
 *****************************************************************************/
389
390
391
static int spmd_handle_spmc_message(unsigned long long msg,
		unsigned long long parm1, unsigned long long parm2,
		unsigned long long parm3, unsigned long long parm4)
392
393
394
395
396
397
398
399
400
401
402
403
404
405
{
	VERBOSE("%s %llx %llx %llx %llx %llx\n", __func__,
		msg, parm1, parm2, parm3, parm4);

	switch (msg) {
	case SPMD_DIRECT_MSG_SET_ENTRY_POINT:
		return spmd_pm_secondary_core_set_ep(parm1, parm2, parm3);
	default:
		break;
	}

	return -EINVAL;
}

406
/*******************************************************************************
J-Alves's avatar
J-Alves committed
407
 * This function handles all SMCs in the range reserved for FFA. Each call is
408
409
 * either forwarded to the other security state or handled by the SPM dispatcher
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
410
411
412
413
414
415
416
uint64_t spmd_smc_handler(uint32_t smc_fid,
			  uint64_t x1,
			  uint64_t x2,
			  uint64_t x3,
			  uint64_t x4,
			  void *cookie,
			  void *handle,
417
418
			  uint64_t flags)
{
Olivier Deprez's avatar
Olivier Deprez committed
419
	spmd_spm_core_context_t *ctx = spmd_get_context();
420
421
	bool secure_origin;
	int32_t ret;
J-Alves's avatar
J-Alves committed
422
	uint32_t input_version;
423
424

	/* Determine which security state this SMC originated from */
425
	secure_origin = is_caller_secure(flags);
426

Olivier Deprez's avatar
Olivier Deprez committed
427
	INFO("SPM: 0x%x 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
428
429
430
431
432
	     smc_fid, x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5),
	     SMC_GET_GP(handle, CTX_GPREG_X6),
	     SMC_GET_GP(handle, CTX_GPREG_X7));

	switch (smc_fid) {
J-Alves's avatar
J-Alves committed
433
	case FFA_ERROR:
434
435
		/*
		 * Check if this is the first invocation of this interface on
Olivier Deprez's avatar
Olivier Deprez committed
436
		 * this CPU. If so, then indicate that the SPM Core initialised
437
438
		 * unsuccessfully.
		 */
439
		if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
440
			spmd_spm_core_sync_exit(x2);
441
		}
442

443
		return spmd_smc_forward(smc_fid, secure_origin,
444
					x1, x2, x3, x4, handle);
445
446
		break; /* not reached */

J-Alves's avatar
J-Alves committed
447
	case FFA_VERSION:
J-Alves's avatar
J-Alves committed
448
		input_version = (uint32_t)(0xFFFFFFFF & x1);
449
		/*
J-Alves's avatar
J-Alves committed
450
451
452
453
454
		 * If caller is secure and SPMC was initialized,
		 * return FFA_VERSION of SPMD.
		 * If caller is non secure and SPMC was initialized,
		 * return SPMC's version.
		 * Sanity check to "input_version".
455
		 */
J-Alves's avatar
J-Alves committed
456
457
458
459
460
461
462
463
464
465
		if ((input_version & FFA_VERSION_BIT31_MASK) ||
			(ctx->state == SPMC_STATE_RESET)) {
			ret = FFA_ERROR_NOT_SUPPORTED;
		} else if (!secure_origin) {
			ret = MAKE_FFA_VERSION(spmc_attrs.major_version, spmc_attrs.minor_version);
		} else {
			ret = MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR);
		}

		SMC_RET8(handle, ret, FFA_TARGET_INFO_MBZ, FFA_TARGET_INFO_MBZ,
J-Alves's avatar
J-Alves committed
466
467
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
468
469
		break; /* not reached */

J-Alves's avatar
J-Alves committed
470
	case FFA_FEATURES:
471
472
		/*
		 * This is an optional interface. Do the minimal checks and
Olivier Deprez's avatar
Olivier Deprez committed
473
		 * forward to SPM Core which will handle it if implemented.
474
475
476
		 */

		/*
J-Alves's avatar
J-Alves committed
477
		 * Check if x1 holds a valid FFA fid. This is an
478
479
		 * optimization.
		 */
J-Alves's avatar
J-Alves committed
480
481
482
		if (!is_ffa_fid(x1)) {
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
483
		}
484

Olivier Deprez's avatar
Olivier Deprez committed
485
		/* Forward SMC from Normal world to the SPM Core */
486
487
		if (!secure_origin) {
			return spmd_smc_forward(smc_fid, secure_origin,
488
						x1, x2, x3, x4, handle);
489
		}
490

Olivier Deprez's avatar
Olivier Deprez committed
491
492
		/*
		 * Return success if call was from secure world i.e. all
J-Alves's avatar
J-Alves committed
493
		 * FFA functions are supported. This is essentially a
Olivier Deprez's avatar
Olivier Deprez committed
494
495
		 * nop.
		 */
J-Alves's avatar
J-Alves committed
496
		SMC_RET8(handle, FFA_SUCCESS_SMC32, x1, x2, x3, x4,
Olivier Deprez's avatar
Olivier Deprez committed
497
498
499
500
			 SMC_GET_GP(handle, CTX_GPREG_X5),
			 SMC_GET_GP(handle, CTX_GPREG_X6),
			 SMC_GET_GP(handle, CTX_GPREG_X7));

501
502
		break; /* not reached */

J-Alves's avatar
J-Alves committed
503
	case FFA_ID_GET:
504
		/*
J-Alves's avatar
J-Alves committed
505
		 * Returns the ID of the calling FFA component.
Olivier Deprez's avatar
Olivier Deprez committed
506
		 */
507
		if (!secure_origin) {
J-Alves's avatar
J-Alves committed
508
509
510
511
512
			SMC_RET8(handle, FFA_SUCCESS_SMC32,
				 FFA_TARGET_INFO_MBZ, FFA_NS_ENDPOINT_ID,
				 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
				 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
				 FFA_PARAM_MBZ);
513
514
		}

J-Alves's avatar
J-Alves committed
515
516
517
518
519
		SMC_RET8(handle, FFA_SUCCESS_SMC32,
			 FFA_TARGET_INFO_MBZ, spmc_attrs.spmc_id,
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
			 FFA_PARAM_MBZ);
Olivier Deprez's avatar
Olivier Deprez committed
520

521
522
		break; /* not reached */

523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
		if (secure_origin && spmd_is_spmc_message(x1)) {
			ret = spmd_handle_spmc_message(x3, x4,
				SMC_GET_GP(handle, CTX_GPREG_X5),
				SMC_GET_GP(handle, CTX_GPREG_X6),
				SMC_GET_GP(handle, CTX_GPREG_X7));

			SMC_RET8(handle, FFA_SUCCESS_SMC32,
				FFA_TARGET_INFO_MBZ, ret,
				FFA_PARAM_MBZ, FFA_PARAM_MBZ,
				FFA_PARAM_MBZ, FFA_PARAM_MBZ,
				FFA_PARAM_MBZ);
		} else {
			/* Forward direct message to the other world */
			return spmd_smc_forward(smc_fid, secure_origin,
				x1, x2, x3, x4, handle);
		}
		break; /* Not reached */

	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
		if (secure_origin && spmd_is_spmc_message(x1)) {
			spmd_spm_core_sync_exit(0);
		} else {
			/* Forward direct message to the other world */
			return spmd_smc_forward(smc_fid, secure_origin,
				x1, x2, x3, x4, handle);
		}
		break; /* Not reached */

J-Alves's avatar
J-Alves committed
552
553
554
555
556
	case FFA_RX_RELEASE:
	case FFA_RXTX_MAP_SMC32:
	case FFA_RXTX_MAP_SMC64:
	case FFA_RXTX_UNMAP:
	case FFA_MSG_RUN:
557
		/* This interface must be invoked only by the Normal world */
558
		if (secure_origin) {
J-Alves's avatar
J-Alves committed
559
560
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
561
562
563
564
		}

		/* Fall through to forward the call to the other world */

J-Alves's avatar
J-Alves committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
	case FFA_PARTITION_INFO_GET:
	case FFA_MSG_SEND:
	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
	case FFA_MEM_DONATE_SMC32:
	case FFA_MEM_DONATE_SMC64:
	case FFA_MEM_LEND_SMC32:
	case FFA_MEM_LEND_SMC64:
	case FFA_MEM_SHARE_SMC32:
	case FFA_MEM_SHARE_SMC64:
	case FFA_MEM_RETRIEVE_REQ_SMC32:
	case FFA_MEM_RETRIEVE_REQ_SMC64:
	case FFA_MEM_RETRIEVE_RESP:
	case FFA_MEM_RELINQUISH:
	case FFA_MEM_RECLAIM:
	case FFA_SUCCESS_SMC32:
	case FFA_SUCCESS_SMC64:
582
583
584
585
586
587
588
		/*
		 * TODO: Assume that no requests originate from EL3 at the
		 * moment. This will change if a SP service is required in
		 * response to secure interrupts targeted to EL3. Until then
		 * simply forward the call to the Normal world.
		 */

589
		return spmd_smc_forward(smc_fid, secure_origin,
590
					x1, x2, x3, x4, handle);
591
592
		break; /* not reached */

J-Alves's avatar
J-Alves committed
593
	case FFA_MSG_WAIT:
594
595
596
		/*
		 * Check if this is the first invocation of this interface on
		 * this CPU from the Secure world. If so, then indicate that the
Olivier Deprez's avatar
Olivier Deprez committed
597
		 * SPM Core initialised successfully.
598
		 */
599
		if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
600
601
602
			spmd_spm_core_sync_exit(0);
		}

603
		/* Fall through to forward the call to the other world */
604

J-Alves's avatar
J-Alves committed
605
	case FFA_MSG_YIELD:
606
		/* This interface must be invoked only by the Secure world */
607
		if (!secure_origin) {
J-Alves's avatar
J-Alves committed
608
609
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
610
611
		}

612
		return spmd_smc_forward(smc_fid, secure_origin,
613
					x1, x2, x3, x4, handle);
614
615
616
617
		break; /* not reached */

	default:
		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
J-Alves's avatar
J-Alves committed
618
		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
619
620
	}
}