Merge changes from topic "spmd-sel2" into integration

* changes:
  SPMD: add command line parameter to run SPM at S-EL2 or S-EL1
  SPMD: smc handler qualify secure origin using booleans
  SPMD: SPMC init, SMC handler cosmetic changes
  SPMD: [tegra] rename el1_sys_regs structure to sys_regs
  SPMD: Adds partially supported EL2 registers.
  SPMD: save/restore EL2 system registers.
diff --git a/Makefile b/Makefile
index 03f9fc6..f3cb9be 100644
--- a/Makefile
+++ b/Makefile
@@ -412,40 +412,48 @@
 ################################################################################
 
 ifneq (${SPD},none)
-ifeq (${ARCH},aarch32)
+    ifeq (${ARCH},aarch32)
         $(error "Error: SPD is incompatible with AArch32.")
-endif
-ifdef EL3_PAYLOAD_BASE
+    endif
+
+    ifdef EL3_PAYLOAD_BASE
         $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.")
         $(warning "The SPD and its BL32 companion will be present but ignored.")
-endif
-	ifeq (${SPD},spmd)
-		# SPMD is located in std_svc directory
-		SPD_DIR := std_svc
-	else
-		# All other SPDs in spd directory
-		SPD_DIR := spd
-	endif
-
-	# We expect to locate an spd.mk under the specified SPD directory
-	SPD_MAKE	:=	$(wildcard services/${SPD_DIR}/${SPD}/${SPD}.mk)
+    endif
 
+    ifeq (${SPD},spmd)
+        $(warning "SPMD is an experimental feature")
+        # SPMD is located in std_svc directory
+        SPD_DIR := std_svc
 
-        ifeq (${SPD_MAKE},)
-                $(error Error: No services/${SPD_DIR}/${SPD}/${SPD}.mk located)
+        ifeq ($(SPMD_SPM_AT_SEL2),1)
+            ifeq ($(CTX_INCLUDE_EL2_REGS),0)
+                $(error SPMD with SPM at S-EL2 requires CTX_INCLUDE_EL2_REGS option)
+            endif
         endif
-        $(info Including ${SPD_MAKE})
-        include ${SPD_MAKE}
+    else
+        # All other SPDs in spd directory
+        SPD_DIR := spd
+    endif
 
-        # If there's BL32 companion for the chosen SPD, we expect that the SPD's
-        # Makefile would set NEED_BL32 to "yes". In this case, the build system
-        # supports two mutually exclusive options:
-        # * BL32 is built from source: then BL32_SOURCES must contain the list
-        #   of source files to build BL32
-        # * BL32 is a prebuilt binary: then BL32 must point to the image file
-        #   that will be included in the FIP
-        # If both BL32_SOURCES and BL32 are defined, the binary takes precedence
-        # over the sources.
+    # We expect to locate an spd.mk under the specified SPD directory
+    SPD_MAKE	:=	$(wildcard services/${SPD_DIR}/${SPD}/${SPD}.mk)
+
+    ifeq (${SPD_MAKE},)
+        $(error Error: No services/${SPD_DIR}/${SPD}/${SPD}.mk located)
+    endif
+    $(info Including ${SPD_MAKE})
+    include ${SPD_MAKE}
+
+    # If there's BL32 companion for the chosen SPD, we expect that the SPD's
+    # Makefile would set NEED_BL32 to "yes". In this case, the build system
+    # supports two mutually exclusive options:
+    # * BL32 is built from source: then BL32_SOURCES must contain the list
+    #   of source files to build BL32
+    # * BL32 is a prebuilt binary: then BL32 must point to the image file
+    #   that will be included in the FIP
+    # If both BL32_SOURCES and BL32 are defined, the binary takes precedence
+    # over the sources.
 endif
 
 ################################################################################
@@ -761,6 +769,7 @@
 $(eval $(call assert_boolean,CTX_INCLUDE_FPREGS))
 $(eval $(call assert_boolean,CTX_INCLUDE_PAUTH_REGS))
 $(eval $(call assert_boolean,CTX_INCLUDE_MTE_REGS))
+$(eval $(call assert_boolean,CTX_INCLUDE_EL2_REGS))
 $(eval $(call assert_boolean,DEBUG))
 $(eval $(call assert_boolean,DYN_DISABLE_AUTH))
 $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING))
@@ -793,6 +802,7 @@
 $(eval $(call assert_boolean,SEPARATE_NOBITS_REGION))
 $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT))
 $(eval $(call assert_boolean,SPM_MM))
+$(eval $(call assert_boolean,SPMD_SPM_AT_SEL2))
 $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT))
 $(eval $(call assert_boolean,USE_COHERENT_MEM))
 $(eval $(call assert_boolean,USE_DEBUGFS))
@@ -832,6 +842,7 @@
 $(eval $(call add_define,CTX_INCLUDE_PAUTH_REGS))
 $(eval $(call add_define,EL3_EXCEPTION_HANDLING))
 $(eval $(call add_define,CTX_INCLUDE_MTE_REGS))
+$(eval $(call add_define,CTX_INCLUDE_EL2_REGS))
 $(eval $(call add_define,ENABLE_AMU))
 $(eval $(call add_define,ENABLE_ASSERTIONS))
 $(eval $(call add_define,ENABLE_BTI))
@@ -863,6 +874,7 @@
 $(eval $(call add_define,SPD_${SPD}))
 $(eval $(call add_define,SPIN_ON_BL1_EXIT))
 $(eval $(call add_define,SPM_MM))
+$(eval $(call add_define,SPMD_SPM_AT_SEL2))
 $(eval $(call add_define,TRUSTED_BOARD_BOOT))
 $(eval $(call add_define,USE_COHERENT_MEM))
 $(eval $(call add_define,USE_DEBUGFS))
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 1faddbe..b0c2650 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -97,6 +97,32 @@
 #define ICC_SGI0R_EL1		S3_0_c12_c11_7
 
 /*******************************************************************************
+ * Definitions for EL2 system registers for save/restore routine
+ ******************************************************************************/
+
+#define CNTPOFF_EL2		S3_4_C14_C0_6
+#define HAFGRTR_EL2		S3_4_C3_C1_6
+#define HDFGRTR_EL2		S3_4_C3_C1_4
+#define HDFGWTR_EL2		S3_4_C3_C1_5
+#define HFGITR_EL2		S3_4_C1_C1_6
+#define HFGRTR_EL2		S3_4_C1_C1_4
+#define HFGWTR_EL2		S3_4_C1_C1_5
+#define ICH_HCR_EL2		S3_4_C12_C11_0
+#define ICH_VMCR_EL2		S3_4_C12_C11_7
+#define MPAMVPM0_EL2		S3_4_C10_C5_0
+#define MPAMVPM1_EL2		S3_4_C10_C5_1
+#define MPAMVPM2_EL2		S3_4_C10_C5_2
+#define MPAMVPM3_EL2		S3_4_C10_C5_3
+#define MPAMVPM4_EL2		S3_4_C10_C5_4
+#define MPAMVPM5_EL2		S3_4_C10_C5_5
+#define MPAMVPM6_EL2		S3_4_C10_C5_6
+#define MPAMVPM7_EL2		S3_4_C10_C5_7
+#define MPAMVPMV_EL2		S3_4_C10_C4_1
+#define TRFCR_EL2		S3_4_C1_C2_1
+#define PMSCR_EL2		S3_4_C9_C9_0
+#define TFSR_EL2		S3_4_C5_C6_0
+
+/*******************************************************************************
  * Generic timer memory mapped registers & offsets
  ******************************************************************************/
 #define CNTCR_OFF			U(0x000)
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 4158c02..e061950 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -68,7 +68,7 @@
  * registers are only 32-bits wide but are stored as 64-bit values for
  * convenience
  ******************************************************************************/
