Merge "feat(libc): add printf support for space padding" into integration
diff --git a/Makefile b/Makefile
index 81143e4..a107785 100644
--- a/Makefile
+++ b/Makefile
@@ -308,6 +308,10 @@
 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105523
 TF_CFLAGS		+= 	$(call cc_option, --param=min-pagesize=0)
 
+ifeq ($(HARDEN_SLS), 1)
+        TF_CFLAGS_aarch64       +=      $(call cc_option, -mharden-sls=all)
+endif
+
 else
 # using clang
 WARNINGS	+=		-Wshift-overflow -Wshift-sign-overflow \
@@ -1185,6 +1189,7 @@
 	GENERATE_COT \
 	GICV2_G0_FOR_EL3 \
 	HANDLE_EA_EL3_FIRST_NS \
+	HARDEN_SLS \
 	HW_ASSISTED_COHERENCY \
 	MEASURED_BOOT \
 	DRTM_SUPPORT \
diff --git a/changelog.yaml b/changelog.yaml
index 1467ab4..c5e157d 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -569,6 +569,9 @@
               - rockchip/rk3399
               - rk3399/suspend
 
+          - title: RK3328
+            scope: rk3328
+
       - title: Socionext
         scope: socionext
 
diff --git a/docs/design/auth-framework.rst b/docs/design/auth-framework.rst
index 597f955..281f35f 100644
--- a/docs/design/auth-framework.rst
+++ b/docs/design/auth-framework.rst
@@ -254,8 +254,8 @@
     REGISTER_CRYPTO_LIB(_name,
                         _init,
                         _verify_signature,
-                        _calc_hash,
                         _verify_hash,
+                        _calc_hash,
                         _auth_decrypt,
                         _convert_pk);
 
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 8782f18..091456d 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -536,6 +536,14 @@
    CPU. This needs to be enabled for revisions r0p0, r0p1 and r0p2. It is still
    open.
 
+-  ``ERRATA_V2_2618597``: This applies errata 2618597 workaround to Neoverse-V2
+   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in
+   r0p2.
+
+-  ``ERRATA_V2_2662553``: This applies errata 2662553 workaround to Neoverse-V2
+   CPU. This needs to be enabled for revisions r0p0 and r0p1. It is fixed in
+   r0p2.
+
 -  ``ERRATA_V2_2719103``: This applies errata 2719103 workaround to Neoverse-V2
    CPU, this affects system configurations that do not use and ARM interconnect
    IP. This needs to be enabled for revisions r0p0 and r0p1. It has been fixed
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 599aed9..7ca0300 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -671,6 +671,19 @@
 
       MARCH_DIRECTIVE := -march=armv8.5-a
 
+-  ``HARDEN_SLS``: used to pass -mharden-sls=all from the TF-A build
+   options to the compiler currently supporting only of the options.
+   GCC documentation:
+   https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html#index-mharden-sls
+
+   An example usage:
+
+   .. code:: make
+
+      HARDEN_SLS := 1
+
+   This option defaults to 0.
+
 -  ``NON_TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It
    specifies a file that contains the Non-Trusted World private key in PEM
    format or a PKCS11 URI. If ``SAVE_KEYS=1``, only a file is accepted and it
diff --git a/include/lib/cpus/aarch64/neoverse_v2.h b/include/lib/cpus/aarch64/neoverse_v2.h
index 68c1558..39a6607 100644
--- a/include/lib/cpus/aarch64/neoverse_v2.h
+++ b/include/lib/cpus/aarch64/neoverse_v2.h
@@ -22,6 +22,10 @@
  ******************************************************************************/
 #define NEOVERSE_V2_CPUPWRCTLR_EL1			S3_0_C15_C2_7
 #define NEOVERSE_V2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT	U(1)
+#define NEOVERSE_V2_CPUPWRCTLR_EL1_WFI_RET_CTRL_SHIFT	U(4)
+#define NEOVERSE_V2_CPUPWRCTLR_EL1_WFI_RET_CTRL_WIDTH	U(3)
+#define NEOVERSE_V2_CPUPWRCTLR_EL1_WFE_RET_CTRL_SHIFT	U(7)
+#define NEOVERSE_V2_CPUPWRCTLR_EL1_WFE_RET_CTRL_WIDTH	U(3)
 
 /*******************************************************************************
  * CPU Extended Control register 2 specific definitions.
@@ -30,6 +34,9 @@
 #define NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_CNSRV		ULL(9)
 #define NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_LSB		U(11)
 #define NEOVERSE_V2_CPUECTLR2_EL1_PF_MODE_WIDTH		U(4)
+#define NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_STATIC_FULL	ULL(0)
+#define NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_LSB		U(0)
+#define NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_WIDTH		U(3)
 
 /*******************************************************************************
  * CPU Auxiliary Control register 2 specific definitions.
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
index de56638..c3a3a7c 100644
--- a/include/services/ffa_svc.h
+++ b/include/services/ffa_svc.h
@@ -117,6 +117,8 @@
 #define FFA_FNUM_SPM_ID_GET			U(0x85)
 #define FFA_FNUM_MSG_SEND2			U(0x86)
 #define FFA_FNUM_SECONDARY_EP_REGISTER		U(0x87)
+#define FFA_FNUM_MEM_PERM_GET			U(0x88)
+#define FFA_FNUM_MEM_PERM_SET			U(0x89)
 #define FFA_FNUM_PARTITION_INFO_GET_REGS	U(0x8B)
 #define FFA_FNUM_EL3_INTR_HANDLE		U(0x8C)
 
@@ -165,6 +167,8 @@
 #define FFA_SPM_ID_GET		FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET)
 #define FFA_NORMAL_WORLD_RESUME	FFA_FID(SMC_32, FFA_FNUM_NORMAL_WORLD_RESUME)
 #define FFA_EL3_INTR_HANDLE	FFA_FID(SMC_32, FFA_FNUM_EL3_INTR_HANDLE)
+#define FFA_MEM_PERM_GET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_GET)
+#define FFA_MEM_PERM_SET	FFA_FID(SMC_32, FFA_FNUM_MEM_PERM_SET)
 
 /* FFA SMC64 FIDs */
 #define FFA_ERROR_SMC64		FFA_FID(SMC_64, FFA_FNUM_ERROR)
diff --git a/lib/cpus/aarch64/neoverse_v2.S b/lib/cpus/aarch64/neoverse_v2.S
index bfd088d..d4b3a96 100644
--- a/lib/cpus/aarch64/neoverse_v2.S
+++ b/lib/cpus/aarch64/neoverse_v2.S
@@ -29,6 +29,25 @@
 
 check_erratum_ls neoverse_v2, ERRATUM(2331132), CPU_REV(0, 2)
 
