xref: /rk3399_ARM-atf/services/std_svc/spmd/spmd_main.c (revision c0267cc9947ac04478f6f0e54dbbfc7f8c02f6a0)
1bdd2596dSAchin Gupta /*
2bdd2596dSAchin Gupta  * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3bdd2596dSAchin Gupta  *
4bdd2596dSAchin Gupta  * SPDX-License-Identifier: BSD-3-Clause
5bdd2596dSAchin Gupta  */
6bdd2596dSAchin Gupta 
7bdd2596dSAchin Gupta #include <assert.h>
8bdd2596dSAchin Gupta #include <errno.h>
9bdd2596dSAchin Gupta #include <string.h>
10bdd2596dSAchin Gupta 
11bdd2596dSAchin Gupta #include <arch_helpers.h>
1252696946SOlivier Deprez #include <arch/aarch64/arch_features.h>
13bdd2596dSAchin Gupta #include <bl31/bl31.h>
14bdd2596dSAchin Gupta #include <common/debug.h>
15bdd2596dSAchin Gupta #include <common/runtime_svc.h>
16bdd2596dSAchin Gupta #include <lib/el3_runtime/context_mgmt.h>
17bdd2596dSAchin Gupta #include <lib/smccc.h>
18bdd2596dSAchin Gupta #include <lib/spinlock.h>
19bdd2596dSAchin Gupta #include <lib/utils.h>
20bdd2596dSAchin Gupta #include <plat/common/common_def.h>
21bdd2596dSAchin Gupta #include <plat/common/platform.h>
22bdd2596dSAchin Gupta #include <platform_def.h>
23662af36dSJ-Alves #include <services/ffa_svc.h>
24bdd2596dSAchin Gupta #include <services/spmd_svc.h>
25bdd2596dSAchin Gupta #include <smccc_helpers.h>
26bdd2596dSAchin Gupta #include "spmd_private.h"
27bdd2596dSAchin Gupta 
28bdd2596dSAchin Gupta /*******************************************************************************
29bdd2596dSAchin Gupta  * SPM Core context information.
30bdd2596dSAchin Gupta  ******************************************************************************/
3152696946SOlivier Deprez static spmd_spm_core_context_t spm_core_context[PLATFORM_CORE_COUNT];
32bdd2596dSAchin Gupta 
33bdd2596dSAchin Gupta /*******************************************************************************
34bdd2596dSAchin Gupta  * SPM Core attribute information read from its manifest.
35bdd2596dSAchin Gupta  ******************************************************************************/
3652696946SOlivier Deprez static spmc_manifest_attribute_t spmc_attrs;
370f14d02fSMax Shvetsov 
380f14d02fSMax Shvetsov /*******************************************************************************
390f14d02fSMax Shvetsov  * SPM Core entry point information. Discovered on the primary core and reused
400f14d02fSMax Shvetsov  * on secondary cores.
410f14d02fSMax Shvetsov  ******************************************************************************/
420f14d02fSMax Shvetsov static entry_point_info_t *spmc_ep_info;
430f14d02fSMax Shvetsov 
440f14d02fSMax Shvetsov /*******************************************************************************
4552696946SOlivier Deprez  * SPM Core context on current CPU get helper.
4652696946SOlivier Deprez  ******************************************************************************/
4752696946SOlivier Deprez spmd_spm_core_context_t *spmd_get_context(void)
4852696946SOlivier Deprez {
4952696946SOlivier Deprez 	unsigned int linear_id = plat_my_core_pos();
5052696946SOlivier Deprez 
5152696946SOlivier Deprez 	return &spm_core_context[linear_id];
5252696946SOlivier Deprez }
5352696946SOlivier Deprez 
5452696946SOlivier Deprez /*******************************************************************************
55*c0267cc9SOlivier Deprez  * SPM Core entry point information get helper.
56*c0267cc9SOlivier Deprez  ******************************************************************************/
57*c0267cc9SOlivier Deprez entry_point_info_t *spmd_spmc_ep_info_get(void)
58*c0267cc9SOlivier Deprez {
59*c0267cc9SOlivier Deprez 	return spmc_ep_info;
60*c0267cc9SOlivier Deprez }
61*c0267cc9SOlivier Deprez 
62*c0267cc9SOlivier Deprez /*******************************************************************************
630f14d02fSMax Shvetsov  * Static function declaration.
640f14d02fSMax Shvetsov  ******************************************************************************/
650f14d02fSMax Shvetsov static int32_t spmd_init(void);
6623d5ba86SOlivier Deprez static int spmd_spmc_init(void *pm_addr);
67662af36dSJ-Alves static uint64_t spmd_ffa_error_return(void *handle,
6852696946SOlivier Deprez 				       int error_code);
6952696946SOlivier Deprez static uint64_t spmd_smc_forward(uint32_t smc_fid,
7052696946SOlivier Deprez 				 bool secure_origin,
7152696946SOlivier Deprez 				 uint64_t x1,
7252696946SOlivier Deprez 				 uint64_t x2,
7352696946SOlivier Deprez 				 uint64_t x3,
7452696946SOlivier Deprez 				 uint64_t x4,
7552696946SOlivier Deprez 				 void *handle);
76bdd2596dSAchin Gupta 
77bdd2596dSAchin Gupta /*******************************************************************************
7852696946SOlivier Deprez  * This function takes an SPMC context pointer and performs a synchronous
7952696946SOlivier Deprez  * SPMC entry.
80bdd2596dSAchin Gupta  ******************************************************************************/
81bdd2596dSAchin Gupta uint64_t spmd_spm_core_sync_entry(spmd_spm_core_context_t *spmc_ctx)
82bdd2596dSAchin Gupta {
83bdd2596dSAchin Gupta 	uint64_t rc;
84bdd2596dSAchin Gupta 
85bdd2596dSAchin Gupta 	assert(spmc_ctx != NULL);
86bdd2596dSAchin Gupta 
87bdd2596dSAchin Gupta 	cm_set_context(&(spmc_ctx->cpu_ctx), SECURE);
88bdd2596dSAchin Gupta 
89bdd2596dSAchin Gupta 	/* Restore the context assigned above */
90bdd2596dSAchin Gupta 	cm_el1_sysregs_context_restore(SECURE);
91033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
9228f39f02SMax Shvetsov 	cm_el2_sysregs_context_restore(SECURE);
93033039f8SMax Shvetsov #endif
94bdd2596dSAchin Gupta 	cm_set_next_eret_context(SECURE);
95bdd2596dSAchin Gupta 
96033039f8SMax Shvetsov 	/* Enter SPMC */
97bdd2596dSAchin Gupta 	rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);
98bdd2596dSAchin Gupta 
99bdd2596dSAchin Gupta 	/* Save secure state */
100bdd2596dSAchin Gupta 	cm_el1_sysregs_context_save(SECURE);
101033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
10228f39f02SMax Shvetsov 	cm_el2_sysregs_context_save(SECURE);
103033039f8SMax Shvetsov #endif
104bdd2596dSAchin Gupta 
105bdd2596dSAchin Gupta 	return rc;
106bdd2596dSAchin Gupta }
107bdd2596dSAchin Gupta 
108bdd2596dSAchin Gupta /*******************************************************************************
10952696946SOlivier Deprez  * This function returns to the place where spmd_spm_core_sync_entry() was
110bdd2596dSAchin Gupta  * called originally.
111bdd2596dSAchin Gupta  ******************************************************************************/
112bdd2596dSAchin Gupta __dead2 void spmd_spm_core_sync_exit(uint64_t rc)
113bdd2596dSAchin Gupta {
11452696946SOlivier Deprez 	spmd_spm_core_context_t *ctx = spmd_get_context();
115bdd2596dSAchin Gupta 
11652696946SOlivier Deprez 	/* Get current CPU context from SPMC context */
117bdd2596dSAchin Gupta 	assert(cm_get_context(SECURE) == &(ctx->cpu_ctx));
118bdd2596dSAchin Gupta 
119bdd2596dSAchin Gupta 	/*
120bdd2596dSAchin Gupta 	 * The SPMD must have initiated the original request through a
121bdd2596dSAchin Gupta 	 * synchronous entry into SPMC. Jump back to the original C runtime
122bdd2596dSAchin Gupta 	 * context with the value of rc in x0;
123bdd2596dSAchin Gupta 	 */
124bdd2596dSAchin Gupta 	spmd_spm_core_exit(ctx->c_rt_ctx, rc);
125bdd2596dSAchin Gupta 
126bdd2596dSAchin Gupta 	panic();
127bdd2596dSAchin Gupta }
128bdd2596dSAchin Gupta 
129bdd2596dSAchin Gupta /*******************************************************************************
13052696946SOlivier Deprez  * Jump to the SPM Core for the first time.
131bdd2596dSAchin Gupta  ******************************************************************************/
132bdd2596dSAchin Gupta static int32_t spmd_init(void)
133bdd2596dSAchin Gupta {
13452696946SOlivier Deprez 	spmd_spm_core_context_t *ctx = spmd_get_context();
13552696946SOlivier Deprez 	uint64_t rc;
136bdd2596dSAchin Gupta 
13752696946SOlivier Deprez 	VERBOSE("SPM Core init start.\n");
138bdd2596dSAchin Gupta 	ctx->state = SPMC_STATE_RESET;
139bdd2596dSAchin Gupta 
140bdd2596dSAchin Gupta 	rc = spmd_spm_core_sync_entry(ctx);
14152696946SOlivier Deprez 	if (rc != 0ULL) {
142bdd2596dSAchin Gupta 		ERROR("SPMC initialisation failed 0x%llx\n", rc);
14352696946SOlivier Deprez 		return 0;
144bdd2596dSAchin Gupta 	}
145bdd2596dSAchin Gupta 
146bdd2596dSAchin Gupta 	ctx->state = SPMC_STATE_IDLE;
14752696946SOlivier Deprez 	VERBOSE("SPM Core init end.\n");
148bdd2596dSAchin Gupta 
149bdd2596dSAchin Gupta 	return 1;
150bdd2596dSAchin Gupta }
151bdd2596dSAchin Gupta 
152bdd2596dSAchin Gupta /*******************************************************************************
15352696946SOlivier Deprez  * Loads SPMC manifest and inits SPMC.
1540f14d02fSMax Shvetsov  ******************************************************************************/
15523d5ba86SOlivier Deprez static int spmd_spmc_init(void *pm_addr)
1560f14d02fSMax Shvetsov {
15752696946SOlivier Deprez 	spmd_spm_core_context_t *spm_ctx = spmd_get_context();
1580f14d02fSMax Shvetsov 	uint32_t ep_attr;
15952696946SOlivier Deprez 	int rc;
1600f14d02fSMax Shvetsov 
16152696946SOlivier Deprez 	/* Load the SPM Core manifest */
16223d5ba86SOlivier Deprez 	rc = plat_spm_core_manifest_load(&spmc_attrs, pm_addr);
1630f14d02fSMax Shvetsov 	if (rc != 0) {
16452696946SOlivier Deprez 		WARN("No or invalid SPM Core manifest image provided by BL2\n");
16552696946SOlivier Deprez 		return rc;
1660f14d02fSMax Shvetsov 	}
1670f14d02fSMax Shvetsov 
1680f14d02fSMax Shvetsov 	/*
16952696946SOlivier Deprez 	 * Ensure that the SPM Core version is compatible with the SPM
17052696946SOlivier Deprez 	 * Dispatcher version.
1710f14d02fSMax Shvetsov 	 */
172662af36dSJ-Alves 	if ((spmc_attrs.major_version != FFA_VERSION_MAJOR) ||
173662af36dSJ-Alves 	    (spmc_attrs.minor_version > FFA_VERSION_MINOR)) {
174662af36dSJ-Alves 		WARN("Unsupported FFA version (%u.%u)\n",
1750f14d02fSMax Shvetsov 		     spmc_attrs.major_version, spmc_attrs.minor_version);
17652696946SOlivier Deprez 		return -EINVAL;
1770f14d02fSMax Shvetsov 	}
1780f14d02fSMax Shvetsov 
179662af36dSJ-Alves 	VERBOSE("FFA version (%u.%u)\n", spmc_attrs.major_version,
1800f14d02fSMax Shvetsov 	     spmc_attrs.minor_version);
1810f14d02fSMax Shvetsov 
18252696946SOlivier Deprez 	VERBOSE("SPM Core run time EL%x.\n",
183033039f8SMax Shvetsov 	     SPMD_SPM_AT_SEL2 ? MODE_EL2 : MODE_EL1);
1840f14d02fSMax Shvetsov 
185ac03ac5eSMax Shvetsov 	/* Validate the SPMC ID, Ensure high bit is set */
18652696946SOlivier Deprez 	if (((spmc_attrs.spmc_id >> SPMC_SECURE_ID_SHIFT) &
18752696946SOlivier Deprez 			SPMC_SECURE_ID_MASK) == 0U) {
18852696946SOlivier Deprez 		WARN("Invalid ID (0x%x) for SPMC.\n", spmc_attrs.spmc_id);
18952696946SOlivier Deprez 		return -EINVAL;
190ac03ac5eSMax Shvetsov 	}
191ac03ac5eSMax Shvetsov 
19252696946SOlivier Deprez 	/* Validate the SPM Core execution state */
1930f14d02fSMax Shvetsov 	if ((spmc_attrs.exec_state != MODE_RW_64) &&
1940f14d02fSMax Shvetsov 	    (spmc_attrs.exec_state != MODE_RW_32)) {
19523d5ba86SOlivier Deprez 		WARN("Unsupported %s%x.\n", "SPM Core execution state 0x",
1960f14d02fSMax Shvetsov 		     spmc_attrs.exec_state);
19752696946SOlivier Deprez 		return -EINVAL;
1980f14d02fSMax Shvetsov 	}
1990f14d02fSMax Shvetsov 
20023d5ba86SOlivier Deprez 	VERBOSE("%s%x.\n", "SPM Core execution state 0x",
20123d5ba86SOlivier Deprez 		spmc_attrs.exec_state);
2020f14d02fSMax Shvetsov 
203033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
204033039f8SMax Shvetsov 	/* Ensure manifest has not requested AArch32 state in S-EL2 */
205033039f8SMax Shvetsov 	if (spmc_attrs.exec_state == MODE_RW_32) {
206033039f8SMax Shvetsov 		WARN("AArch32 state at S-EL2 is not supported.\n");
20752696946SOlivier Deprez 		return -EINVAL;
2080f14d02fSMax Shvetsov 	}
2090f14d02fSMax Shvetsov 
2100f14d02fSMax Shvetsov 	/*
2110f14d02fSMax Shvetsov 	 * Check if S-EL2 is supported on this system if S-EL2
2120f14d02fSMax Shvetsov 	 * is required for SPM
2130f14d02fSMax Shvetsov 	 */
21452696946SOlivier Deprez 	if (!is_armv8_4_sel2_present()) {
21552696946SOlivier Deprez 		WARN("SPM Core run time S-EL2 is not supported.\n");
21652696946SOlivier Deprez 		return -EINVAL;
2170f14d02fSMax Shvetsov 	}
218033039f8SMax Shvetsov #endif /* SPMD_SPM_AT_SEL2 */
2190f14d02fSMax Shvetsov 
2200f14d02fSMax Shvetsov 	/* Initialise an entrypoint to set up the CPU context */
2210f14d02fSMax Shvetsov 	ep_attr = SECURE | EP_ST_ENABLE;
22252696946SOlivier Deprez 	if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0ULL) {
2230f14d02fSMax Shvetsov 		ep_attr |= EP_EE_BIG;
2240f14d02fSMax Shvetsov 	}
2250f14d02fSMax Shvetsov 
2260f14d02fSMax Shvetsov 	SET_PARAM_HEAD(spmc_ep_info, PARAM_EP, VERSION_1, ep_attr);
2270f14d02fSMax Shvetsov 	assert(spmc_ep_info->pc == BL32_BASE);
2280f14d02fSMax Shvetsov 
2290f14d02fSMax Shvetsov 	/*
23052696946SOlivier Deprez 	 * Populate SPSR for SPM Core based upon validated parameters from the
23152696946SOlivier Deprez 	 * manifest.
2320f14d02fSMax Shvetsov 	 */
2330f14d02fSMax Shvetsov 	if (spmc_attrs.exec_state == MODE_RW_32) {
2340f14d02fSMax Shvetsov 		spmc_ep_info->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
2350f14d02fSMax Shvetsov 						 SPSR_E_LITTLE,
2360f14d02fSMax Shvetsov 						 DAIF_FIQ_BIT |
2370f14d02fSMax Shvetsov 						 DAIF_IRQ_BIT |
2380f14d02fSMax Shvetsov 						 DAIF_ABT_BIT);
2390f14d02fSMax Shvetsov 	} else {
240033039f8SMax Shvetsov 
241033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
242033039f8SMax Shvetsov 		static const uint32_t runtime_el = MODE_EL2;
243033039f8SMax Shvetsov #else
244033039f8SMax Shvetsov 		static const uint32_t runtime_el = MODE_EL1;
245033039f8SMax Shvetsov #endif
246033039f8SMax Shvetsov 		spmc_ep_info->spsr = SPSR_64(runtime_el,
2470f14d02fSMax Shvetsov 					     MODE_SP_ELX,
2480f14d02fSMax Shvetsov 					     DISABLE_ALL_EXCEPTIONS);
2490f14d02fSMax Shvetsov 	}
2500f14d02fSMax Shvetsov 
25152696946SOlivier Deprez 	/* Initialise SPM Core context with this entry point information */
2520f14d02fSMax Shvetsov 	cm_setup_context(&spm_ctx->cpu_ctx, spmc_ep_info);
2530f14d02fSMax Shvetsov 
2540f14d02fSMax Shvetsov 	/* Reuse PSCI affinity states to mark this SPMC context as off */
2550f14d02fSMax Shvetsov 	spm_ctx->state = AFF_STATE_OFF;
2560f14d02fSMax Shvetsov 
25752696946SOlivier Deprez 	INFO("SPM Core setup done.\n");
2580f14d02fSMax Shvetsov 
2590f14d02fSMax Shvetsov 	/* Register init function for deferred init. */
2600f14d02fSMax Shvetsov 	bl31_register_bl32_init(&spmd_init);
2610f14d02fSMax Shvetsov 
2620f14d02fSMax Shvetsov 	return 0;
2630f14d02fSMax Shvetsov }
2640f14d02fSMax Shvetsov 
2650f14d02fSMax Shvetsov /*******************************************************************************
26652696946SOlivier Deprez  * Initialize context of SPM Core.
267bdd2596dSAchin Gupta  ******************************************************************************/
2680f14d02fSMax Shvetsov int spmd_setup(void)
269bdd2596dSAchin Gupta {
27023d5ba86SOlivier Deprez 	void *spmc_manifest;
271bdd2596dSAchin Gupta 	int rc;
272bdd2596dSAchin Gupta 
273bdd2596dSAchin Gupta 	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
27452696946SOlivier Deprez 	if (spmc_ep_info == NULL) {
27552696946SOlivier Deprez 		WARN("No SPM Core image provided by BL2 boot loader.\n");
27652696946SOlivier Deprez 		return -EINVAL;
277bdd2596dSAchin Gupta 	}
278bdd2596dSAchin Gupta 
279bdd2596dSAchin Gupta 	/* Under no circumstances will this parameter be 0 */
28052696946SOlivier Deprez 	assert(spmc_ep_info->pc != 0ULL);
281bdd2596dSAchin Gupta 
282bdd2596dSAchin Gupta 	/*
283bdd2596dSAchin Gupta 	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
28452696946SOlivier Deprez 	 * be used as a manifest for the SPM Core at the next lower EL/mode.
285bdd2596dSAchin Gupta 	 */
28623d5ba86SOlivier Deprez 	spmc_manifest = (void *)spmc_ep_info->args.arg0;
28723d5ba86SOlivier Deprez 	if (spmc_manifest == NULL) {
28823d5ba86SOlivier Deprez 		ERROR("Invalid or absent SPM Core manifest.\n");
28923d5ba86SOlivier Deprez 		return -EINVAL;
290bdd2596dSAchin Gupta 	}
291bdd2596dSAchin Gupta 
2920f14d02fSMax Shvetsov 	/* Load manifest, init SPMC */
29323d5ba86SOlivier Deprez 	rc = spmd_spmc_init(spmc_manifest);
2940f14d02fSMax Shvetsov 	if (rc != 0) {
29552696946SOlivier Deprez 		WARN("Booting device without SPM initialization.\n");
296bdd2596dSAchin Gupta 	}
297bdd2596dSAchin Gupta 
2980f14d02fSMax Shvetsov 	return rc;
2990f14d02fSMax Shvetsov }
3000f14d02fSMax Shvetsov 
3010f14d02fSMax Shvetsov /*******************************************************************************
3020f14d02fSMax Shvetsov  * Forward SMC to the other security state
3030f14d02fSMax Shvetsov  ******************************************************************************/
30452696946SOlivier Deprez static uint64_t spmd_smc_forward(uint32_t smc_fid,
30552696946SOlivier Deprez 				 bool secure_origin,
30652696946SOlivier Deprez 				 uint64_t x1,
30752696946SOlivier Deprez 				 uint64_t x2,
30852696946SOlivier Deprez 				 uint64_t x3,
30952696946SOlivier Deprez 				 uint64_t x4,
31052696946SOlivier Deprez 				 void *handle)
3110f14d02fSMax Shvetsov {
31293ff138bSOlivier Deprez 	uint32_t secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
31393ff138bSOlivier Deprez 	uint32_t secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
31493ff138bSOlivier Deprez 
3150f14d02fSMax Shvetsov 	/* Save incoming security state */
31693ff138bSOlivier Deprez 	cm_el1_sysregs_context_save(secure_state_in);
317033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
31893ff138bSOlivier Deprez 	cm_el2_sysregs_context_save(secure_state_in);
319033039f8SMax Shvetsov #endif
3200f14d02fSMax Shvetsov 
3210f14d02fSMax Shvetsov 	/* Restore outgoing security state */
32293ff138bSOlivier Deprez 	cm_el1_sysregs_context_restore(secure_state_out);
323033039f8SMax Shvetsov #if SPMD_SPM_AT_SEL2
32493ff138bSOlivier Deprez 	cm_el2_sysregs_context_restore(secure_state_out);
325033039f8SMax Shvetsov #endif
32693ff138bSOlivier Deprez 	cm_set_next_eret_context(secure_state_out);
3270f14d02fSMax Shvetsov 
32893ff138bSOlivier Deprez 	SMC_RET8(cm_get_context(secure_state_out), smc_fid, x1, x2, x3, x4,
3290f14d02fSMax Shvetsov 			SMC_GET_GP(handle, CTX_GPREG_X5),
3300f14d02fSMax Shvetsov 			SMC_GET_GP(handle, CTX_GPREG_X6),
3310f14d02fSMax Shvetsov 			SMC_GET_GP(handle, CTX_GPREG_X7));
3320f14d02fSMax Shvetsov }
3330f14d02fSMax Shvetsov 
3340f14d02fSMax Shvetsov /*******************************************************************************
335662af36dSJ-Alves  * Return FFA_ERROR with specified error code
3360f14d02fSMax Shvetsov  ******************************************************************************/
337662af36dSJ-Alves static uint64_t spmd_ffa_error_return(void *handle, int error_code)
3380f14d02fSMax Shvetsov {
339662af36dSJ-Alves 	SMC_RET8(handle, FFA_ERROR,
340662af36dSJ-Alves 		 FFA_TARGET_INFO_MBZ, error_code,
341662af36dSJ-Alves 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
342662af36dSJ-Alves 		 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
343bdd2596dSAchin Gupta }
344bdd2596dSAchin Gupta 
345bdd2596dSAchin Gupta /*******************************************************************************
346662af36dSJ-Alves  * This function handles all SMCs in the range reserved for FFA. Each call is
347bdd2596dSAchin Gupta  * either forwarded to the other security state or handled by the SPM dispatcher
348bdd2596dSAchin Gupta  ******************************************************************************/
34952696946SOlivier Deprez uint64_t spmd_smc_handler(uint32_t smc_fid,
35052696946SOlivier Deprez 			  uint64_t x1,
35152696946SOlivier Deprez 			  uint64_t x2,
35252696946SOlivier Deprez 			  uint64_t x3,
35352696946SOlivier Deprez 			  uint64_t x4,
35452696946SOlivier Deprez 			  void *cookie,
35552696946SOlivier Deprez 			  void *handle,
356bdd2596dSAchin Gupta 			  uint64_t flags)
357bdd2596dSAchin Gupta {
35852696946SOlivier Deprez 	spmd_spm_core_context_t *ctx = spmd_get_context();
35993ff138bSOlivier Deprez 	bool secure_origin;
36093ff138bSOlivier Deprez 	int32_t ret;
3614388f28fSJ-Alves 	uint32_t input_version;
362bdd2596dSAchin Gupta 
363bdd2596dSAchin Gupta 	/* Determine which security state this SMC originated from */
36493ff138bSOlivier Deprez 	secure_origin = is_caller_secure(flags);
365bdd2596dSAchin Gupta 
36652696946SOlivier Deprez 	INFO("SPM: 0x%x 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
367bdd2596dSAchin Gupta 	     smc_fid, x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5),
368bdd2596dSAchin Gupta 	     SMC_GET_GP(handle, CTX_GPREG_X6),
369bdd2596dSAchin Gupta 	     SMC_GET_GP(handle, CTX_GPREG_X7));
370bdd2596dSAchin Gupta 
371bdd2596dSAchin Gupta 	switch (smc_fid) {
372662af36dSJ-Alves 	case FFA_ERROR:
373bdd2596dSAchin Gupta 		/*
374bdd2596dSAchin Gupta 		 * Check if this is the first invocation of this interface on
37552696946SOlivier Deprez 		 * this CPU. If so, then indicate that the SPM Core initialised
376bdd2596dSAchin Gupta 		 * unsuccessfully.
377bdd2596dSAchin Gupta 		 */
37893ff138bSOlivier Deprez 		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
379bdd2596dSAchin Gupta 			spmd_spm_core_sync_exit(x2);
3800f14d02fSMax Shvetsov 		}
381bdd2596dSAchin Gupta 
38293ff138bSOlivier Deprez 		return spmd_smc_forward(smc_fid, secure_origin,
3830f14d02fSMax Shvetsov 					x1, x2, x3, x4, handle);
384bdd2596dSAchin Gupta 		break; /* not reached */
385bdd2596dSAchin Gupta 
386662af36dSJ-Alves 	case FFA_VERSION:
3874388f28fSJ-Alves 		input_version = (uint32_t)(0xFFFFFFFF & x1);
388bdd2596dSAchin Gupta 		/*
3894388f28fSJ-Alves 		 * If caller is secure and SPMC was initialized,
3904388f28fSJ-Alves 		 * return FFA_VERSION of SPMD.
3914388f28fSJ-Alves 		 * If caller is non secure and SPMC was initialized,
3924388f28fSJ-Alves 		 * return SPMC's version.
3934388f28fSJ-Alves 		 * Sanity check to "input_version".
394bdd2596dSAchin Gupta 		 */
3954388f28fSJ-Alves 		if ((input_version & FFA_VERSION_BIT31_MASK) ||
3964388f28fSJ-Alves 			(ctx->state == SPMC_STATE_RESET)) {
3974388f28fSJ-Alves 			ret = FFA_ERROR_NOT_SUPPORTED;
3984388f28fSJ-Alves 		} else if (!secure_origin) {
3994388f28fSJ-Alves 			ret = MAKE_FFA_VERSION(spmc_attrs.major_version, spmc_attrs.minor_version);
4004388f28fSJ-Alves 		} else {
4014388f28fSJ-Alves 			ret = MAKE_FFA_VERSION(FFA_VERSION_MAJOR, FFA_VERSION_MINOR);
4024388f28fSJ-Alves 		}
4034388f28fSJ-Alves 
4044388f28fSJ-Alves 		SMC_RET8(handle, ret, FFA_TARGET_INFO_MBZ, FFA_TARGET_INFO_MBZ,
405662af36dSJ-Alves 			 FFA_PARAM_MBZ, FFA_PARAM_MBZ, FFA_PARAM_MBZ,
406662af36dSJ-Alves 			 FFA_PARAM_MBZ, FFA_PARAM_MBZ);
407bdd2596dSAchin Gupta 		break; /* not reached */
408bdd2596dSAchin Gupta 
409662af36dSJ-Alves 	case FFA_FEATURES:
410bdd2596dSAchin Gupta 		/*
411bdd2596dSAchin Gupta 		 * This is an optional interface. Do the minimal checks and
41252696946SOlivier Deprez 		 * forward to SPM Core which will handle it if implemented.
413bdd2596dSAchin Gupta 		 */
414bdd2596dSAchin Gupta 
415bdd2596dSAchin Gupta 		/*
416662af36dSJ-Alves 		 * Check if x1 holds a valid FFA fid. This is an
417bdd2596dSAchin Gupta 		 * optimization.
418bdd2596dSAchin Gupta 		 */
419662af36dSJ-Alves 		if (!is_ffa_fid(x1)) {
420662af36dSJ-Alves 			return spmd_ffa_error_return(handle,
421662af36dSJ-Alves 						      FFA_ERROR_NOT_SUPPORTED);
4220f14d02fSMax Shvetsov 		}
423bdd2596dSAchin Gupta 
42452696946SOlivier Deprez 		/* Forward SMC from Normal world to the SPM Core */
42593ff138bSOlivier Deprez 		if (!secure_origin) {
42693ff138bSOlivier Deprez 			return spmd_smc_forward(smc_fid, secure_origin,
4270f14d02fSMax Shvetsov 						x1, x2, x3, x4, handle);
42852696946SOlivier Deprez 		}
42952696946SOlivier Deprez 
430bdd2596dSAchin Gupta 		/*
431bdd2596dSAchin Gupta 		 * Return success if call was from secure world i.e. all
432662af36dSJ-Alves 		 * FFA functions are supported. This is essentially a
433bdd2596dSAchin Gupta 		 * nop.
434bdd2596dSAchin Gupta 		 */
435662af36dSJ-Alves 		SMC_RET8(handle, FFA_SUCCESS_SMC32, x1, x2, x3, x4,
436bdd2596dSAchin Gupta 			 SMC_GET_GP(handle, CTX_GPREG_X5),
437bdd2596dSAchin Gupta 			 SMC_GET_GP(handle, CTX_GPREG_X6),
438bdd2596dSAchin Gupta 			 SMC_GET_GP(handle, CTX_GPREG_X7));
4390f14d02fSMax Shvetsov 
440bdd2596dSAchin Gupta 		break; /* not reached */
441bdd2596dSAchin Gupta 
442662af36dSJ-Alves 	case FFA_ID_GET:
443ac03ac5eSMax Shvetsov 		/*
444662af36dSJ-Alves 		 * Returns the ID of the calling FFA component.
445ac03ac5eSMax Shvetsov 		 */
446ac03ac5eSMax Shvetsov 		if (!secure_origin) {
447662af36dSJ-Alves 			SMC_RET8(handle, FFA_SUCCESS_SMC32,
448662af36dSJ-Alves 				 FFA_TARGET_INFO_MBZ, FFA_NS_ENDPOINT_ID,
449662af36dSJ-Alves 				 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
450662af36dSJ-Alves 				 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
451662af36dSJ-Alves 				 FFA_PARAM_MBZ);
45252696946SOlivier Deprez 		}
45352696946SOlivier Deprez 
454662af36dSJ-Alves 		SMC_RET8(handle, FFA_SUCCESS_SMC32,
455662af36dSJ-Alves 			 FFA_TARGET_INFO_MBZ, spmc_attrs.spmc_id,
456662af36dSJ-Alves 			 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
457662af36dSJ-Alves 			 FFA_PARAM_MBZ, FFA_PARAM_MBZ,
458662af36dSJ-Alves 			 FFA_PARAM_MBZ);
459ac03ac5eSMax Shvetsov 
460ac03ac5eSMax Shvetsov 		break; /* not reached */
461ac03ac5eSMax Shvetsov 
462662af36dSJ-Alves 	case FFA_RX_RELEASE:
463662af36dSJ-Alves 	case FFA_RXTX_MAP_SMC32:
464662af36dSJ-Alves 	case FFA_RXTX_MAP_SMC64:
465662af36dSJ-Alves 	case FFA_RXTX_UNMAP:
466662af36dSJ-Alves 	case FFA_MSG_RUN:
467bdd2596dSAchin Gupta 		/* This interface must be invoked only by the Normal world */
46893ff138bSOlivier Deprez 		if (secure_origin) {
469662af36dSJ-Alves 			return spmd_ffa_error_return(handle,
470662af36dSJ-Alves 						      FFA_ERROR_NOT_SUPPORTED);
471bdd2596dSAchin Gupta 		}
472bdd2596dSAchin Gupta 
473bdd2596dSAchin Gupta 		/* Fall through to forward the call to the other world */
474bdd2596dSAchin Gupta 
475662af36dSJ-Alves 	case FFA_PARTITION_INFO_GET:
476662af36dSJ-Alves 	case FFA_MSG_SEND:
477662af36dSJ-Alves 	case FFA_MSG_SEND_DIRECT_REQ_SMC32:
478662af36dSJ-Alves 	case FFA_MSG_SEND_DIRECT_REQ_SMC64:
479662af36dSJ-Alves 	case FFA_MSG_SEND_DIRECT_RESP_SMC32:
480662af36dSJ-Alves 	case FFA_MSG_SEND_DIRECT_RESP_SMC64:
481662af36dSJ-Alves 	case FFA_MEM_DONATE_SMC32:
482662af36dSJ-Alves 	case FFA_MEM_DONATE_SMC64:
483662af36dSJ-Alves 	case FFA_MEM_LEND_SMC32:
484662af36dSJ-Alves 	case FFA_MEM_LEND_SMC64:
485662af36dSJ-Alves 	case FFA_MEM_SHARE_SMC32:
486662af36dSJ-Alves 	case FFA_MEM_SHARE_SMC64:
487662af36dSJ-Alves 	case FFA_MEM_RETRIEVE_REQ_SMC32:
488662af36dSJ-Alves 	case FFA_MEM_RETRIEVE_REQ_SMC64:
489662af36dSJ-Alves 	case FFA_MEM_RETRIEVE_RESP:
490662af36dSJ-Alves 	case FFA_MEM_RELINQUISH:
491662af36dSJ-Alves 	case FFA_MEM_RECLAIM:
492662af36dSJ-Alves 	case FFA_SUCCESS_SMC32:
493662af36dSJ-Alves 	case FFA_SUCCESS_SMC64:
494bdd2596dSAchin Gupta 		/*
495bdd2596dSAchin Gupta 		 * TODO: Assume that no requests originate from EL3 at the
496bdd2596dSAchin Gupta 		 * moment. This will change if a SP service is required in
497bdd2596dSAchin Gupta 		 * response to secure interrupts targeted to EL3. Until then
498bdd2596dSAchin Gupta 		 * simply forward the call to the Normal world.
499bdd2596dSAchin Gupta 		 */
500bdd2596dSAchin Gupta 
50193ff138bSOlivier Deprez 		return spmd_smc_forward(smc_fid, secure_origin,
5020f14d02fSMax Shvetsov 					x1, x2, x3, x4, handle);
503bdd2596dSAchin Gupta 		break; /* not reached */
504bdd2596dSAchin Gupta 
505662af36dSJ-Alves 	case FFA_MSG_WAIT:
506bdd2596dSAchin Gupta 		/*
507bdd2596dSAchin Gupta 		 * Check if this is the first invocation of this interface on
508bdd2596dSAchin Gupta 		 * this CPU from the Secure world. If so, then indicate that the
50952696946SOlivier Deprez 		 * SPM Core initialised successfully.
510bdd2596dSAchin Gupta 		 */
51193ff138bSOlivier Deprez 		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
512bdd2596dSAchin Gupta 			spmd_spm_core_sync_exit(0);
513bdd2596dSAchin Gupta 		}
514bdd2596dSAchin Gupta 
5150f14d02fSMax Shvetsov 		/* Fall through to forward the call to the other world */
516bdd2596dSAchin Gupta 
517662af36dSJ-Alves 	case FFA_MSG_YIELD:
518bdd2596dSAchin Gupta 		/* This interface must be invoked only by the Secure world */
51993ff138bSOlivier Deprez 		if (!secure_origin) {
520662af36dSJ-Alves 			return spmd_ffa_error_return(handle,
521662af36dSJ-Alves 						      FFA_ERROR_NOT_SUPPORTED);
522bdd2596dSAchin Gupta 		}
523bdd2596dSAchin Gupta 
52493ff138bSOlivier Deprez 		return spmd_smc_forward(smc_fid, secure_origin,
5250f14d02fSMax Shvetsov 					x1, x2, x3, x4, handle);
526bdd2596dSAchin Gupta 		break; /* not reached */
527bdd2596dSAchin Gupta 
528bdd2596dSAchin Gupta 	default:
529bdd2596dSAchin Gupta 		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
530662af36dSJ-Alves 		return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
531bdd2596dSAchin Gupta 	}
532bdd2596dSAchin Gupta }
533