-#define CTX_SYSREGS_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
+#define CTX_EL1_SYSREGS_OFFSET	(CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
 #define CTX_SPSR_EL1		U(0x0)
 #define CTX_ELR_EL1		U(0x8)
 #define CTX_SCTLR_EL1		U(0x10)
@@ -138,13 +138,118 @@
 /*
  * End of system registers.
  */
-#define CTX_SYSREGS_END		CTX_MTE_REGS_END
+#define CTX_EL1_SYSREGS_END		CTX_MTE_REGS_END
+
+/*
+ * EL2 register set
+ */
+
+#if CTX_INCLUDE_EL2_REGS
+/* For later discussion
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_LR<n>_EL2
+ */
+#define CTX_EL2_SYSREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+
+#define CTX_ACTLR_EL2		U(0x0)
+#define CTX_AFSR0_EL2		U(0x8)
+#define CTX_AFSR1_EL2		U(0x10)
+#define CTX_AMAIR_EL2		U(0x18)
+#define CTX_CNTHCTL_EL2		U(0x20)
+#define CTX_CNTHP_CTL_EL2	U(0x28)
+#define CTX_CNTHP_CVAL_EL2	U(0x30)
+#define CTX_CNTHP_TVAL_EL2	U(0x38)
+#define CTX_CNTVOFF_EL2		U(0x40)
+#define CTX_CPTR_EL2		U(0x48)
+#define CTX_DBGVCR32_EL2	U(0x50)
+#define CTX_ELR_EL2		U(0x58)
+#define CTX_ESR_EL2		U(0x60)
+#define CTX_FAR_EL2		U(0x68)
+#define CTX_FPEXC32_EL2		U(0x70)
+#define CTX_HACR_EL2		U(0x78)
+#define CTX_HCR_EL2		U(0x80)
+#define CTX_HPFAR_EL2		U(0x88)
+#define CTX_HSTR_EL2		U(0x90)
+#define CTX_ICC_SRE_EL2		U(0x98)
+#define CTX_ICH_HCR_EL2		U(0xa0)
+#define CTX_ICH_VMCR_EL2	U(0xa8)
+#define CTX_MAIR_EL2		U(0xb0)
+#define CTX_MDCR_EL2		U(0xb8)
+#define CTX_PMSCR_EL2		U(0xc0)
+#define CTX_SCTLR_EL2		U(0xc8)
+#define CTX_SPSR_EL2		U(0xd0)
+#define CTX_SP_EL2		U(0xd8)
+#define CTX_TCR_EL2		U(0xe0)
+#define CTX_TRFCR_EL2		U(0xe8)
+#define CTX_TTBR0_EL2		U(0xf0)
+#define CTX_VBAR_EL2		U(0xf8)
+#define CTX_VMPIDR_EL2		U(0x100)
+#define CTX_VPIDR_EL2		U(0x108)
+#define CTX_VTCR_EL2		U(0x110)
+#define CTX_VTTBR_EL2		U(0x118)
+
+// Only if MTE registers in use
+#define CTX_TFSR_EL2		U(0x120)
+
+// Only if ENABLE_MPAM_FOR_LOWER_ELS==1
+#define CTX_MPAM2_EL2		U(0x128)
+#define CTX_MPAMHCR_EL2		U(0x130)
+#define CTX_MPAMVPM0_EL2	U(0x138)
+#define CTX_MPAMVPM1_EL2	U(0x140)
+#define CTX_MPAMVPM2_EL2	U(0x148)
+#define CTX_MPAMVPM3_EL2	U(0x150)
+#define CTX_MPAMVPM4_EL2	U(0x158)
+#define CTX_MPAMVPM5_EL2	U(0x160)
+#define CTX_MPAMVPM6_EL2	U(0x168)
+#define CTX_MPAMVPM7_EL2	U(0x170)
+#define CTX_MPAMVPMV_EL2	U(0x178)
+
+// Starting with Armv8.6
+#define CTX_HAFGRTR_EL2		U(0x180)
+#define CTX_HDFGRTR_EL2		U(0x188)
+#define CTX_HDFGWTR_EL2		U(0x190)
+#define CTX_HFGITR_EL2		U(0x198)
+#define CTX_HFGRTR_EL2		U(0x1a0)
+#define CTX_HFGWTR_EL2		U(0x1a8)
+#define CTX_CNTPOFF_EL2		U(0x1b0)
+
+// Starting with Armv8.4
+#define CTX_CNTHPS_CTL_EL2	U(0x1b8)
+#define CTX_CNTHPS_CVAL_EL2	U(0x1c0)
+#define CTX_CNTHPS_TVAL_EL2	U(0x1c8)
+#define CTX_CNTHVS_CTL_EL2	U(0x1d0)
+#define CTX_CNTHVS_CVAL_EL2	U(0x1d8)
+#define CTX_CNTHVS_TVAL_EL2	U(0x1e0)
+#define CTX_CNTHV_CTL_EL2	U(0x1e8)
+#define CTX_CNTHV_CVAL_EL2	U(0x1f0)
+#define CTX_CNTHV_TVAL_EL2	U(0x1f8)
+#define CTX_CONTEXTIDR_EL2	U(0x200)
+#define CTX_SDER32_EL2		U(0x208)
+#define CTX_TTBR1_EL2		U(0x210)
+#define CTX_VDISR_EL2		U(0x218)
+#define CTX_VNCR_EL2		U(0x220)
+#define CTX_VSESR_EL2		U(0x228)
+#define CTX_VSTCR_EL2		U(0x230)
+#define CTX_VSTTBR_EL2		U(0x238)
+
+// Starting with Armv8.5
+#define CTX_SCXTNUM_EL2		U(0x240)
+/* Align to the next 16 byte boundary */
+#define CTX_EL2_SYSREGS_END	U(0x250)
+#endif /* CTX_INCLUDE_EL2_REGS */
 
 /*******************************************************************************
  * Constants that allow assembler code to access members of and the 'fp_regs'
  * structure at their correct offsets.
  ******************************************************************************/
-#define CTX_FPREGS_OFFSET	(CTX_SYSREGS_OFFSET + CTX_SYSREGS_END)
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_FPREGS_OFFSET	(CTX_EL2_SYSREGS_OFFSET + CTX_EL2_SYSREGS_END)
+#else
+# define CTX_FPREGS_OFFSET	(CTX_EL1_SYSREGS_OFFSET + CTX_EL1_SYSREGS_END)
+#endif
 #if CTX_INCLUDE_FPREGS
 #define CTX_FP_Q0		U(0x0)
 #define CTX_FP_Q1		U(0x10)
@@ -235,7 +340,10 @@
 
 /* Constants to determine the size of individual context structures */
 #define CTX_GPREG_ALL		(CTX_GPREGS_END >> DWORD_SHIFT)
-#define CTX_SYSREG_ALL		(CTX_SYSREGS_END >> DWORD_SHIFT)
+#define CTX_EL1_SYSREGS_ALL	(CTX_EL1_SYSREGS_END >> DWORD_SHIFT)
+#if CTX_INCLUDE_EL2_REGS
+# define CTX_EL2_SYSREGS_ALL	(CTX_EL2_SYSREGS_END >> DWORD_SHIFT)
+#endif
 #if CTX_INCLUDE_FPREGS
 # define CTX_FPREG_ALL		(CTX_FPREGS_END >> DWORD_SHIFT)
 #endif
@@ -256,10 +364,18 @@
 
 /*
  * AArch64 EL1 system register context structure for preserving the
- * architectural state during switches from one security state to
- * another in EL1.
+ * architectural state during world switches.
  */
