spmd_main.c 18 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
/*******************************************************************************
 * Static function declaration.
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
65
static int32_t spmd_init(void);
66
static int spmd_spmc_init(void *pm_addr);
J-Alves's avatar
J-Alves committed
67
static uint64_t spmd_ffa_error_return(void *handle,
Olivier Deprez's avatar
Olivier Deprez committed
68
69
70
71
72
73
74
75
				       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);
76
77

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
78
79
 * This function takes an SPMC context pointer and performs a synchronous
 * SPMC entry.
80
81
82
83
84
85
86
87
88
89
90
 ******************************************************************************/
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);
91
#if SPMD_SPM_AT_SEL2
92
	cm_el2_sysregs_context_restore(SECURE);
93
#endif
94
95
	cm_set_next_eret_context(SECURE);

96
	/* Enter SPMC */
97
98
99
100
	rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);

	/* Save secure state */
	cm_el1_sysregs_context_save(SECURE);
101
#if SPMD_SPM_AT_SEL2
102
	cm_el2_sysregs_context_save(SECURE);
103
#endif
104
105
106
107
108

	return rc;
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
109
 * This function returns to the place where spmd_spm_core_sync_entry() was
110
111
112
113
 * called originally.
 ******************************************************************************/
__dead2 void spmd_spm_core_sync_exit(uint64_t rc)
{
Olivier Deprez's avatar
Olivier Deprez committed
114
	spmd_spm_core_context_t *ctx = spmd_get_context();
115

Olivier Deprez's avatar
Olivier Deprez committed
116
	/* Get current CPU context from SPMC context */
117
118
119
120
121
122
123
124
125
126
127
128
129
	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
130
 * Jump to the SPM Core for the first time.
131
132
133
 ******************************************************************************/
static int32_t spmd_init(void)
{
Olivier Deprez's avatar
Olivier Deprez committed
134
135
	spmd_spm_core_context_t *ctx = spmd_get_context();
	uint64_t rc;
136
137
	unsigned int linear_id = plat_my_core_pos();
	unsigned int core_id;
138

Olivier Deprez's avatar
Olivier Deprez committed
139
	VERBOSE("SPM Core init start.\n");
140
141
142
	ctx->state = SPMC_STATE_ON_PENDING;

	/* Set the SPMC context state on other CPUs to OFF */
143
	for (core_id = 0U; core_id < PLATFORM_CORE_COUNT; core_id++) {
144
145
146
147
		if (core_id != linear_id) {
			spm_core_context[core_id].state = SPMC_STATE_OFF;
		}
	}
148
149

	rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez's avatar
Olivier Deprez committed
150
	if (rc != 0ULL) {
151
		ERROR("SPMC initialisation failed 0x%llx\n", rc);
Olivier Deprez's avatar
Olivier Deprez committed
152
		return 0;
153
154
	}

155
156
	ctx->state = SPMC_STATE_ON;

Olivier Deprez's avatar
Olivier Deprez committed
157
	VERBOSE("SPM Core init end.\n");
158
159
160
161
162

	return 1;
}

/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
163
 * Loads SPMC manifest and inits SPMC.
164
 ******************************************************************************/
165
static int spmd_spmc_init(void *pm_addr)
166
{
Olivier Deprez's avatar
Olivier Deprez committed
167
	spmd_spm_core_context_t *spm_ctx = spmd_get_context();
168
	uint32_t ep_attr;
Olivier Deprez's avatar
Olivier Deprez committed
169
	int rc;
170

Olivier Deprez's avatar
Olivier Deprez committed
171
	/* Load the SPM Core manifest */
172
	rc = plat_spm_core_manifest_load(&spmc_attrs, pm_addr);
173
	if (rc != 0) {
Olivier Deprez's avatar
Olivier Deprez committed
174
175
		WARN("No or invalid SPM Core manifest image provided by BL2\n");
		return rc;
176
177
178
	}

	/*
Olivier Deprez's avatar
Olivier Deprez committed
179
180
	 * Ensure that the SPM Core version is compatible with the SPM
	 * Dispatcher version.
181
	 */
J-Alves's avatar
J-Alves committed
182
183
184
	if ((spmc_attrs.major_version != FFA_VERSION_MAJOR) ||
	    (spmc_attrs.minor_version > FFA_VERSION_MINOR)) {
		WARN("Unsupported FFA version (%u.%u)\n",
185
		     spmc_attrs.major_version, spmc_attrs.minor_version);
Olivier Deprez's avatar
Olivier Deprez committed
186
		return -EINVAL;
187
188
	}

J-Alves's avatar
J-Alves committed
189
	VERBOSE("FFA version (%u.%u)\n", spmc_attrs.major_version,
190
191
	     spmc_attrs.minor_version);

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

195
	/* Validate the SPMC ID, Ensure high bit is set */
Olivier Deprez's avatar
Olivier Deprez committed
196
197
198
199
	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;
200
201
	}

Olivier Deprez's avatar
Olivier Deprez committed
202
	/* Validate the SPM Core execution state */
203
204
	if ((spmc_attrs.exec_state != MODE_RW_64) &&
	    (spmc_attrs.exec_state != MODE_RW_32)) {
205
		WARN("Unsupported %s%x.\n", "SPM Core execution state 0x",
206
		     spmc_attrs.exec_state);
Olivier Deprez's avatar
Olivier Deprez committed
207
		return -EINVAL;
208
209
	}

210
211
	VERBOSE("%s%x.\n", "SPM Core execution state 0x",
		spmc_attrs.exec_state);
212

213
214
215
216
#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
217
		return -EINVAL;
218
219
220
221
222
223
	}

	/*
	 * Check if S-EL2 is supported on this system if S-EL2
	 * is required for SPM
	 */