+workaround_reset_start neoverse_v2, ERRATUM(2618597), ERRATA_V2_2618597
+        /* Disable retention control for WFI and WFE. */
+        mrs     x0, NEOVERSE_V2_CPUPWRCTLR_EL1
+        bfi     x0, xzr, #NEOVERSE_V2_CPUPWRCTLR_EL1_WFI_RET_CTRL_SHIFT, \
+		#NEOVERSE_V2_CPUPWRCTLR_EL1_WFI_RET_CTRL_WIDTH
+        bfi     x0, xzr, #NEOVERSE_V2_CPUPWRCTLR_EL1_WFE_RET_CTRL_SHIFT, \
+		#NEOVERSE_V2_CPUPWRCTLR_EL1_WFE_RET_CTRL_WIDTH
+        msr     NEOVERSE_V2_CPUPWRCTLR_EL1, x0
+workaround_reset_end neoverse_v2, ERRATUM(2618597)
+
+check_erratum_ls neoverse_v2, ERRATUM(2618597), CPU_REV(0, 1)
+
+workaround_reset_start neoverse_v2, ERRATUM(2662553), ERRATA_V2_2662553
+	sysreg_bitfield_insert NEOVERSE_V2_CPUECTLR2_EL1, NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_STATIC_FULL, \
+		NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_LSB, NEOVERSE_V2_CPUECTLR2_EL1_TXREQ_WIDTH
+workaround_reset_end neoverse_v2, ERRATUM(2662553)
+
+check_erratum_ls neoverse_v2, ERRATUM(2662553), CPU_REV(0, 1)
+
 workaround_reset_start neoverse_v2, ERRATUM(2719105), ERRATA_V2_2719105
 	sysreg_bit_set NEOVERSE_V2_CPUACTLR2_EL1, NEOVERSE_V2_CPUACTLR2_EL1_BIT_0
 workaround_reset_end neoverse_v2, ERRATUM(2719105)
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 3901d17..bbf44b4 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -838,6 +838,14 @@
 # to revisions r0p0, r0p1 and r0p2. It is still open.
 CPU_FLAG_LIST += ERRATA_V2_2331132
 
+# Flag to apply erratum 2618597 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_V2_2618597
+
+# Flag to apply erratum 2662553 workaround during reset. This erratum applies
+# to revisions r0p0 and r0p1. It is fixed in r0p2.
+CPU_FLAG_LIST += ERRATA_V2_2662553
+
 # Flag to apply erratum 2719103 workaround for non-arm interconnect ip. This
 # erratum applies to revisions r0p0, rop1. Fixed in r0p2.
 CPU_FLAG_LIST += ERRATA_V2_2719103
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 3ff0aaf..8829fcb 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -150,6 +150,10 @@
 # Enable Handoff protocol using transfer lists
 TRANSFER_LIST			:= 0
 
+# Enables support for the gcc compiler option "-mharden-sls=all".
+# By default, disables all SLS hardening.
+HARDEN_SLS			:= 0
+
 # Secure hash algorithm flag, accepts 3 values: sha256, sha384 and sha512.
 # The default value is sha256.
 HASH_ALG			:= sha256
diff --git a/plat/arm/board/rdn1edge/platform.mk b/plat/arm/board/rdn1edge/platform.mk
index 95753aa..d8d1293 100644
--- a/plat/arm/board/rdn1edge/platform.mk
+++ b/plat/arm/board/rdn1edge/platform.mk
@@ -73,3 +73,6 @@
 endif
 
 override CTX_INCLUDE_AARCH32_REGS	:= 0
+
+# Enable the flag since RD-N1-EDGE has a system level cache
+NEOVERSE_Nx_EXTERNAL_LLC		:=	1
diff --git a/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts b/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
index 9c9cefe..d992eac 100644
--- a/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
+++ b/plat/arm/board/rdn2/fdts/rdn2_fw_config.dts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2023, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,6 +18,12 @@
 			id = <TB_FW_CONFIG_ID>;
 		};
 