-DEFINE_REG_STRUCT(el1_sys_regs, CTX_SYSREG_ALL);
+DEFINE_REG_STRUCT(el1_sysregs, CTX_EL1_SYSREGS_ALL);
+
+
+/*
+ * AArch64 EL2 system register context structure for preserving the
+ * architectural state during world switches.
+ */
+#if CTX_INCLUDE_EL2_REGS
+DEFINE_REG_STRUCT(el2_sysregs, CTX_EL2_SYSREGS_ALL);
+#endif
 
 /*
  * AArch64 floating point register context structure for preserving
@@ -304,7 +420,10 @@
 typedef struct cpu_context {
 	gp_regs_t gpregs_ctx;
 	el3_state_t el3state_ctx;
-	el1_sys_regs_t sysregs_ctx;
+	el1_sysregs_t el1_sysregs_ctx;
+#if CTX_INCLUDE_EL2_REGS
+	el2_sysregs_t el2_sysregs_ctx;
+#endif
 #if CTX_INCLUDE_FPREGS
 	fp_regs_t fpregs_ctx;
 #endif
@@ -319,7 +438,10 @@
 #if CTX_INCLUDE_FPREGS
 # define get_fpregs_ctx(h)	(&((cpu_context_t *) h)->fpregs_ctx)
 #endif
-#define get_sysregs_ctx(h)	(&((cpu_context_t *) h)->sysregs_ctx)
+#define get_el1_sysregs_ctx(h)	(&((cpu_context_t *) h)->el1_sysregs_ctx)
+#if CTX_INCLUDE_EL2_REGS
+# define get_el2_sysregs_ctx(h)	(&((cpu_context_t *) h)->el2_sysregs_ctx)
+#endif
 #define get_gpregs_ctx(h)	(&((cpu_context_t *) h)->gpregs_ctx)
 #define get_cve_2018_3639_ctx(h)	(&((cpu_context_t *) h)->cve_2018_3639_ctx)
 #if CTX_INCLUDE_PAUTH_REGS
@@ -333,8 +455,12 @@
  */
 CASSERT(CTX_GPREGS_OFFSET == __builtin_offsetof(cpu_context_t, gpregs_ctx), \
 	assert_core_context_gp_offset_mismatch);
-CASSERT(CTX_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, sysregs_ctx), \
-	assert_core_context_sys_offset_mismatch);
+CASSERT(CTX_EL1_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el1_sysregs_ctx), \
+	assert_core_context_el1_sys_offset_mismatch);
+#if CTX_INCLUDE_EL2_REGS
+CASSERT(CTX_EL2_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, el2_sysregs_ctx), \
+	assert_core_context_el2_sys_offset_mismatch);
+#endif
 #if CTX_INCLUDE_FPREGS
 CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx), \
 	assert_core_context_fp_offset_mismatch);
@@ -387,8 +513,14 @@
 /*******************************************************************************
  * Function prototypes
  ******************************************************************************/
-void el1_sysregs_context_save(el1_sys_regs_t *regs);
-void el1_sysregs_context_restore(el1_sys_regs_t *regs);
+void el1_sysregs_context_save(el1_sysregs_t *regs);
+void el1_sysregs_context_restore(el1_sysregs_t *regs);
+
+#if CTX_INCLUDE_EL2_REGS
+void el2_sysregs_context_save(el2_sysregs_t *regs);
+void el2_sysregs_context_restore(el2_sysregs_t *regs);
+#endif
+
 #if CTX_INCLUDE_FPREGS
 void fpregs_context_save(fp_regs_t *regs);
 void fpregs_context_restore(fp_regs_t *regs);
diff --git a/include/lib/el3_runtime/context_mgmt.h b/include/lib/el3_runtime/context_mgmt.h
index 17955e3..b36cd3d 100644
--- a/include/lib/el3_runtime/context_mgmt.h
+++ b/include/lib/el3_runtime/context_mgmt.h
@@ -36,6 +36,11 @@
 void cm_prepare_el3_exit(uint32_t security_state);
 
 #ifdef __aarch64__
+#if CTX_INCLUDE_EL2_REGS
+void cm_el2_sysregs_context_save(uint32_t security_state);
+void cm_el2_sysregs_context_restore(uint32_t security_state);
+#endif
+
 void cm_el1_sysregs_context_save(uint32_t security_state);
 void cm_el1_sysregs_context_restore(uint32_t security_state);
 void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint);