Olivier Deprez's avatar
Olivier Deprez committed
224
225
226
	if (!is_armv8_4_sel2_present()) {
		WARN("SPM Core run time S-EL2 is not supported.\n");
		return -EINVAL;
227
	}
228
#endif /* SPMD_SPM_AT_SEL2 */
229
230
231

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

236
237
238
239
	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
240
241
	 * Populate SPSR for SPM Core based upon validated parameters from the
	 * manifest.
242
243
244
245
246
247
248
249
	 */
	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 {
250
251
252
253
254
255
256

#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,
257
258
259
260
					     MODE_SP_ELX,
					     DISABLE_ALL_EXCEPTIONS);
	}

Olivier Deprez's avatar
Olivier Deprez committed
261
	/* Initialise SPM Core context with this entry point information */
262
263
264
265
	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;
266

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

269
270
271
	/* Register power management hooks with PSCI */
	psci_register_spd_pm_hook(&spmd_pm);

Olivier Deprez's avatar
Olivier Deprez committed
272
	/* Register init function for deferred init. */
273
274
275
	bl31_register_bl32_init(&spmd_init);

	return 0;
276
}
277

278
/*******************************************************************************
Olivier Deprez's avatar
Olivier Deprez committed
279
 * Initialize context of SPM Core.
280
281
282
 ******************************************************************************/
int spmd_setup(void)
{
283
	void *spmc_manifest;
284
	int rc;
285

286
	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
Olivier Deprez's avatar
Olivier Deprez committed
287
288
289
	if (spmc_ep_info == NULL) {
		WARN("No SPM Core image provided by BL2 boot loader.\n");
		return -EINVAL;
290
291
292
	}

	/* Under no circumstances will this parameter be 0 */
Olivier Deprez's avatar
Olivier Deprez committed
293
	assert(spmc_ep_info->pc != 0ULL);
294
295
296

	/*
	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
Olivier Deprez's avatar
Olivier Deprez committed
297
	 * be used as a manifest for the SPM Core at the next lower EL/mode.
298
	 */
299
300
301
302
	spmc_manifest = (void *)spmc_ep_info->args.arg0;
	if (spmc_manifest == NULL) {
		ERROR("Invalid or absent SPM Core manifest.\n");
		return -EINVAL;
303
304
305
	}

	/* Load manifest, init SPMC */
306
	rc = spmd_spmc_init(spmc_manifest);
307
	if (rc != 0) {
Olivier Deprez's avatar
Olivier Deprez committed
308
		WARN("Booting device without SPM initialization.\n");
309
310
	}

311
	return rc;
312
313
314
315
316
}