+		tos_fw-config {
+			load-address = <0x0 0x04001500>;
+			max-size = <0x1000>;
+			id = <TOS_FW_CONFIG_ID>;
+		};
+
 		nt_fw-config {
 			load-address = <0x0 0xFEF00000>;
 			max-size = <0x0100000>;
diff --git a/plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts b/plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
new file mode 100644
index 0000000..2cf3f75
--- /dev/null
+++ b/plat/arm/board/rdn2/fdts/rdn2_stmm_sel0_manifest.dts
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+#include <platform_def.h>
+
+/ {
+#define MODE_SEL0		(0x1)
+
+#define SECURE_RO		0x1
+#define SECURE_RW		0x3
+#define SECURE_EXECUTE_RO 	0x5
+#define SECURE_EXECUTE_RW 	0x7
+#define NON_SECURE_RO 		0x9
+#define NON_SECURE_RW 		0xB
+#define NON_SECURE_EXECUTE_RO 	0xD
+#define NON_SECURE_EXECUTE_RW 	0xF
+	/*
+	 * FF-A compatible Secure Partition Manager parses the
+	 * manifest file and fetch the following booting arguments to
+	 * pass on to the StandAloneMM(StMM) Secure Partition.
+	 */
+	compatible = "arm,ffa-manifest-1.0";
+
+	description = "RDN2 StMM";
+	ffa-version = <0x00010001>; /* 31:16 - Major, 15:0 - Minor */
+	uuid = <0x378daedc 0xf06b4446 0x831440ab 0x933c87a3>;
+	id = <0x8001>;
+	execution-ctx-count = <1>;
+	exception-level = <MODE_SEL0>; /* S-EL0 */
+	execution-state = <0>; /* AArch64 */
+	load-address = <0x0 0xFF200000>;
+	image-size = <0x0 0x280000>;
+	xlat-granule = <0>; /* 4KiB */
+	boot-order = <0>;
+	messaging-method = <0x3>; /* Direct request/response supported. */
+	power-management-messages = <0x1>;
+	gp-register-num = <0>;
+
+	device-regions {
+		compatible = "arm,ffa-manifest-device-regions";
+
+		/*
+		 * System registers region for access from S-EL0.
+		 * Similar to PLAT_ARM_SECURE_MAP_SYSTEMREG.
+		 */
+		sys-regs {
+			base-address = <0x0 0x0C010000>;
+			pages-count = <0x10>;
+			attributes = <SECURE_RW>;
+		};
+
+		rtc {
+			base-address = <0x0 0x0C170000>;
+			pages-count = <0x1>;
+			attributes = <SECURE_RW>;
+		};
+
+		/*
+		 * ARM CSS SoC Expansion Peripherals.
+		 */
+		soc_components {
+			base-address = <0x0 0x0E000000>;
+			pages-count = <0x2000>;
+			attributes = <SECURE_RW>;
+		};
+
+		cluster_utility {
+			base-address = <0x0 0x20000000>;
+			pages-count = <0x20000>;
+			attributes = <SECURE_RW>;
+		};
+
+		secure_uart {
+			base-address = <0x0 0x2A410000>;
+			pages-count = <0x10>;
+			attributes = <SECURE_RW>;
+		};
+
+		/*
+		 * Used for Secure booting.
+		 */
+		nor_flash2 {
+			base-address = <0x10 0x54000000>;
+			pages-count = <0x4000>;
+			attributes = <SECURE_RW>;
+		};
+	};
+
+	memory-regions {
+		compatible = "arm,ffa-manifest-memory-regions";
+
+		/*
+		 * SPM Payload memory. Mapped as code region for S-EL0
+		 * Similar to ARM_SP_IMAGE_MMAP macro used for defining base of
+		 * the SP image.
+		 */
+		stmm_region {
+			base-address = <0x0 0xff200000>;
+			pages-count = <0x300>;
+			/* StMM will remap the regions during runtime. */
+			attributes = <SECURE_EXECUTE_RO>;
+		};
+
+		/*
+		 * Memory shared between EL3 SPMC and S-EL0.
+		 */
+		rx-tx-buffers {
+			description = "shared-buff";
+			base-address = <0x0 0xff500000>;
+			pages-count = <0x100>;
+			attributes = <SECURE_RW>;
+		};
+
+		/*
+		 * Memory shared between Normal world and S-EL0.
+		 */
+		ns_comm_buffer {
+			/*
+			 * Description is needed for StMM to identify
+			 * ns-communication buffer.
+			 */
+			description = "ns-comm";
+			base-address = <0x0 0xff600000>;
+			pages-count = <0x30>;
+			attributes = <NON_SECURE_RW>;
+		};
+
+		/*
+		 * Heap used by SP to allocate memory for DMA.
+		 */
+		heap {
+			/*
+			 * Description is needed for StMM to identify
+			 * heap buffer.
+			 */
+			description = "heap";
+			base-address = <0x0 0xFF630000>;
+			pages-count = <0x5D0>;
+			attributes = <SECURE_RW>;
+		};
+	};
+};
diff --git a/plat/arm/board/rdn2/platform.mk b/plat/arm/board/rdn2/platform.mk
index ef8f3d4..beaddef 100644
--- a/plat/arm/board/rdn2/platform.mk
+++ b/plat/arm/board/rdn2/platform.mk
@@ -93,5 +93,15 @@
 # Add the NT_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config))
 
+STMM_CONFIG_DTS		:=	${RDN2_BASE}/fdts/${PLAT}_stmm_sel0_manifest.dts
+FDT_SOURCES		+=	${STMM_CONFIG_DTS}
+TOS_FW_CONFIG		:=	${BUILD_PLAT}/fdts/$(notdir $(basename ${STMM_CONFIG_DTS})).dtb
+
+# Add the TOS_FW_CONFIG to FIP and specify the same to certtool
+$(eval $(call TOOL_ADD_PAYLOAD,${TOS_FW_CONFIG},--tos-fw-config,${TOS_FW_CONFIG}))
+
 override CTX_INCLUDE_AARCH32_REGS	:= 0
 override ENABLE_FEAT_AMU		:= 1
+
+# Enable the flag since RD-N2 has a system level cache
+NEOVERSE_Nx_EXTERNAL_LLC		:=	1
diff --git a/plat/arm/board/rdv1/platform.mk b/plat/arm/board/rdv1/platform.mk
index a5fba67..0b059b5 100644
--- a/plat/arm/board/rdv1/platform.mk
+++ b/plat/arm/board/rdv1/platform.mk
@@ -63,3 +63,6 @@
  $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1 should always be 0, \
      currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
 endif
+
+# Enable the flag since RD-V1 has a system level cache
+NEOVERSE_Nx_EXTERNAL_LLC		:=	1
diff --git a/plat/arm/board/rdv1mc/platform.mk b/plat/arm/board/rdv1mc/platform.mk
index 92f7c10..176e0ef 100644
--- a/plat/arm/board/rdv1mc/platform.mk
+++ b/plat/arm/board/rdv1mc/platform.mk
@@ -74,3 +74,6 @@
  $(error "CSS_SGI_PLATFORM_VARIANT for RD-V1-MC should always be 0, \
      currently set to ${CSS_SGI_PLATFORM_VARIANT}.")
 endif
+
+# Enable the flag since RD-V1-MC has a system level cache
+NEOVERSE_Nx_EXTERNAL_LLC		:=	1
diff --git a/plat/rockchip/rk3328/platform.mk b/plat/rockchip/rk3328/platform.mk
index 5b4766d..f96e18b 100644
--- a/plat/rockchip/rk3328/platform.mk
+++ b/plat/rockchip/rk3328/platform.mk
@@ -65,6 +65,7 @@
 
 # Enable workarounds for selected Cortex-A53 errata
 ERRATA_A53_855873	:=	1
+ERRATA_A53_1530924	:=      1
 
 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
 $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
diff --git a/services/std_svc/errata_abi/errata_abi_main.c b/services/std_svc/errata_abi/errata_abi_main.c
index cf2e653..13d8361 100644
--- a/services/std_svc/errata_abi/errata_abi_main.c
+++ b/services/std_svc/errata_abi/errata_abi_main.c
@@ -415,13 +415,15 @@
 	.cpu_partnumber = NEOVERSE_V2_MIDR,
 	.cpu_errata_list = {
 		[0] = {2331132, 0x00, 0x02, ERRATA_V2_2331132},
-		[1] = {2719103, 0x00, 0x01, ERRATA_V2_2719103, \
+		[1] = {2618597, 0x00, 0x01, ERRATA_V2_2618597},
+		[2] = {2662553, 0x00, 0x01, ERRATA_V2_2662553},
+		[3] = {2719103, 0x00, 0x01, ERRATA_V2_2719103, \
 			ERRATA_NON_ARM_INTERCONNECT},
-		[2] = {2719105, 0x00, 0x01, ERRATA_V2_2719105},
-		[3] = {2743011, 0x00, 0x01, ERRATA_V2_2743011},
-		[4] = {2779510, 0x00, 0x01, ERRATA_V2_2779510},
-		[5] = {2801372, 0x00, 0x01, ERRATA_V2_2801372},
-		[6 ... ERRATA_LIST_END] = UNDEF_ERRATA,
+		[4] = {2719105, 0x00, 0x01, ERRATA_V2_2719105},
+		[5] = {2743011, 0x00, 0x01, ERRATA_V2_2743011},
+		[6] = {2779510, 0x00, 0x01, ERRATA_V2_2779510},
+		[7] = {2801372, 0x00, 0x01, ERRATA_V2_2801372},
+		[8 ... ERRATA_LIST_END] = UNDEF_ERRATA,
 	}
 },
 #endif /* NEOVERSE_V2_H_INC */
diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h
index 48644ac..e093a82 100644
--- a/services/std_svc/spm/el3_spmc/spmc.h
+++ b/services/std_svc/spm/el3_spmc/spmc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -168,6 +168,12 @@
 	/* Mailbox tracking. */
 	struct mailbox mailbox;
 
+	/* Lock to protect the runtime state of a S-EL0 SP execution context. */
+	spinlock_t rt_state_lock;
+
+	/* Pointer to translation table context of a S-EL0 SP. */
+	xlat_ctx_t *xlat_ctx_handle;
+
 	/* Secondary entrypoint. Only valid for a S-EL1 SP. */
 	uintptr_t secondary_ep;
 
@@ -224,6 +230,10 @@
 		       entry_point_info_t *ep_info);
 void spmc_sp_common_ep_commit(struct secure_partition_desc *sp,
 			      entry_point_info_t *ep_info);