diff --git a/include/services/spm_core_manifest.h b/include/services/spm_core_manifest.h
index 06ecc13..7874882 100644
--- a/include/services/spm_core_manifest.h
+++ b/include/services/spm_core_manifest.h
@@ -21,13 +21,6 @@
 	uint32_t minor_version;
 
 	/*
-	 * Run-Time Exception Level (mandatory):
-	 * - 1: SEL1
-	 * - 2: SEL2
-	 */
-	uint32_t runtime_el;
-
-	/*
 	 * Run-Time Execution state (optional):
 	 * - 0: AArch64 (default)
 	 * - 1: AArch32
diff --git a/include/services/spmd_svc.h b/include/services/spmd_svc.h
index 6e4caf2..a766dcf 100644
--- a/include/services/spmd_svc.h
+++ b/include/services/spmd_svc.h
@@ -11,7 +11,7 @@
 #include <services/spci_svc.h>
 #include <stdint.h>
 
-int32_t spmd_setup(void);
+int spmd_setup(void);
 uint64_t spmd_smc_handler(uint32_t smc_fid,
 			  uint64_t x1,
 			  uint64_t x2,
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 9bd25ba..30ad7b7 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,11 @@
 #include <assert_macros.S>
 #include <context.h>
 
+#if CTX_INCLUDE_EL2_REGS
+	.global	el2_sysregs_context_save
+	.global	el2_sysregs_context_restore
+#endif
+
 	.global	el1_sysregs_context_save
 	.global	el1_sysregs_context_restore
 #if CTX_INCLUDE_FPREGS
@@ -19,6 +24,385 @@
 	.global	restore_gp_pmcr_pauth_regs
 	.global	el3_exit
 
+#if CTX_INCLUDE_EL2_REGS
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to save EL2 system register context. It assumes that
+ * 'x0' is pointing to a 'el2_sys_regs' structure where
+ * the register context will be saved.
+ *
+ * The following registers are not added.
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * ICH_LR<n>_EL2
+ * -----------------------------------------------------
+ */
+
+func el2_sysregs_context_save
+	mrs	x9, actlr_el2
+	mrs	x10, afsr0_el2
+	stp	x9, x10, [x0, #CTX_ACTLR_EL2]
+
+	mrs	x11, afsr1_el2
+	mrs	x12, amair_el2
+	stp	x11, x12, [x0, #CTX_AFSR1_EL2]
+
+	mrs	x13, cnthctl_el2
+	mrs	x14, cnthp_ctl_el2
+	stp	x13, x14, [x0, #CTX_CNTHCTL_EL2]
+
+	mrs	x15, cnthp_cval_el2
+	mrs	x16, cnthp_tval_el2
+	stp	x15, x16, [x0, #CTX_CNTHP_CVAL_EL2]
+
+	mrs	x17, cntvoff_el2
+	mrs	x9, cptr_el2
+	stp	x17, x9, [x0, #CTX_CNTVOFF_EL2]
+
+	mrs	x10, dbgvcr32_el2
+	mrs	x11, elr_el2
+	stp	x10, x11, [x0, #CTX_DBGVCR32_EL2]
+
+	mrs	x14, esr_el2
+	mrs	x15, far_el2
+	stp	x14, x15, [x0, #CTX_ESR_EL2]
+
+	mrs	x16, fpexc32_el2
+	mrs	x17, hacr_el2
+	stp	x16, x17, [x0, #CTX_FPEXC32_EL2]
+
+	mrs	x9, hcr_el2
+	mrs	x10, hpfar_el2
+	stp	x9, x10, [x0, #CTX_HCR_EL2]
+
+	mrs	x11, hstr_el2
+	mrs	x12, ICC_SRE_EL2
+	stp	x11, x12, [x0, #CTX_HSTR_EL2]
+
+	mrs	x13, ICH_HCR_EL2
+	mrs	x14, ICH_VMCR_EL2
+	stp	x13, x14, [x0, #CTX_ICH_HCR_EL2]
+
+	mrs	x15, mair_el2
+	mrs	x16, mdcr_el2
+	stp	x15, x16, [x0, #CTX_MAIR_EL2]
+
+	mrs	x17, PMSCR_EL2
+	mrs	x9, sctlr_el2
+	stp	x17, x9, [x0, #CTX_PMSCR_EL2]
+
+	mrs	x10, spsr_el2
+	mrs	x11, sp_el2
+	stp	x10, x11, [x0, #CTX_SPSR_EL2]
+
+	mrs	x12, tcr_el2
+	mrs	x13, TRFCR_EL2
+	stp	x12, x13, [x0, #CTX_TCR_EL2]
+
+	mrs	x14, ttbr0_el2
+	mrs	x15, vbar_el2
+	stp	x14, x15, [x0, #CTX_TTBR0_EL2]
+
+	mrs	x16, vmpidr_el2
+	mrs	x17, vpidr_el2
+	stp	x16, x17, [x0, #CTX_VMPIDR_EL2]
+
+	mrs	x9, vtcr_el2
+	mrs	x10, vttbr_el2
+	stp	x9, x10, [x0, #CTX_VTCR_EL2]
+
+#if CTX_INCLUDE_MTE_REGS
+	mrs	x11, TFSR_EL2
+	str	x11, [x0, #CTX_TFSR_EL2]
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	mrs	x9, MPAM2_EL2
+	mrs	x10, MPAMHCR_EL2
+	stp	x9, x10, [x0, #CTX_MPAM2_EL2]
+
+	mrs	x11, MPAMVPM0_EL2
+	mrs	x12, MPAMVPM1_EL2
+	stp	x11, x12, [x0, #CTX_MPAMVPM0_EL2]
+
+	mrs	x13, MPAMVPM2_EL2
+	mrs	x14, MPAMVPM3_EL2
+	stp	x13, x14, [x0, #CTX_MPAMVPM2_EL2]
+
+	mrs	x15, MPAMVPM4_EL2
+	mrs	x16, MPAMVPM5_EL2
+	stp	x15, x16, [x0, #CTX_MPAMVPM4_EL2]
+
+	mrs	x17, MPAMVPM6_EL2
+	mrs	x9, MPAMVPM7_EL2
+	stp	x17, x9, [x0, #CTX_MPAMVPM6_EL2]
+
+	mrs	x10, MPAMVPMV_EL2
+	str	x10, [x0, #CTX_MPAMVPMV_EL2]
+#endif
+
+
+#if ARM_ARCH_AT_LEAST(8, 6)
+	mrs	x11, HAFGRTR_EL2
+	mrs	x12, HDFGRTR_EL2
+	stp	x11, x12, [x0, #CTX_HAFGRTR_EL2]
+
+	mrs	x13, HDFGWTR_EL2
+	mrs	x14, HFGITR_EL2
+	stp	x13, x14, [x0, #CTX_HDFGWTR_EL2]
+
+	mrs	x15, HFGRTR_EL2
+	mrs	x16, HFGWTR_EL2
+	stp	x15, x16, [x0, #CTX_HFGRTR_EL2]
+
+	mrs	x17, CNTPOFF_EL2
+	str	x17, [x0, #CTX_CNTPOFF_EL2]
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 4)
+	mrs	x9, cnthps_ctl_el2
+	mrs	x10, cnthps_cval_el2
+	stp	x9, x10, [x0, #CTX_CNTHPS_CTL_EL2]
+
+	mrs	x11, cnthps_tval_el2
+	mrs	x12, cnthvs_ctl_el2
+	stp	x11, x12, [x0, #CTX_CNTHPS_TVAL_EL2]
+
+	mrs	x13, cnthvs_cval_el2
+	mrs	x14, cnthvs_tval_el2
+	stp	x13, x14, [x0, #CTX_CNTHVS_CVAL_EL2]
+
+	mrs	x15, cnthv_ctl_el2
+	mrs	x16, cnthv_cval_el2
+	stp	x15, x16, [x0, #CTX_CNTHV_CTL_EL2]
+
+	mrs	x17, cnthv_tval_el2
+	mrs	x9, contextidr_el2
+	stp	x17, x9, [x0, #CTX_CNTHV_TVAL_EL2]
+
+	mrs	x10, sder32_el2
+	str	x10, [x0, #CTX_SDER32_EL2]
+
+	mrs	x11, ttbr1_el2
+	str	x11, [x0, #CTX_TTBR1_EL2]
+
+	mrs	x12, vdisr_el2
+	str	x12, [x0, #CTX_VDISR_EL2]
+
+	mrs	x13, vncr_el2
+	str	x13, [x0, #CTX_VNCR_EL2]
+
+	mrs	x14, vsesr_el2
+	str	x14, [x0, #CTX_VSESR_EL2]
+
+	mrs	x15, vstcr_el2
+	str	x15, [x0, #CTX_VSTCR_EL2]
+
+	mrs	x16, vsttbr_el2
+	str	x16, [x0, #CTX_VSTTBR_EL2]
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 5)
+	mrs	x17, scxtnum_el2
+	str	x17, [x0, #CTX_SCXTNUM_EL2]
+#endif
+
+	ret
+endfunc el2_sysregs_context_save
+
+/* -----------------------------------------------------
+ * The following function strictly follows the AArch64
+ * PCS to use x9-x17 (temporary caller-saved registers)
+ * to restore EL2 system register context.  It assumes
+ * that 'x0' is pointing to a 'el2_sys_regs' structure
+ * from where the register context will be restored
+
+ * The following registers are not restored
+ * AMEVCNTVOFF0<n>_EL2
+ * AMEVCNTVOFF1<n>_EL2
+ * ICH_AP0R<n>_EL2
+ * ICH_AP1R<n>_EL2
+ * ICH_LR<n>_EL2
+ * -----------------------------------------------------
+ */
+func el2_sysregs_context_restore
+
+	ldp	x9, x10, [x0, #CTX_ACTLR_EL2]
+	msr	actlr_el2, x9
+	msr	afsr0_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_AFSR1_EL2]
+	msr	afsr1_el2, x11
+	msr	amair_el2, x12
+
+	ldp	x13, x14, [x0, #CTX_CNTHCTL_EL2]
+	msr	cnthctl_el2, x13
+	msr	cnthp_ctl_el2, x14
+
+	ldp	x15, x16, [x0, #CTX_CNTHP_CVAL_EL2]
+	msr	cnthp_cval_el2, x15
+	msr	cnthp_tval_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_CNTVOFF_EL2]
+	msr	cntvoff_el2, x17
+	msr	cptr_el2, x9
+
+	ldp	x10, x11, [x0, #CTX_DBGVCR32_EL2]
+	msr	dbgvcr32_el2, x10
+	msr	elr_el2, x11
+
+	ldp	x14, x15, [x0, #CTX_ESR_EL2]
+	msr	esr_el2, x14
+	msr	far_el2, x15
+
+	ldp	x16, x17, [x0, #CTX_FPEXC32_EL2]
+	msr	fpexc32_el2, x16
+	msr	hacr_el2, x17
+
+	ldp	x9, x10, [x0, #CTX_HCR_EL2]
+	msr	hcr_el2, x9
+	msr	hpfar_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_HSTR_EL2]
+	msr	hstr_el2, x11
+	msr	ICC_SRE_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_ICH_HCR_EL2]
+	msr	ICH_HCR_EL2, x13
+	msr	ICH_VMCR_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_MAIR_EL2]
+	msr	mair_el2, x15
+	msr	mdcr_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_PMSCR_EL2]
+	msr	PMSCR_EL2, x17
+	msr	sctlr_el2, x9
+
+	ldp	x10, x11, [x0, #CTX_SPSR_EL2]
+	msr	spsr_el2, x10
+	msr	sp_el2, x11
+
+	ldp	x12, x13, [x0, #CTX_TCR_EL2]
+	msr	tcr_el2, x12
+	msr	TRFCR_EL2, x13
+
+	ldp	x14, x15, [x0, #CTX_TTBR0_EL2]
+	msr	ttbr0_el2, x14
+	msr	vbar_el2, x15
+
+	ldp	x16, x17, [x0, #CTX_VMPIDR_EL2]
+	msr	vmpidr_el2, x16
+	msr	vpidr_el2, x17
+
+	ldp	x9, x10, [x0, #CTX_VTCR_EL2]
+	msr	vtcr_el2, x9
+	msr	vttbr_el2, x10
+
+#if CTX_INCLUDE_MTE_REGS
+	ldr	x11, [x0, #CTX_TFSR_EL2]
+	msr	TFSR_EL2, x11
+#endif
+
+#if ENABLE_MPAM_FOR_LOWER_ELS
+	ldp	x9, x10, [x0, #CTX_MPAM2_EL2]
+	msr	MPAM2_EL2, x9
+	msr	MPAMHCR_EL2, x10
+
+	ldp	x11, x12, [x0, #CTX_MPAMVPM0_EL2]
+	msr	MPAMVPM0_EL2, x11
+	msr	MPAMVPM1_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_MPAMVPM2_EL2]
+	msr	MPAMVPM2_EL2, x13
+	msr	MPAMVPM3_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_MPAMVPM4_EL2]
+	msr	MPAMVPM4_EL2, x15
+	msr	MPAMVPM5_EL2, x16
+
+	ldp	x17, x9, [x0, #CTX_MPAMVPM6_EL2]
+	msr	MPAMVPM6_EL2, x17
+	msr	MPAMVPM7_EL2, x9
+
+	ldr	x10, [x0, #CTX_MPAMVPMV_EL2]
+	msr	MPAMVPMV_EL2, x10
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 6)
+	ldp	x11, x12, [x0, #CTX_HAFGRTR_EL2]
+	msr	HAFGRTR_EL2, x11
+	msr	HDFGRTR_EL2, x12
+
+	ldp	x13, x14, [x0, #CTX_HDFGWTR_EL2]
+	msr	HDFGWTR_EL2, x13
+	msr	HFGITR_EL2, x14
+
+	ldp	x15, x16, [x0, #CTX_HFGRTR_EL2]
+	msr	HFGRTR_EL2, x15
+	msr	HFGWTR_EL2, x16
+
+	ldr	x17, [x0, #CTX_CNTPOFF_EL2]
+	msr	CNTPOFF_EL2, x17
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 4)
+	ldp	x9, x10, [x0, #CTX_CNTHPS_CTL_EL2]
+	msr	cnthps_ctl_el2, x9
+	msr	cnthps_cval_el2, x10
+
+	ldp	x11, x12, [x0, #CTX_CNTHPS_TVAL_EL2]
+	msr	cnthps_tval_el2, x11
+	msr	cnthvs_ctl_el2, x12
+
+	ldp	x13, x14, [x0, #CTX_CNTHVS_CVAL_EL2]
+	msr	cnthvs_cval_el2, x13
+	msr	cnthvs_tval_el2, x14
+
+	ldp	x15, x16, [x0, #CTX_CNTHV_CTL_EL2]
+	msr	cnthv_ctl_el2, x15
+	msr	cnthv_cval_el2, x16
+
+	ldp	x17, x9, [x0, #CTX_CNTHV_TVAL_EL2]
+	msr	cnthv_tval_el2, x17
+	msr	contextidr_el2, x9
+
+	ldr	x10, [x0, #CTX_SDER32_EL2]
+	msr	sder32_el2, x10
+
+	ldr	x11, [x0, #CTX_TTBR1_EL2]
+	msr	ttbr1_el2, x11
+
+	ldr	x12, [x0, #CTX_VDISR_EL2]
+	msr	vdisr_el2, x12
+
+	ldr	x13, [x0, #CTX_VNCR_EL2]
+	msr	vncr_el2, x13
+
+	ldr	x14, [x0, #CTX_VSESR_EL2]
+	msr	vsesr_el2, x14
+
+	ldr	x15, [x0, #CTX_VSTCR_EL2]
+	msr	vstcr_el2, x15
+
+	ldr	x16, [x0, #CTX_VSTTBR_EL2]
+	msr	vsttbr_el2, x16
+#endif
+
+#if ARM_ARCH_AT_LEAST(8, 5)
+	ldr	x17, [x0, #CTX_SCXTNUM_EL2]
+	msr	scxtnum_el2, x17
+#endif
+
+	ret
+endfunc el2_sysregs_context_restore
+
+#endif /* CTX_INCLUDE_EL2_REGS */
+
 /* ------------------------------------------------------------------
  * The following function strictly follows the AArch64 PCS to use
  * x9-x17 (temporary caller-saved registers) to save EL1 system
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 546e39e..0314a85 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -234,7 +234,7 @@
 	 * and other EL2 registers are set up by cm_prepare_ns_entry() as they
 	 * are not part of the stored cpu_context.
 	 */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx);
 
 	/*
 	 * Base the context ACTLR_EL1 on the current value, as it is
@@ -244,7 +244,7 @@
 	 * be zero.
 	 */
 	actlr_elx = read_actlr_el1();
-	write_ctx_reg((get_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
+	write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
 
 	/*
 	 * Populate EL3 state so that we've the right context
@@ -336,7 +336,7 @@
 						 CTX_SCR_EL3);
 		if ((scr_el3 & SCR_HCE_BIT) != 0U) {
 			/* Use SCTLR_EL1.EE value to initialise sctlr_el2 */
-			sctlr_elx = read_ctx_reg(get_sysregs_ctx(ctx),
+			sctlr_elx = read_ctx_reg(get_el1_sysregs_ctx(ctx),
 							   CTX_SCTLR_EL1);
 			sctlr_elx &= SCTLR_EE_BIT;
 			sctlr_elx |= SCTLR_EL2_RES1;
@@ -530,6 +530,52 @@
 	cm_set_next_eret_context(security_state);
 }
 
+#if CTX_INCLUDE_EL2_REGS
+/*******************************************************************************
+ * Save EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_save(uint32_t security_state)
+{
+	u_register_t scr_el3 = read_scr();
+
+	/*
+	 * Always save the non-secure EL2 context, only save the
+	 * S-EL2 context if S-EL2 is enabled.
+	 */
+	if ((security_state == NON_SECURE) ||
+	    ((scr_el3 & SCR_EEL2_BIT) != 0U)) {
+		cpu_context_t *ctx;
+
+		ctx = cm_get_context(security_state);
+		assert(ctx != NULL);
+
+		el2_sysregs_context_save(get_el2_sysregs_ctx(ctx));
+	}
+}
+
+/*******************************************************************************
+ * Restore EL2 sysreg context
+ ******************************************************************************/
+void cm_el2_sysregs_context_restore(uint32_t security_state)
+{
+	u_register_t scr_el3 = read_scr();
+
+	/*
+	 * Always restore the non-secure EL2 context, only restore the
+	 * S-EL2 context if S-EL2 is enabled.
+	 */
+	if ((security_state == NON_SECURE) ||
+	    ((scr_el3 & SCR_EEL2_BIT) != 0U)) {
+		cpu_context_t *ctx;
+
+		ctx = cm_get_context(security_state);
+		assert(ctx != NULL);
+
+		el2_sysregs_context_restore(get_el2_sysregs_ctx(ctx));
+	}
+}
+#endif /* CTX_INCLUDE_EL2_REGS */
+
 /*******************************************************************************
  * The next four functions are used by runtime services to save and restore
  * EL1 context on the 'cpu_context' structure for the specified security
@@ -542,7 +588,7 @@
 	ctx = cm_get_context(security_state);
 	assert(ctx != NULL);
 
-	el1_sysregs_context_save(get_sysregs_ctx(ctx));
+	el1_sysregs_context_save(get_el1_sysregs_ctx(ctx));
 
 #if IMAGE_BL31
 	if (security_state == SECURE)
@@ -559,7 +605,7 @@
 	ctx = cm_get_context(security_state);
 	assert(ctx != NULL);
 
-	el1_sysregs_context_restore(get_sysregs_ctx(ctx));
+	el1_sysregs_context_restore(get_el1_sysregs_ctx(ctx));
 
 #if IMAGE_BL31
 	if (security_state == SECURE)
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 60958a1..9273469 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -188,6 +188,9 @@
 # Enable the Management Mode (MM)-based Secure Partition Manager implementation
 SPM_MM				:= 0
 
+# Use SPM at S-EL2 as a default config for SPMD
+SPMD_SPM_AT_SEL2		:= 1
+
 # Flag to introduce an infinite loop in BL1 just before it exits into the next
 # image. This is meant to help debugging the post-BL2 phase.
 SPIN_ON_BL1_EXIT		:= 0
@@ -262,3 +265,8 @@
 
 # Enable Link Time Optimization
 ENABLE_LTO			:= 0
+
+# Build flag to include EL2 registers in cpu context save and restore during
+# S-EL2 firmware entry/exit. This flag is to be used with SPD=spmd option.
+# Default is 0.
+CTX_INCLUDE_EL2_REGS		:= 0
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index e1c106f..c94a209 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -11,7 +11,6 @@
 	attribute {
 		maj_ver = <0x0>;
 		min_ver = <0x9>;
-		runtime_el = <0x1>;
 		exec_state = <0x0>;
 		load_address = <0x0 0x6000000>;
 		entrypoint = <0x0 0x6000000>;
diff --git a/plat/common/plat_spmd_manifest.c b/plat/common/plat_spmd_manifest.c
index 4c78979..9c3dc71 100644
--- a/plat/common/plat_spmd_manifest.c
+++ b/plat/common/plat_spmd_manifest.c
@@ -37,12 +37,6 @@
 		return -ENOENT;
 	}
 
-	rc = fdtw_read_cells(fdt, node, "runtime_el", 1, &attr->runtime_el);
-	if (rc) {
-		ERROR("Missing SPM core runtime EL in manifest.\n");
-		return -ENOENT;
-	}
-
 	rc = fdtw_read_cells(fdt, node, "exec_state", 1, &attr->exec_state);
 	if (rc)
 		NOTICE("Execution state not specified in SPM core manifest.\n");
@@ -61,7 +55,6 @@
 
 	VERBOSE("SPM core manifest attribute section:\n");
 	VERBOSE("  version: %x.%x\n", attr->major_version, attr->minor_version);
-	VERBOSE("  runtime_el: 0x%x\n", attr->runtime_el);
 	VERBOSE("  binary_size: 0x%x\n", attr->binary_size);
 	VERBOSE("  load_address: 0x%llx\n", attr->load_address);
 	VERBOSE("  entrypoint: 0x%llx\n", attr->entrypoint);
diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c
index 60b5595..8e198ae 100644
--- a/plat/nvidia/tegra/common/tegra_fiq_glue.c
+++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -155,7 +155,7 @@
 {
 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
 	gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx);
-	const el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx);
+	const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx);
 	uint32_t cpu = plat_my_core_pos();
 	uint64_t val;
 
diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c
index 092ffa8..ba2f4a6 100644
--- a/services/spd/trusty/trusty.c
+++ b/services/spd/trusty/trusty.c
@@ -150,9 +150,9 @@
 	(void)memcpy(&ctx->fiq_gpregs, get_gpregs_ctx(handle), sizeof(ctx->fiq_gpregs));
 	ctx->fiq_pc = SMC_GET_EL3(handle, CTX_ELR_EL3);
 	ctx->fiq_cpsr = SMC_GET_EL3(handle, CTX_SPSR_EL3);
-	ctx->fiq_sp_el1 = read_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1);
+	ctx->fiq_sp_el1 = read_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1);
 
-	write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_handler_sp);
+	write_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_handler_sp);
 	cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_handler_pc, (uint32_t)ctx->fiq_handler_cpsr);
 
 	SMC_RET0(handle);
@@ -211,7 +211,7 @@
 	 */
 	(void)memcpy(get_gpregs_ctx(handle), &ctx->fiq_gpregs, sizeof(ctx->fiq_gpregs));
 	ctx->fiq_handler_active = 0;
-	write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_sp_el1);
+	write_ctx_reg(get_el1_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_sp_el1);
 	cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_pc, (uint32_t)ctx->fiq_cpsr);
 
 	SMC_RET0(handle);
diff --git a/services/std_svc/spm_mm/spm_mm_setup.c b/services/std_svc/spm_mm/spm_mm_setup.c
index ccb2f90..468e5b3 100644
--- a/services/std_svc/spm_mm/spm_mm_setup.c
+++ b/services/std_svc/spm_mm/spm_mm_setup.c
@@ -116,17 +116,17 @@
 		      xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
 		      EL1_EL0_REGIME);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
 		      mmu_cfg_params[MMU_CFG_MAIR]);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
 		      mmu_cfg_params[MMU_CFG_TCR]);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
 		      mmu_cfg_params[MMU_CFG_TTBR0]);
 
 	/* Setup SCTLR_EL1 */
-	u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1);
+	u_register_t sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1);
 
 	sctlr_el1 |=
 		/*SCTLR_EL1_RES1 |*/
@@ -160,7 +160,7 @@
 		SCTLR_UMA_BIT
 	);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
 
 	/*
 	 * Setup other system registers
@@ -168,10 +168,10 @@
 	 */
 
 	/* Shim Exception Vector Base Address */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
 			SPM_SHIM_EXCEPTIONS_PTR);
 
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
 		      EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
 
 	/*
@@ -181,7 +181,7 @@
 	 * TTA: Enable access to trace registers.
 	 * ZEN (v8.2): Trap SVE instructions and access to SVE registers.
 	 */
-	write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1,
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1,
 			CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
 
 	/*
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 677f639..2cdf4f5 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -33,9 +33,25 @@
 /*******************************************************************************
  * SPM Core attribute information read from its manifest.
  ******************************************************************************/
-spmc_manifest_sect_attribute_t spmc_attrs;
+static spmc_manifest_sect_attribute_t spmc_attrs;
 
 /*******************************************************************************
+ * SPM Core entry point information. Discovered on the primary core and reused
+ * on secondary cores.
+ ******************************************************************************/
+static entry_point_info_t *spmc_ep_info;
+
+/*******************************************************************************
+ * Static function declaration.
+ ******************************************************************************/
+static int32_t	spmd_init(void);
+static int	spmd_spmc_init(void *rd_base, size_t rd_size);
+static uint64_t	spmd_spci_error_return(void *handle, 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);
+
+/*******************************************************************************
  * This function takes an SP context pointer and performs a synchronous entry
  * into it.
  ******************************************************************************/
@@ -49,17 +65,19 @@
 
 	/* Restore the context assigned above */
 	cm_el1_sysregs_context_restore(SECURE);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_restore(SECURE);
+#endif
 	cm_set_next_eret_context(SECURE);
 
-	/* Invalidate TLBs at EL1. */
-	tlbivmalle1();
-	dsbish();
-
-	/* Enter Secure Partition */
+	/* Enter SPMC */
 	rc = spmd_spm_core_enter(&spmc_ctx->c_rt_ctx);
 
 	/* Save secure state */
 	cm_el1_sysregs_context_save(SECURE);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_save(SECURE);
+#endif
 
 	return rc;
 }
@@ -109,63 +127,21 @@
 }
 
 /*******************************************************************************
- * Initialize context of SPM core.
+ * Load SPMC manifest, init SPMC.
  ******************************************************************************/
-int32_t spmd_setup(void)
+static int spmd_spmc_init(void *rd_base, size_t rd_size)
 {
 	int rc;
-	void *rd_base;
-	size_t rd_size;
-	entry_point_info_t *spmc_ep_info;
-	uintptr_t rd_base_align;
-	uintptr_t rd_size_align;
 	uint32_t ep_attr;
-
-	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
-	if (!spmc_ep_info) {
-		WARN("No SPM core image provided by BL2 boot loader, Booting "
-		     "device without SP initialization. SMC`s destined for SPM "
-		     "core will return SMC_UNK\n");
-		return 1;
-	}
-
-	/* Under no circumstances will this parameter be 0 */
-	assert(spmc_ep_info->pc != 0U);
-
-	/*
-	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
-	 * be used as a manifest for the SPM core at the next lower EL/mode.
-	 */
-	if (spmc_ep_info->args.arg0 == 0U || spmc_ep_info->args.arg2 == 0U) {
-		ERROR("Invalid or absent SPM core manifest\n");
-		panic();
-	}
-
-	/* Obtain whereabouts of SPM core manifest */
-	rd_base = (void *) spmc_ep_info->args.arg0;
-	rd_size = spmc_ep_info->args.arg2;
-
-	rd_base_align = page_align((uintptr_t) rd_base, DOWN);
-	rd_size_align = page_align((uintptr_t) rd_size, UP);
-
-	/* Map the manifest in the SPMD translation regime first */
-	VERBOSE("SPM core manifest base : 0x%lx\n", rd_base_align);
-	VERBOSE("SPM core manifest size : 0x%lx\n", rd_size_align);
-	rc = mmap_add_dynamic_region((unsigned long long) rd_base_align,
-				     (uintptr_t) rd_base_align,
-				     rd_size_align,
-				     MT_RO_DATA);
-	if (rc < 0) {
-		ERROR("Error while mapping SPM core manifest (%d).\n", rc);
-		panic();
-	}
+	unsigned int linear_id = plat_my_core_pos();
+	spmd_spm_core_context_t *spm_ctx = &spm_core_context[linear_id];
 
 	/* Load the SPM core manifest */
 	rc = plat_spm_core_manifest_load(&spmc_attrs, rd_base, rd_size);
-	if (rc < 0) {
+	if (rc != 0) {
 		WARN("No or invalid SPM core manifest image provided by BL2 "
 		     "boot loader. ");
-		goto error;
+		return 1;
 	}
 
 	/*
@@ -177,22 +153,14 @@
 		WARN("Unsupported SPCI version (%x.%x) specified in SPM core "
 		     "manifest image provided by BL2 boot loader.\n",
 		     spmc_attrs.major_version, spmc_attrs.minor_version);
-		goto error;
+		return 1;
 	}
 
 	INFO("SPCI version (%x.%x).\n", spmc_attrs.major_version,
 	     spmc_attrs.minor_version);
 
-	/* Validate the SPM core runtime EL */
-	if ((spmc_attrs.runtime_el != MODE_EL1) &&
-	    (spmc_attrs.runtime_el != MODE_EL2)) {
-		WARN("Unsupported SPM core run time EL%x specified in "
-		     "manifest image provided by BL2 boot loader.\n",
-		     spmc_attrs.runtime_el);
-		goto error;
-	}
-
-	INFO("SPM core run time EL%x.\n", spmc_attrs.runtime_el);
+	INFO("SPM core run time EL%x.\n",
+	     SPMD_SPM_AT_SEL2 ? MODE_EL2 : MODE_EL1);
 
 	/* Validate the SPM core execution state */
 	if ((spmc_attrs.exec_state != MODE_RW_64) &&
@@ -200,42 +168,39 @@
 		WARN("Unsupported SPM core execution state %x specified in "
 		     "manifest image provided by BL2 boot loader.\n",
 		     spmc_attrs.exec_state);
-		goto error;
+		return 1;
 	}
 
 	INFO("SPM core execution state %x.\n", spmc_attrs.exec_state);
 
-	/* Ensure manifest has not requested S-EL2 in AArch32 state */
-	if ((spmc_attrs.exec_state == MODE_RW_32) &&
-	    (spmc_attrs.runtime_el == MODE_EL2)) {
-		WARN("Invalid combination of SPM core execution state (%x) "
-		     "and run time EL (%x).\n", spmc_attrs.exec_state,
-		     spmc_attrs.runtime_el);
-		goto error;
+#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");
+		return 1;
 	}
 
 	/*
 	 * Check if S-EL2 is supported on this system if S-EL2
 	 * is required for SPM
 	 */
-	if (spmc_attrs.runtime_el == MODE_EL2) {
-		uint64_t sel2 = read_id_aa64pfr0_el1();
+	uint64_t sel2 = read_id_aa64pfr0_el1();
 
-		sel2 >>= ID_AA64PFR0_SEL2_SHIFT;
-		sel2 &= ID_AA64PFR0_SEL2_MASK;
+	sel2 >>= ID_AA64PFR0_SEL2_SHIFT;
+	sel2 &= ID_AA64PFR0_SEL2_MASK;
 
-		if (!sel2) {
-			WARN("SPM core run time EL: S-EL%x is not supported "
-			     "but specified in manifest image provided by "
-			     "BL2 boot loader.\n", spmc_attrs.runtime_el);
-			goto error;
-		}
+	if (!sel2) {
+		WARN("SPM core run time S-EL2 is not supported.");
+		return 1;
 	}
+#endif /* SPMD_SPM_AT_SEL2 */
 
 	/* Initialise an entrypoint to set up the CPU context */
 	ep_attr = SECURE | EP_ST_ENABLE;
-	if (read_sctlr_el3() & SCTLR_EE_BIT)
+	if (read_sctlr_el3() & SCTLR_EE_BIT) {
 		ep_attr |= EP_EE_BIG;
+	}
+
 	SET_PARAM_HEAD(spmc_ep_info, PARAM_EP, VERSION_1, ep_attr);
 	assert(spmc_ep_info->pc == BL32_BASE);
 
@@ -250,14 +215,22 @@
 						 DAIF_IRQ_BIT |
 						 DAIF_ABT_BIT);
 	} else {
-		spmc_ep_info->spsr = SPSR_64(spmc_attrs.runtime_el,
+
+#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,
 					     MODE_SP_ELX,
 					     DISABLE_ALL_EXCEPTIONS);
 	}
 
 	/* Initialise SPM core context with this entry point information */
-	cm_setup_context(&(spm_core_context[plat_my_core_pos()].cpu_ctx),
-			 spmc_ep_info);
+	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;
 
 	INFO("SPM core setup done.\n");
 
@@ -265,23 +238,122 @@
 	bl31_register_bl32_init(&spmd_init);
 
 	return 0;
+}
 
-error:
-	WARN("Booting device without SPM initialization. "
-	     "SPCI SMCs destined for SPM core will return "
-	     "ENOTSUPPORTED\n");
+/*******************************************************************************
+ * Initialize context of SPM core.
+ ******************************************************************************/
+int spmd_setup(void)
+{
+	int rc;
+	void *rd_base;
+	size_t rd_size;
+	uintptr_t rd_base_align;
+	uintptr_t rd_size_align;
 
-	rc = mmap_remove_dynamic_region(rd_base_align, rd_size_align);
-	if (rc < 0) {
-		ERROR("Error while unmapping SPM core manifest (%d).\n",
-		      rc);
+	spmc_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
+	if (!spmc_ep_info) {
+		WARN("No SPM core image provided by BL2 boot loader, Booting "
+		     "device without SP initialization. SMC`s destined for SPM "
+		     "core will return SMC_UNK\n");
+		return 1;
+	}
+
+	/* Under no circumstances will this parameter be 0 */
+	assert(spmc_ep_info->pc != 0U);
+
+	/*
+	 * Check if BL32 ep_info has a reference to 'tos_fw_config'. This will
+	 * be used as a manifest for the SPM core at the next lower EL/mode.
+	 */
+	if (spmc_ep_info->args.arg0 == 0U || spmc_ep_info->args.arg2 == 0U) {
+		ERROR("Invalid or absent SPM core manifest\n");
 		panic();
 	}
 
-	return 1;
+	/* Obtain whereabouts of SPM core manifest */
+	rd_base = (void *) spmc_ep_info->args.arg0;
+	rd_size = spmc_ep_info->args.arg2;
+
+	rd_base_align = page_align((uintptr_t) rd_base, DOWN);
+	rd_size_align = page_align((uintptr_t) rd_size, UP);
+
+	/* Map the manifest in the SPMD translation regime first */
+	VERBOSE("SPM core manifest base : 0x%lx\n", rd_base_align);
+	VERBOSE("SPM core manifest size : 0x%lx\n", rd_size_align);
+	rc = mmap_add_dynamic_region((unsigned long long) rd_base_align,
+				     (uintptr_t) rd_base_align,
+				     rd_size_align,
+				     MT_RO_DATA);
+	if (rc != 0) {
+		ERROR("Error while mapping SPM core manifest (%d).\n", rc);
+		panic();
+	}
+
+	/* Load manifest, init SPMC */
+	rc = spmd_spmc_init(rd_base, rd_size);
+	if (rc != 0) {
+		int mmap_rc;
+
+		WARN("Booting device without SPM initialization. "
+		     "SPCI SMCs destined for SPM core will return "
+		     "ENOTSUPPORTED\n");
+
+		mmap_rc = mmap_remove_dynamic_region(rd_base_align,
+						     rd_size_align);
+		if (mmap_rc != 0) {
+			ERROR("Error while unmapping SPM core manifest (%d).\n",
+			      mmap_rc);
+			panic();
+		}
+
+		return rc;
+	}
+
+	return 0;
 }
 
 /*******************************************************************************
+ * Forward SMC to the other security state
+ ******************************************************************************/
+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)
+{
+	uint32_t secure_state_in = (secure_origin) ? SECURE : NON_SECURE;
+	uint32_t secure_state_out = (!secure_origin) ? SECURE : NON_SECURE;
+
+	/* Save incoming security state */
+	cm_el1_sysregs_context_save(secure_state_in);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_save(secure_state_in);
+#endif
+
+	/* Restore outgoing security state */
+	cm_el1_sysregs_context_restore(secure_state_out);
+#if SPMD_SPM_AT_SEL2
+	cm_el2_sysregs_context_restore(secure_state_out);
+#endif
+	cm_set_next_eret_context(secure_state_out);
+
+	SMC_RET8(cm_get_context(secure_state_out), 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));
+}
+
+/*******************************************************************************
+ * Return SPCI_ERROR with specified error code
+ ******************************************************************************/
+static uint64_t spmd_spci_error_return(void *handle, int error_code)
+{
+	SMC_RET8(handle, SPCI_ERROR,
+		 SPCI_TARGET_INFO_MBZ, error_code,
+		 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
+		 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+}
+
+/*******************************************************************************
  * This function handles all SMCs in the range reserved for SPCI. Each call is
  * either forwarded to the other security state or handled by the SPM dispatcher
  ******************************************************************************/
@@ -289,19 +361,12 @@
 			  uint64_t x3, uint64_t x4, void *cookie, void *handle,
 			  uint64_t flags)
 {
-	uint32_t in_sstate;
-	uint32_t out_sstate;
-	int32_t ret;
 	spmd_spm_core_context_t *ctx = &spm_core_context[plat_my_core_pos()];
+	bool secure_origin;
+	int32_t ret;
 
 	/* Determine which security state this SMC originated from */
-	if (is_caller_secure(flags)) {
-		in_sstate = SECURE;
-		out_sstate = NON_SECURE;
-	} else {
-		in_sstate = NON_SECURE;
-		out_sstate = SECURE;
-	}
+	secure_origin = is_caller_secure(flags);
 
 	INFO("SPM: 0x%x, 0x%llx, 0x%llx, 0x%llx, 0x%llx, "
 	     "0x%llx, 0x%llx, 0x%llx\n",
@@ -316,20 +381,12 @@
 		 * this CPU. If so, then indicate that the SPM core initialised
 		 * unsuccessfully.
 		 */
-		if ((in_sstate == SECURE) && (ctx->state == SPMC_STATE_RESET))
+		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
 			spmd_spm_core_sync_exit(x2);
-
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
+		}
 
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	case SPCI_VERSION:
@@ -353,29 +410,18 @@
 		 */
 
 		/*
-		 * Check if w1 holds a valid SPCI fid. This is an
+		 * Check if x1 holds a valid SPCI fid. This is an
 		 * optimization.
 		 */
-		if (!is_spci_fid(x1))
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (!is_spci_fid(x1)) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
+		}
 
 		/* Forward SMC from Normal world to the SPM core */
-		if (in_sstate == NON_SECURE) {
-			/* Save incoming security state */
-			cm_el1_sysregs_context_save(in_sstate);
-
-			/* Restore outgoing security state */
-			cm_el1_sysregs_context_restore(out_sstate);
-			cm_set_next_eret_context(out_sstate);
-
-			SMC_RET8(cm_get_context(out_sstate), 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));
+		if (!secure_origin) {
+			return spmd_smc_forward(smc_fid, secure_origin,
+						x1, x2, x3, x4, handle);
 		} else {
 			/*
 			 * Return success if call was from secure world i.e. all
@@ -387,6 +433,7 @@
 				 SMC_GET_GP(handle, CTX_GPREG_X6),
 				 SMC_GET_GP(handle, CTX_GPREG_X7));
 		}
+
 		break; /* not reached */
 
 	case SPCI_RX_RELEASE:
@@ -395,11 +442,9 @@
 	case SPCI_RXTX_UNMAP:
 	case SPCI_MSG_RUN:
 		/* This interface must be invoked only by the Normal world */
-		if (in_sstate == SECURE) {
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (secure_origin) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
 		}
 
 		/* Fall through to forward the call to the other world */
@@ -430,17 +475,8 @@
 		 * simply forward the call to the Normal world.
 		 */
 
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
-
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	case SPCI_MSG_WAIT:
@@ -449,39 +485,25 @@
 		 * this CPU from the Secure world. If so, then indicate that the
 		 * SPM core initialised successfully.
 		 */
-		if ((in_sstate == SECURE) && (ctx->state == SPMC_STATE_RESET)) {
+		if (secure_origin && (ctx->state == SPMC_STATE_RESET)) {
 			spmd_spm_core_sync_exit(0);
 		}
 
-		/* Intentional fall-through */
+		/* Fall through to forward the call to the other world */
 
 	case SPCI_MSG_YIELD:
 		/* This interface must be invoked only by the Secure world */
-		if (in_sstate == NON_SECURE) {
-			SMC_RET8(handle, SPCI_ERROR,
-				 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-				 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		if (!secure_origin) {
+			return spmd_spci_error_return(handle,
+						      SPCI_ERROR_NOT_SUPPORTED);
 		}
 
-		/* Save incoming security state */
-		cm_el1_sysregs_context_save(in_sstate);
-
-		/* Restore outgoing security state */
-		cm_el1_sysregs_context_restore(out_sstate);
-		cm_set_next_eret_context(out_sstate);
-
-		SMC_RET8(cm_get_context(out_sstate), 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));
+		return spmd_smc_forward(smc_fid, secure_origin,
+					x1, x2, x3, x4, handle);
 		break; /* not reached */
 
 	default:
 		WARN("SPM: Unsupported call 0x%08x\n", smc_fid);
-		SMC_RET8(handle, SPCI_ERROR,
-			 SPCI_TARGET_INFO_MBZ, SPCI_ERROR_NOT_SUPPORTED,
-			 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ, SPCI_PARAM_MBZ,
-			 SPCI_PARAM_MBZ, SPCI_PARAM_MBZ);
+		return spmd_spci_error_return(handle, SPCI_ERROR_NOT_SUPPORTED);
 	}
 }