/*******************************************************************************
 * Forward SMC to the other security state
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
317
318
319
320
321
322
323
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)
324
{
325
326
	unsigned int secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
	unsigned int secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
327

328
	/* Save incoming security state */
329
	cm_el1_sysregs_context_save(secure_state_in);
330
#if SPMD_SPM_AT_SEL2
331
	cm_el2_sysregs_context_save(secure_state_in);
332
#endif
333
334

	/* Restore outgoing security state */
335
	cm_el1_sysregs_context_restore(secure_state_out);
336
#if SPMD_SPM_AT_SEL2
337
	cm_el2_sysregs_context_restore(secure_state_out);
338
#endif
339
	cm_set_next_eret_context(secure_state_out);
340

341
	SMC_RET8(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
342
343
344
345
346
347
			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
348
 * Return FFA_ERROR with specified error code
349
 ******************************************************************************/
J-Alves's avatar
J-Alves committed
350
static uint64_t spmd_ffa_error_return(void *handle, int error_code)
351
{
J-Alves's avatar
J-Alves committed
352
353
354
355
	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);
356
357
}

358
359
360
361
362
363
364
365
366
367
368
/*******************************************************************************
 * 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)));
}

369
370
371
372
373
374
375
376
377
/******************************************************************************
 * 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));
}

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
/******************************************************************************
 * spmd_handle_spmc_message
 *****************************************************************************/
static int32_t spmd_handle_spmc_message(uint64_t msg, uint64_t parm1,
					uint64_t parm2, uint64_t parm3,
					uint64_t parm4)
{
	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;
}

398
/*******************************************************************************
J-Alves's avatar
J-Alves committed
399
 * This function handles all SMCs in the range reserved for FFA. Each call is
400
401
 * either forwarded to the other security state or handled by the SPM dispatcher
 ******************************************************************************/