+void spmc_el0_sp_spsr_setup(entry_point_info_t *ep_info);
+void spmc_el0_sp_setup(struct secure_partition_desc *sp,
+		       int32_t boot_info_reg,
+		       void *sp_manifest);
 
 /*
  * Helper function to perform a synchronous entry into a SP.
diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c
index ada6f45..42747bf 100644
--- a/services/std_svc/spm/el3_spmc/spmc_main.c
+++ b/services/std_svc/spm/el3_spmc/spmc_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -30,6 +30,17 @@
 
 #include <platform_def.h>
 
+/* FFA_MEM_PERM_* helpers */
+#define FFA_MEM_PERM_MASK		U(7)
+#define FFA_MEM_PERM_DATA_MASK		U(3)
+#define FFA_MEM_PERM_DATA_SHIFT		U(0)
+#define FFA_MEM_PERM_DATA_NA		U(0)
+#define FFA_MEM_PERM_DATA_RW		U(1)
+#define FFA_MEM_PERM_DATA_RES		U(2)
+#define FFA_MEM_PERM_DATA_RO		U(3)
+#define FFA_MEM_PERM_INST_EXEC          (U(0) << 2)
+#define FFA_MEM_PERM_INST_NON_EXEC      (U(1) << 2)
+
 /* Declare the maximum number of SPs and El3 LPs. */
 #define MAX_SP_LP_PARTITIONS SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT
 
@@ -390,6 +401,11 @@
 					     FFA_ERROR_INVALID_PARAMETER);
 	}
 
+	/* Protect the runtime state of a UP S-EL0 SP with a lock. */
+	if (sp->runtime_el == S_EL0) {
+		spin_lock(&sp->rt_state_lock);
+	}
+
 	/*
 	 * Check that the target execution context is in a waiting state before
 	 * forwarding the direct request to it.
@@ -398,6 +414,11 @@
 	if (sp->ec[idx].rt_state != RT_STATE_WAITING) {
 		VERBOSE("SP context on core%u is not waiting (%u).\n",
 			idx, sp->ec[idx].rt_model);
+
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
+
 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
 	}
 
@@ -408,6 +429,11 @@
 	sp->ec[idx].rt_state = RT_STATE_RUNNING;
 	sp->ec[idx].rt_model = RT_MODEL_DIR_REQ;
 	sp->ec[idx].dir_req_origin_id = src_id;
+
+	if (sp->runtime_el == S_EL0) {
+		spin_unlock(&sp->rt_state_lock);
+	}
+
 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
 			       handle, cookie, flags, dst_id);
 }
@@ -462,6 +488,10 @@
 					     FFA_ERROR_INVALID_PARAMETER);
 	}
 
+	if (sp->runtime_el == S_EL0) {
+		spin_lock(&sp->rt_state_lock);
+	}
+
 	/* Sanity check state is being tracked correctly in the SPMC. */
 	idx = get_ec_index(sp);
 	assert(sp->ec[idx].rt_state == RT_STATE_RUNNING);
@@ -470,12 +500,18 @@
 	if (sp->ec[idx].rt_model != RT_MODEL_DIR_REQ) {
 		VERBOSE("SP context on core%u not handling direct req (%u).\n",
 			idx, sp->ec[idx].rt_model);
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
 	}
 
 	if (sp->ec[idx].dir_req_origin_id != dst_id) {
 		WARN("Invalid direct resp partition ID 0x%x != 0x%x on core%u.\n",
 		     dst_id, sp->ec[idx].dir_req_origin_id, idx);
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
 	}
 
@@ -485,6 +521,10 @@
 	/* Clear the ongoing direct request ID. */
 	sp->ec[idx].dir_req_origin_id = INV_SP_ID;
 
+	if (sp->runtime_el == S_EL0) {
+		spin_unlock(&sp->rt_state_lock);
+	}
+
 	/*
 	 * If the receiver is not the SPMC then forward the response to the
 	 * Normal world.
@@ -536,9 +576,15 @@
 	 * Get the execution context of the SP that invoked FFA_MSG_WAIT.
 	 */
 	idx = get_ec_index(sp);
+	if (sp->runtime_el == S_EL0) {
+		spin_lock(&sp->rt_state_lock);
+	}
 
 	/* Ensure SP execution context was in the right runtime model. */
 	if (sp->ec[idx].rt_model == RT_MODEL_DIR_REQ) {
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
 		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
 	}
 
@@ -550,6 +596,9 @@
 	 * state is updated after the exit.
 	 */
 	if (sp->ec[idx].rt_model == RT_MODEL_INIT) {
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
 		spmc_sp_synchronous_exit(&sp->ec[idx], x4);
 		/* Should not get here */
 		panic();
@@ -567,9 +616,19 @@
 		cm_el1_sysregs_context_save(secure_state_in);
 		cm_el1_sysregs_context_restore(secure_state_out);
 		cm_set_next_eret_context(secure_state_out);
+
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
+
 		SMC_RET0(cm_get_context(secure_state_out));
 	}
 
+	/* Protect the runtime state of a S-EL0 SP with a lock. */
+	if (sp->runtime_el == S_EL0) {
+		spin_unlock(&sp->rt_state_lock);
+	}
+
 	/* Forward the response to the Normal world. */
 	return spmc_smc_return(smc_fid, secure_origin, x1, x2, x3, x4,
 			       handle, cookie, flags, FFA_NWD_ID);