Olivier Deprez's avatar
Olivier Deprez committed
402
403
404
405
406
407
408
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,
409
410
			  uint64_t flags)
{
Olivier Deprez's avatar
Olivier Deprez committed
411
	spmd_spm_core_context_t *ctx = spmd_get_context();
412
413
	bool secure_origin;
	int32_t ret;
J-Alves's avatar
J-Alves committed
414
	uint32_t input_version;
415
416

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

Olivier Deprez's avatar
Olivier Deprez committed
419
	INFO("SPM: 0x%x 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
420
421
422
423
424
	     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
425
	case FFA_ERROR:
426
427
		/*
		 * Check if this is the first invocation of this interface on
Olivier Deprez's avatar
Olivier Deprez committed
428
		 * this CPU. If so, then indicate that the SPM Core initialised
429
430
		 * unsuccessfully.
		 */
431
		if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
432
			spmd_spm_core_sync_exit(x2);
433
		}
434

435
		return spmd_smc_forward(smc_fid, secure_origin,
436
					x1, x2, x3, x4, handle);
437
438
		break; /* not reached */

J-Alves's avatar
J-Alves committed
439
	case FFA_VERSION:
J-Alves's avatar
J-Alves committed
440
		input_version = (uint32_t)(0xFFFFFFFF & x1);
441
		/*
J-Alves's avatar
J-Alves committed
442
443
444
445
446
		 * 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".
447
		 */
J-Alves's avatar
J-Alves committed
448
449
450
451
452
453
454
455
456
457
		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
458
459
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
			 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
460
461
		break; /* not reached */

J-Alves's avatar
J-Alves committed
462
	case FFA_FEATURES:
463
464
		/*
		 * This is an optional interface. Do the minimal checks and
Olivier Deprez's avatar
Olivier Deprez committed
465
		 * forward to SPM Core which will handle it if implemented.
466
467
468
		 */

		/*
J-Alves's avatar
J-Alves committed
469
		 * Check if x1 holds a valid FFA fid. This is an
470
471
		 * optimization.
		 */
J-Alves's avatar
J-Alves committed
472
473
474
		if (!is_ffa_fid(x1)) {
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
475
		}
476

Olivier Deprez's avatar
Olivier Deprez committed
477
		/* Forward SMC from Normal world to the SPM Core */
478
479
		if (!secure_origin) {
			return spmd_smc_forward(smc_fid, secure_origin,
480
						x1, x2, x3, x4, handle);
481
		}
482

Olivier Deprez's avatar
Olivier Deprez committed
483
484
		/*
		 * Return success if call was from secure world i.e. all
J-Alves's avatar
J-Alves committed
485
		 * FFA functions are supported. This is essentially a
Olivier Deprez's avatar
Olivier Deprez committed
486
487
		 * nop.
		 */
J-Alves's avatar
J-Alves committed
488
		SMC_RET8(handle, FFA_SUCCESS_SMC32, x1, x2, x3, x4,
Olivier Deprez's avatar
Olivier Deprez committed
489
490
491
492
			 SMC_GET_GP(handle, CTX_GPREG_X5),
			 SMC_GET_GP(handle, CTX_GPREG_X6),
			 SMC_GET_GP(handle, CTX_GPREG_X7));

493
494
		break; /* not reached */

J-Alves's avatar
J-Alves committed
495
	case FFA_ID_GET:
496
		/*
J-Alves's avatar
J-Alves committed
497
		 * Returns the ID of the calling FFA component.
Olivier Deprez's avatar
Olivier Deprez committed
498
		 */
499
		if (!secure_origin) {
J-Alves's avatar
J-Alves committed
500
501
502
503
504
			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);
505
506
		}

J-Alves's avatar
J-Alves committed
507
508
509
510
511
		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
512

513
514
		break; /* not reached */

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
	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
544
545
546
547
548
	case FFA_RX_RELEASE:
	case FFA_RXTX_MAP_SMC32:
	case FFA_RXTX_MAP_SMC64:
	case FFA_RXTX_UNMAP:
	case FFA_MSG_RUN:
549
		/* This interface must be invoked only by the Normal world */
550
		if (secure_origin) {
J-Alves's avatar
J-Alves committed
551
552
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
553
554
555
556
		}

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

J-Alves's avatar
J-Alves committed
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
	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:
574
575
576
577
578
579
580
		/*
		 * 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.
		 */

581
		return spmd_smc_forward(smc_fid, secure_origin,
582
					x1, x2, x3, x4, handle);
583
584
		break; /* not reached */

J-Alves's avatar
J-Alves committed
585
	case FFA_MSG_WAIT:
586
587
588
		/*
		 * 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
589
		 * SPM Core initialised successfully.
590
		 */
591
		if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) {
592
593
594
			spmd_spm_core_sync_exit(0);
		}

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

J-Alves's avatar
J-Alves committed
597
	case FFA_MSG_YIELD:
598
		/* This interface must be invoked only by the Secure world */
599
		if (!secure_origin) {
J-Alves's avatar
J-Alves committed
600
601
			return spmd_ffa_error_return(handle,
						      FFA_ERROR_NOT_SUPPORTED);
602
603
		}

604
		return spmd_smc_forward(smc_fid, secure_origin,
605
					x1, x2, x3, x4, handle);
606
607
608
609
		break; /* not reached */

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