@@ -1343,14 +1402,21 @@
 	}
 
 	idx = get_ec_index(sp);
+
 	if (idx != vcpu_id) {
 		ERROR("Cannot run vcpu %d != %d.\n", idx, vcpu_id);
 		return spmc_ffa_error_return(handle,
 					     FFA_ERROR_INVALID_PARAMETER);
 	}
+	if (sp->runtime_el == S_EL0) {
+		spin_lock(&sp->rt_state_lock);
+	}
 	rt_state = &((sp->ec[idx]).rt_state);
 	rt_model = &((sp->ec[idx]).rt_model);
 	if (*rt_state == RT_STATE_RUNNING) {
+		if (sp->runtime_el == S_EL0) {
+			spin_unlock(&sp->rt_state_lock);
+		}
 		ERROR("Partition (0x%x) is already running.\n", target_id);
 		return spmc_ffa_error_return(handle, FFA_ERROR_BUSY);
 	}
@@ -1377,6 +1443,10 @@
 	 */
 	*rt_state = RT_STATE_RUNNING;
 
+	if (sp->runtime_el == S_EL0) {
+		spin_unlock(&sp->rt_state_lock);
+	}
+
 	return spmc_smc_return(smc_fid, secure_origin, x1, 0, 0, 0,
 			       handle, cookie, flags, target_id);
 }
@@ -1505,6 +1575,223 @@
 }
 
 /*******************************************************************************
+ * Permissions are encoded using a different format in the FFA_MEM_PERM_* ABIs
+ * than in the Trusted Firmware, where the mmap_attr_t enum type is used. This
+ * function converts a permission value from the FF-A format to the mmap_attr_t
+ * format by setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and
+ * MT_EXECUTE/MT_EXECUTE_NEVER. The other fields are left as 0 because they are
+ * ignored by the function xlat_change_mem_attributes_ctx().
+ ******************************************************************************/
+static unsigned int ffa_perm_to_mmap_perm(unsigned int perms)
+{
+	unsigned int tf_attr = 0U;
+	unsigned int access;
+
+	/* Deal with data access permissions first. */
+	access = (perms & FFA_MEM_PERM_DATA_MASK) >> FFA_MEM_PERM_DATA_SHIFT;
+
+	switch (access) {
+	case FFA_MEM_PERM_DATA_RW:
+		/* Return 0 if the execute is set with RW. */
+		if ((perms & FFA_MEM_PERM_INST_NON_EXEC) != 0) {
+			tf_attr |= MT_RW | MT_USER | MT_EXECUTE_NEVER;
+		}
+		break;
+
+	case FFA_MEM_PERM_DATA_RO:
+		tf_attr |= MT_RO | MT_USER;
+		/* Deal with the instruction access permissions next. */
+		if ((perms & FFA_MEM_PERM_INST_NON_EXEC) == 0) {
+			tf_attr |= MT_EXECUTE;
+		} else {
+			tf_attr |= MT_EXECUTE_NEVER;
+		}
+		break;
+
+	case FFA_MEM_PERM_DATA_NA:
+	default:
+		return tf_attr;
+	}
+
+	return tf_attr;
+}
+
+/*******************************************************************************
+ * Handler to set the permissions of a set of contiguous pages of a S-EL0 SP
+ ******************************************************************************/
+static uint64_t ffa_mem_perm_set_handler(uint32_t smc_fid,
+					 bool secure_origin,
+					 uint64_t x1,
+					 uint64_t x2,
+					 uint64_t x3,
+					 uint64_t x4,
+					 void *cookie,
+					 void *handle,
+					 uint64_t flags)
+{
+	struct secure_partition_desc *sp;
+	unsigned int idx;
+	uintptr_t base_va = (uintptr_t) x1;
+	size_t size = (size_t)(x2 * PAGE_SIZE);
+	uint32_t tf_attr;
+	int ret;
+
+	/* This request cannot originate from the Normal world. */
+	if (!secure_origin) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+	}
+
+	if (size == 0) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* Get the context of the current SP. */
+	sp = spmc_get_current_sp_ctx();
+	if (sp == NULL) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* A S-EL1 SP has no business invoking this ABI. */
+	if (sp->runtime_el == S_EL1) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
+	if ((x3 & ~((uint64_t)FFA_MEM_PERM_MASK)) != 0) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* Get the execution context of the calling SP. */
+	idx = get_ec_index(sp);
+
+	/*
+	 * Ensure that the S-EL0 SP is initialising itself. We do not need to
+	 * synchronise this operation through a spinlock since a S-EL0 SP is UP
+	 * and can only be initialising on this cpu.
+	 */
+	if (sp->ec[idx].rt_model != RT_MODEL_INIT) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
+	VERBOSE("Setting memory permissions:\n");
+	VERBOSE("  Start address  : 0x%lx\n", base_va);
+	VERBOSE("  Number of pages: %lu (%zu bytes)\n", x2, size);
+	VERBOSE("  Attributes     : 0x%x\n", (uint32_t)x3);
+
+	/* Convert inbound permissions to TF-A permission attributes */
+	tf_attr = ffa_perm_to_mmap_perm((unsigned int)x3);
+	if (tf_attr == 0U) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* Request the change in permissions */
+	ret = xlat_change_mem_attributes_ctx(sp->xlat_ctx_handle,
+					     base_va, size, tf_attr);
+	if (ret != 0) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	SMC_RET1(handle, FFA_SUCCESS_SMC32);
+}
+
+/*******************************************************************************
+ * Permissions are encoded using a different format in the FFA_MEM_PERM_* ABIs
+ * than in the Trusted Firmware, where the mmap_attr_t enum type is used. This
+ * function converts a permission value from the mmap_attr_t format to the FF-A
+ * format.
+ ******************************************************************************/
+static unsigned int mmap_perm_to_ffa_perm(unsigned int attr)
+{
+	unsigned int perms = 0U;
+	unsigned int data_access;
+
+	if ((attr & MT_USER) == 0) {
+		/* No access from EL0. */
+		data_access = FFA_MEM_PERM_DATA_NA;
+	} else {
+		if ((attr & MT_RW) != 0) {
+			data_access = FFA_MEM_PERM_DATA_RW;
+		} else {
+			data_access = FFA_MEM_PERM_DATA_RO;
+		}
+	}
+
+	perms |= (data_access & FFA_MEM_PERM_DATA_MASK)
+		<< FFA_MEM_PERM_DATA_SHIFT;
+
+	if ((attr & MT_EXECUTE_NEVER) != 0U) {
+		perms |= FFA_MEM_PERM_INST_NON_EXEC;
+	}
+
+	return perms;
+}
+
+/*******************************************************************************
+ * Handler to get the permissions of a set of contiguous pages of a S-EL0 SP
+ ******************************************************************************/
+static uint64_t ffa_mem_perm_get_handler(uint32_t smc_fid,
+					 bool secure_origin,
+					 uint64_t x1,
+					 uint64_t x2,
+					 uint64_t x3,
+					 uint64_t x4,
+					 void *cookie,
+					 void *handle,
+					 uint64_t flags)
+{
+	struct secure_partition_desc *sp;
+	unsigned int idx;
+	uintptr_t base_va = (uintptr_t)x1;
+	uint32_t tf_attr = 0;
+	int ret;
+
+	/* This request cannot originate from the Normal world. */
+	if (!secure_origin) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED);
+	}
+
+	/* Get the context of the current SP. */
+	sp = spmc_get_current_sp_ctx();
+	if (sp == NULL) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* A S-EL1 SP has no business invoking this ABI. */
+	if (sp->runtime_el == S_EL1) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
+	/* Get the execution context of the calling SP. */
+	idx = get_ec_index(sp);
+
+	/*
+	 * Ensure that the S-EL0 SP is initialising itself. We do not need to
+	 * synchronise this operation through a spinlock since a S-EL0 SP is UP
+	 * and can only be initialising on this cpu.
+	 */
+	if (sp->ec[idx].rt_model != RT_MODEL_INIT) {
+		return spmc_ffa_error_return(handle, FFA_ERROR_DENIED);
+	}
+
+	/* Request the permissions */
+	ret = xlat_get_mem_attributes_ctx(sp->xlat_ctx_handle, base_va, &tf_attr);
+	if (ret != 0) {
+		return spmc_ffa_error_return(handle,
+					     FFA_ERROR_INVALID_PARAMETER);
+	}
+
+	/* Convert TF-A permission to FF-A permissions attributes. */
+	x2 = mmap_perm_to_ffa_perm(tf_attr);
+
+	SMC_RET3(handle, FFA_SUCCESS_SMC32, 0, x2);
+}
+
+/*******************************************************************************
  * This function will parse the Secure Partition Manifest. From manifest, it
  * will fetch details for preparing Secure partition image context and secure
  * partition image boot arguments if any.
@@ -1588,7 +1875,7 @@
 	 * since this is currently a hardcoded value for S-EL1 partitions
 	 * we don't need to save it here, just validate.
 	 */
-	if (config_32 != PLATFORM_CORE_COUNT) {
+	if ((sp->runtime_el == S_EL1) && (config_32 != PLATFORM_CORE_COUNT)) {
 		ERROR("SP Execution Context Count (%u) must be %u.\n",
 			config_32, PLATFORM_CORE_COUNT);
 		return -EINVAL;
@@ -1704,7 +1991,8 @@
 	 * the manifest as boot information later.
 	 */
 	next_image_ep_info->args.arg1 = fdt_totalsize(sp_manifest);
-	INFO("Manifest size = %lu bytes.\n", next_image_ep_info->args.arg1);
+	INFO("Manifest adr = %lx , size = %lu bytes\n", manifest_base,
+	     next_image_ep_info->args.arg1);
 
 	/*
 	 * Select an SP descriptor for initialising the partition's execution
@@ -1712,6 +2000,11 @@
 	 */
 	sp = spmc_get_current_sp_ctx();
 
+#if SPMC_AT_EL3_SEL0_SP
+	/* Assign translation tables context. */
+	sp_desc->xlat_ctx_handle = spm_get_sp_xlat_context();
+
+#endif /* SPMC_AT_EL3_SEL0_SP */
 	/* Initialize entry point information for the SP */
 	SET_PARAM_HEAD(next_image_ep_info, PARAM_EP, VERSION_1,
 		       SECURE | EP_ST_ENABLE);
@@ -1725,7 +2018,7 @@
 	}
 
 	/* Check that the runtime EL in the manifest was correct. */
-	if (sp->runtime_el != S_EL1) {
+	if (sp->runtime_el != S_EL0 && sp->runtime_el != S_EL1) {
 		ERROR("Unexpected runtime EL: %d\n", sp->runtime_el);
 		return -EINVAL;
 	}
@@ -1734,11 +2027,29 @@
 	spmc_sp_common_setup(sp, next_image_ep_info, boot_info_reg);
 
 	/* Perform any initialisation specific to S-EL1 SPs. */
-	spmc_el1_sp_setup(sp, next_image_ep_info);
+	if (sp->runtime_el == S_EL1) {
+		spmc_el1_sp_setup(sp, next_image_ep_info);
+	}
+
+#if SPMC_AT_EL3_SEL0_SP
+	/* Setup spsr in endpoint info for common context management routine. */
+	if (sp->runtime_el == S_EL0) {
+		spmc_el0_sp_spsr_setup(next_image_ep_info);
+	}
+#endif /* SPMC_AT_EL3_SEL0_SP */
 
 	/* Initialize the SP context with the required ep info. */
 	spmc_sp_common_ep_commit(sp, next_image_ep_info);
 
+#if SPMC_AT_EL3_SEL0_SP
+	/*
+	 * Perform any initialisation specific to S-EL0 not set by common
+	 * context management routine.
+	 */
+	if (sp->runtime_el == S_EL0) {
+		spmc_el0_sp_setup(sp, boot_info_reg, sp_manifest);
+	}
+#endif /* SPMC_AT_EL3_SEL0_SP */
 	return 0;
 }
 
@@ -2051,6 +2362,14 @@
 		return spmc_ffa_mem_reclaim(smc_fid, secure_origin, x1, x2, x3,
 					    x4, cookie, handle, flags);
 
+	case FFA_MEM_PERM_GET:
+		return ffa_mem_perm_get_handler(smc_fid, secure_origin, x1, x2,
+						x3, x4, cookie, handle, flags);
+
+	case FFA_MEM_PERM_SET:
+		return ffa_mem_perm_set_handler(smc_fid, secure_origin, x1, x2,
+						x3, x4, cookie, handle, flags);
+
 	default:
 		WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
 		break;
diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c
index 6de25f6..609d968 100644
--- a/services/std_svc/spm/el3_spmc/spmc_setup.c
+++ b/services/std_svc/spm/el3_spmc/spmc_setup.c
@@ -20,6 +20,7 @@
 #include <plat/common/platform.h>
 #include <services/ffa_svc.h>
 #include "spm_common.h"
+#include "spm_shim_private.h"
 #include "spmc.h"
 #include <tools_share/firmware_image_package.h>
 
@@ -31,6 +32,26 @@
 static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE);
 
 /*
+ * We need to choose one execution context from all those available for a S-EL0
+ * SP. This execution context will be used subsequently irrespective of which
+ * physical CPU the SP runs on.
+ */
+#define SEL0_SP_EC_INDEX 0
+#define SP_MEM_READ 0x1
+#define SP_MEM_WRITE 0x2
+#define SP_MEM_EXECUTE 0x4
+#define SP_MEM_NON_SECURE 0x8
+#define SP_MEM_READ_ONLY SP_MEM_READ
+#define SP_MEM_READ_WRITE (SP_MEM_READ | SP_MEM_WRITE)
+
+/* Type of the memory region in SP's manifest. */
+enum sp_memory_region_type {
+	SP_MEM_REGION_DEVICE,
+	SP_MEM_REGION_MEMORY,
+	SP_MEM_REGION_NOT_SPECIFIED
+};
+
+/*
  * This function creates a initialization descriptor in the memory reserved
  * for passing boot information to an SP. It then copies the partition manifest
  * into this region and ensures that its reference in the initialization
@@ -143,14 +164,310 @@
 }
 
 /*
- * We are assuming that the index of the execution
- * context used is the linear index of the current physical cpu.
+ * S-EL1 partitions can be assigned with multiple execution contexts, each
+ * pinned to the physical CPU. Each execution context index corresponds to the
+ * respective liner core position.
+ * S-EL0 partitions execute in a single execution context (index 0).
  */
 unsigned int get_ec_index(struct secure_partition_desc *sp)
 {
+	return (sp->runtime_el == S_EL0) ?
+		SEL0_SP_EC_INDEX : plat_my_core_pos();
+}
+
+#if SPMC_AT_EL3_SEL0_SP
+/* Setup spsr in entry point info for common context management code to use. */
+void spmc_el0_sp_spsr_setup(entry_point_info_t *ep_info)
+{
+	/* Setup Secure Partition SPSR for S-EL0 SP. */
+	ep_info->spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS);
+}
+
+static void read_optional_string(void *manifest, int32_t offset,
+				 char *property, char *out, size_t len)
+{
-	return plat_my_core_pos();
+	const fdt32_t *prop;
+	int lenp;
+
+	prop = fdt_getprop(manifest, offset, property, &lenp);
+	if (prop == NULL) {
+		out[0] = '\0';
+	} else {
+		memcpy(out, prop, MIN(lenp, (int)len));
+	}
+}
+
+/*******************************************************************************
+ * This function will parse the Secure Partition Manifest for fetching secure
+ * partition specific memory/device region details. It will find base address,
+ * size, memory attributes for each region and then add the respective region
+ * into secure parition's translation context.
+ ******************************************************************************/
+static void populate_sp_regions(struct secure_partition_desc *sp,
+				void *sp_manifest, int node,
+				enum sp_memory_region_type type)
+{
+	uintptr_t base_address;
+	uint32_t mem_attr, mem_region, size;
+	struct mmap_region sp_mem_regions = {0};
+	int32_t offset, ret;
+	char *compatibility[SP_MEM_REGION_NOT_SPECIFIED] = {
+		"arm,ffa-manifest-device-regions",
+		"arm,ffa-manifest-memory-regions"
+	};
+	char description[10];
+	char *property;
+	char *region[SP_MEM_REGION_NOT_SPECIFIED] = {
+		"device regions",
+		"memory regions"
+	};
+
+	if (type >= SP_MEM_REGION_NOT_SPECIFIED) {
+		WARN("Invalid region type\n");
+		return;
+	}
+
+	INFO("Mapping SP's %s\n", region[type]);
+
+	if (fdt_node_check_compatible(sp_manifest, node,
+				      compatibility[type]) != 0) {
+		WARN("Incompatible region node in manifest\n");
+		return;
+	}
+
+	for (offset = fdt_first_subnode(sp_manifest, node), mem_region = 0;
+	     offset >= 0;
+	     offset = fdt_next_subnode(sp_manifest, offset), mem_region++) {
+		read_optional_string(sp_manifest, offset, "description",
+				     description, sizeof(description));
+
+		INFO("Mapping: region: %d, %s\n", mem_region, description);
+
+		property = "base-address";
+		ret = fdt_read_uint64(sp_manifest, offset, property,
+					&base_address);
+		if (ret < 0) {
+			WARN("Missing:%s for %s.\n", property, description);
+			continue;
+		}
+
+		property = "pages-count";
+		ret = fdt_read_uint32(sp_manifest, offset, property, &size);
+		if (ret < 0) {
+			WARN("Missing: %s for %s.\n", property, description);
+			continue;
+		}
+		size *= PAGE_SIZE;
+
+		property = "attributes";
+		ret = fdt_read_uint32(sp_manifest, offset, property, &mem_attr);
+		if (ret < 0) {
+			WARN("Missing: %s for %s.\n", property, description);
+			continue;
+		}
+
+		sp_mem_regions.attr = MT_USER;
+		if (type == SP_MEM_REGION_DEVICE) {
+			sp_mem_regions.attr |= MT_EXECUTE_NEVER;
+		} else {
+			sp_mem_regions.attr |= MT_MEMORY;
+			if ((mem_attr & SP_MEM_EXECUTE) == SP_MEM_EXECUTE) {
+				sp_mem_regions.attr &= ~MT_EXECUTE_NEVER;
+			} else {
+				sp_mem_regions.attr |= MT_EXECUTE_NEVER;
+			}
+		}
+
+		if ((mem_attr & SP_MEM_READ_WRITE) == SP_MEM_READ_WRITE) {
+			sp_mem_regions.attr |= MT_RW;
+		}
+
+		if ((mem_attr & SP_MEM_NON_SECURE) == SP_MEM_NON_SECURE) {
+			sp_mem_regions.attr |= MT_NS;
+		} else {
+			sp_mem_regions.attr |= MT_SECURE;
+		}
+
+		sp_mem_regions.base_pa = base_address;
+		sp_mem_regions.base_va = base_address;
+		sp_mem_regions.size = size;
+
+		INFO("Adding PA: 0x%llx VA: 0x%lx Size: 0x%lx attr:0x%x\n",
+		     sp_mem_regions.base_pa,
+		     sp_mem_regions.base_va,
+		     sp_mem_regions.size,
+		     sp_mem_regions.attr);
+
+		if (type == SP_MEM_REGION_DEVICE) {
+			sp_mem_regions.granularity = XLAT_BLOCK_SIZE(1);
+		} else {
+			sp_mem_regions.granularity = XLAT_BLOCK_SIZE(3);
+		}
+		mmap_add_region_ctx(sp->xlat_ctx_handle, &sp_mem_regions);
+	}
 }
 
+static void spmc_el0_sp_setup_mmu(struct secure_partition_desc *sp,
+				  cpu_context_t *ctx)
+{
+	xlat_ctx_t *xlat_ctx;
+	uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
+
+	xlat_ctx = sp->xlat_ctx_handle;
+	init_xlat_tables_ctx(sp->xlat_ctx_handle);
+	setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table,
+		      xlat_ctx->pa_max_address, xlat_ctx->va_max_address,
+		      EL1_EL0_REGIME);
+
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_MAIR_EL1,
+		      mmu_cfg_params[MMU_CFG_MAIR]);
+
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TCR_EL1,
+		      mmu_cfg_params[MMU_CFG_TCR]);
+
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_TTBR0_EL1,
+		      mmu_cfg_params[MMU_CFG_TTBR0]);
+}
+
+static void spmc_el0_sp_setup_sctlr_el1(cpu_context_t *ctx)
+{
+	u_register_t sctlr_el1;
+
+	/* Setup SCTLR_EL1 */
+	sctlr_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1);
+
+	sctlr_el1 |=
+		/*SCTLR_EL1_RES1 |*/
+		/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
+		SCTLR_UCI_BIT |
+		/* RW regions at xlat regime EL1&0 are forced to be XN. */
+		SCTLR_WXN_BIT |
+		/* Don't trap to EL1 execution of WFI or WFE at EL0. */
+		SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
+		/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
+		SCTLR_UCT_BIT |
+		/* Don't trap to EL1 execution of DZ ZVA at EL0. */
+		SCTLR_DZE_BIT |
+		/* Enable SP Alignment check for EL0 */
+		SCTLR_SA0_BIT |
+		/* Don't change PSTATE.PAN on taking an exception to EL1 */
+		SCTLR_SPAN_BIT |
+		/* Allow cacheable data and instr. accesses to normal memory. */
+		SCTLR_C_BIT | SCTLR_I_BIT |
+		/* Enable MMU. */
+		SCTLR_M_BIT;
+
+	sctlr_el1 &= ~(
+		/* Explicit data accesses at EL0 are little-endian. */
+		SCTLR_E0E_BIT |
+		/*
+		 * Alignment fault checking disabled when at EL1 and EL0 as
+		 * the UEFI spec permits unaligned accesses.
+		 */
+		SCTLR_A_BIT |
+		/* Accesses to DAIF from EL0 are trapped to EL1. */
+		SCTLR_UMA_BIT
+	);
+
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1);
+}
+
+static void spmc_el0_sp_setup_system_registers(struct secure_partition_desc *sp,
+					       cpu_context_t *ctx)
+{
+
+	spmc_el0_sp_setup_mmu(sp, ctx);
+
+	spmc_el0_sp_setup_sctlr_el1(ctx);
+
+	/* Setup other system registers. */
+
+	/* Shim Exception Vector Base Address */
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_VBAR_EL1,
+			SPM_SHIM_EXCEPTIONS_PTR);
+#if NS_TIMER_SWITCH
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CNTKCTL_EL1,
+		      EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT);
+#endif
+
+	/*
+	 * FPEN: Allow the Secure Partition to access FP/SIMD registers.
+	 * Note that SPM will not do any saving/restoring of these registers on
+	 * behalf of the SP. This falls under the SP's responsibility.
+	 * TTA: Enable access to trace registers.
+	 * ZEN (v8.2): Trap SVE instructions and access to SVE registers.
+	 */
+	write_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_CPACR_EL1,
+			CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
+}
+
+/* Setup context of an EL0 Secure Partition.  */
+void spmc_el0_sp_setup(struct secure_partition_desc *sp,
+		       int32_t boot_info_reg,
+		       void *sp_manifest)
+{
+	mmap_region_t sel1_exception_vectors =
+		MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START,
+				SPM_SHIM_EXCEPTIONS_SIZE,
+				MT_CODE | MT_SECURE | MT_PRIVILEGED);
+	cpu_context_t *ctx;
+	int node;
+	int offset = 0;
+
+	ctx = &sp->ec[SEL0_SP_EC_INDEX].cpu_ctx;
+
+	sp->xlat_ctx_handle->xlat_regime = EL1_EL0_REGIME;
+
+	/* This region contains the exception vectors used at S-EL1. */
+	mmap_add_region_ctx(sp->xlat_ctx_handle,
+			    &sel1_exception_vectors);
+
+	/*
+	 * If the SP manifest specified the register to pass the address of the
+	 * boot information, then map the memory region to pass boot
+	 * information.
+	 */
+	if (boot_info_reg >= 0) {
+		mmap_region_t ffa_boot_info_region = MAP_REGION_FLAT(
+			(uintptr_t) ffa_boot_info_mem,
+			PAGE_SIZE,
+			MT_RO_DATA | MT_SECURE | MT_USER);
+		mmap_add_region_ctx(sp->xlat_ctx_handle, &ffa_boot_info_region);
+	}
+
+	/*
+	 * Parse the manifest for any device regions that the SP wants to be
+	 * mapped in its translation regime.
+	 */
+	node = fdt_subnode_offset_namelen(sp_manifest, offset,
+					  "device-regions",
+					  sizeof("device-regions") - 1);
+	if (node < 0) {
+		WARN("Not found device-region configuration for SP.\n");
+	} else {
+		populate_sp_regions(sp, sp_manifest, node,
+				    SP_MEM_REGION_DEVICE);
+	}
+
+	/*
+	 * Parse the manifest for any memory regions that the SP wants to be
+	 * mapped in its translation regime.
+	 */
+	node = fdt_subnode_offset_namelen(sp_manifest, offset,
+					  "memory-regions",
+					  sizeof("memory-regions") - 1);
+	if (node < 0) {
+		WARN("Not found memory-region configuration for SP.\n");
+	} else {
+		populate_sp_regions(sp, sp_manifest, node,
+				    SP_MEM_REGION_MEMORY);
+	}
+
+	spmc_el0_sp_setup_system_registers(sp, ctx);
+
+}
+#endif /* SPMC_AT_EL3_SEL0_SP */
+
 /* S-EL1 partition specific initialisation. */
 void spmc_el1_sp_setup(struct secure_partition_desc *sp,
 		       entry_point_info_t *ep_info)
@@ -211,12 +528,6 @@
 		sp->sp_id = sp_id;
 	}
 
-	/*
-	 * We currently only support S-EL1 partitions so ensure this is the
-	 * case.
-	 */
-	assert(sp->runtime_el == S_EL1);
-
 	/* Check if the SP wants to use the FF-A boot protocol. */
 	if (boot_info_reg >= 0) {
 		/*