SPM: Split S-EL1 shim from S-EL0 application

The shim prepares the S-EL1/0 environment (stack, VBAR, MMU, I-cache,
BSS clear, PIE fixup) for usage by the S-EL0 application. Split ivy
and shim parition code into separate folders.

Signed-off-by: Ruari Phipps <ruari.phipps@arm.com>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I203bbc0d379b12bd5cf1991b95e4f3a7d78d63d4
diff --git a/spm/ivy/aarch64/ivy_entrypoint.S b/spm/ivy/app/aarch64/ivy_entrypoint.S
similarity index 61%
rename from spm/ivy/aarch64/ivy_entrypoint.S
rename to spm/ivy/app/aarch64/ivy_entrypoint.S
index f79a577..d981d6a 100644
--- a/spm/ivy/aarch64/ivy_entrypoint.S
+++ b/spm/ivy/app/aarch64/ivy_entrypoint.S
@@ -20,23 +20,6 @@
 	/* Setup the stack pointer. */
 	adr	x0, stacks_end
 	mov	sp, x0
-	adr	x0, spm_shim_exceptions_ptr
-	msr	vbar_el1, x0
-
-	/* Enable I-Cache */
-	mrs	x0, sctlr_el1
-	orr	x0, x0, #SCTLR_I_BIT
-	msr	sctlr_el1, x0
-	isb
-
-	/* Relocate symbols */
-pie_fixup:
-	ldr	x0, =pie_fixup
-	and	x0, x0, #~(0x1000 - 1)
-	mov	x1, #IVY_IMAGE_SIZE
-	add	x1, x1, x0
-	bl	fixup_gdt_reloc
-
 
 	/* And jump to the C entrypoint. */
 	b	ivy_main
diff --git a/spm/ivy/ivy.dts b/spm/ivy/app/ivy.dts
similarity index 94%
rename from spm/ivy/ivy.dts
rename to spm/ivy/app/ivy.dts
index aa2324b..49a84bd 100644
--- a/spm/ivy/ivy.dts
+++ b/spm/ivy/app/ivy.dts
@@ -25,7 +25,7 @@
 	xlat-granule = <0>; /* 4KiB */
 	boot-order = <0>;
 	messaging-method = <0>; /* Direct messaging only */
-	run-time-model = <0>; /* Run to completion */
+	run-time-model = <1>; /* SP pre-emptible */
 
 	/* Boot protocol */
 	gp-register-num = <0x0>;
diff --git a/spm/ivy/app/ivy.h b/spm/ivy/app/ivy.h
new file mode 100644
index 0000000..a40f7e1
--- /dev/null
+++ b/spm/ivy/app/ivy.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IVY_H
+#define IVY_H
+
+#include <stdint.h>
+
+/* Linker symbols used to figure out the memory layout of the S-EL1 shim. */
+extern uintptr_t __SHIM_TEXT_START__, __SHIM_TEXT_END__;
+#define SHIM_TEXT_START		((uintptr_t)&__SHIM_TEXT_START__)
+#define SHIM_TEXT_END		((uintptr_t)&__SHIM_TEXT_END__)
+
+extern uintptr_t __SHIM_RODATA_START__, __SHIM_RODATA_END__;
+#define SHIM_RODATA_START	((uintptr_t)&__SHIM_RODATA_START__)
+#define SHIM_RODATA_END		((uintptr_t)&__SHIM_RODATA_END__)
+
+extern uintptr_t __SHIM_DATA_START__, __SHIM_DATA_END__;
+#define SHIM_DATA_START		((uintptr_t)&__SHIM_DATA_START__)
+#define SHIM_DATA_END		((uintptr_t)&__SHIM_DATA_END__)
+
+extern uintptr_t __SHIM_BSS_START__, __SHIM_BSS_END__;
+#define SHIM_BSS_START		((uintptr_t)&__SHIM_BSS_START__)
+#define SHIM_BSS_END		((uintptr_t)&__SHIM_BSS_END__)
+
+/* Linker symbols used to figure out the memory layout of Ivy (S-EL0). */
+extern uintptr_t __TEXT_START__, __TEXT_END__;
+#define IVY_TEXT_START		((uintptr_t)&__TEXT_START__)
+#define IVY_TEXT_END		((uintptr_t)&__TEXT_END__)
+
+extern uintptr_t __RODATA_START__, __RODATA_END__;
+#define IVY_RODATA_START	((uintptr_t)&__RODATA_START__)
+#define IVY_RODATA_END		((uintptr_t)&__RODATA_END__)
+
+extern uintptr_t __DATA_START__, __DATA_END__;
+#define IVY_DATA_START		((uintptr_t)&__DATA_START__)
+#define IVY_DATA_END		((uintptr_t)&__DATA_END__)
+
+extern uintptr_t __BSS_START__, __BSS_END__;
+#define IVY_BSS_START		((uintptr_t)&__BSS_START__)
+#define IVY_BSS_END		((uintptr_t)&__BSS_END__)
+
+#endif /* __IVY_H__ */
diff --git a/spm/ivy/ivy_def.h b/spm/ivy/app/ivy_def.h
similarity index 100%
rename from spm/ivy/ivy_def.h
rename to spm/ivy/app/ivy_def.h
diff --git a/spm/ivy/app/ivy_main.c b/spm/ivy/app/ivy_main.c
new file mode 100644
index 0000000..f51fcb5
--- /dev/null
+++ b/spm/ivy/app/ivy_main.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <ffa_helpers.h>
+#include <ivy_def.h>
+#include <platform_def.h>
+#include <sp_helpers.h>
+
+#include "ivy.h"
+
+/* Host machine information injected by the build system in the ELF file. */
+extern const char build_message[];
+extern const char version_string[];
+
+void __dead2 ivy_main(void)
+{
+	u_register_t ret;
+	svc_args args;
+
+	NOTICE("Entering S-EL0 Secure Partition\n");
+	NOTICE("%s\n", build_message);
+	NOTICE("%s\n", version_string);
+
+init:
+	args = (svc_args){.fid = FFA_MSG_WAIT};
+	ret = sp_svc(&args);
+	while (1) {
+		if (ret != FFA_MSG_SEND_DIRECT_REQ_SMC32) {
+			ERROR("unknown FF-A request %lx\n", ret);
+			goto init;
+		}
+		VERBOSE("Received request: %lx\n", args.arg3);
+		args.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32;
+		args.arg1 = 0x80020000;
+		args.arg2 = 0;
+		args.arg3 = 0;
+		ret = sp_svc(&args);
+	}
+}
diff --git a/spm/ivy/ivy.h b/spm/ivy/ivy.h
deleted file mode 100644
index c5cac2e..0000000
--- a/spm/ivy/ivy.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef IVY_H
-#define IVY_H
-
-#include <stdint.h>
-
-/* Linker symbols used to figure out the memory layout of Ivy. */
-extern uintptr_t __TEXT_START__, __TEXT_END__;
-#define IVY_TEXT_START		((uintptr_t)&__TEXT_START__)
-#define IVY_TEXT_END		((uintptr_t)&__TEXT_END__)
-
-extern uintptr_t __RODATA_START__, __RODATA_END__;
-#define IVY_RODATA_START	((uintptr_t)&__RODATA_START__)
-#define IVY_RODATA_END		((uintptr_t)&__RODATA_END__)
-
-extern uintptr_t __DATA_START__, __DATA_END__;
-#define IVY_DATA_START		((uintptr_t)&__DATA_START__)
-#define IVY_DATA_END		((uintptr_t)&__DATA_END__)
-
-extern uintptr_t __BSS_START__, __BSS_END__;
-#define IVY_BSS_START		((uintptr_t)&__BSS_START__)
-#define IVY_BSS_END		((uintptr_t)&__BSS_END__)
-
-#endif /* __IVY_H__ */
diff --git a/spm/ivy/ivy.ld.S b/spm/ivy/ivy.ld.S
index a247ee4..0e47c21 100644
--- a/spm/ivy/ivy.ld.S
+++ b/spm/ivy/ivy.ld.S
@@ -10,7 +10,7 @@
 
 OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
 OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
-ENTRY(ivy_entrypoint)
+ENTRY(shim_entrypoint)
 
 SECTIONS
 {
@@ -19,6 +19,48 @@
     ASSERT(. == ALIGN(PAGE_SIZE),
            "TEXT_START address is not aligned to PAGE_SIZE.")
 
+    /*----------------- START S-EL1 SHIM ----------------*/
+
+    .shim_text : {
+        __SHIM_TEXT_START__ = .;
+        *spm_shim_entrypoint.o(.text*)
+        *(.vectors)
+        . = NEXT(PAGE_SIZE);
+        __SHIM_TEXT_END__ = .;
+    }
+
+    .shim_rodata : {
+        . = ALIGN(PAGE_SIZE);
+        __SHIM_RODATA_START__ = .;
+
+        . = NEXT(PAGE_SIZE);
+        __SHIM_RODATA_END__ = .;
+    }
+
+    .shim_data : {
+        . = ALIGN(PAGE_SIZE);
+        __SHIM_DATA_START__ = .;
+
+        . = NEXT(PAGE_SIZE);
+        __SHIM_DATA_END__ = .;
+    }
+
+    .shim_bss (NOLOAD) : {
+        . = ALIGN(PAGE_SIZE);
+        __SHIM_BSS_START__ = .;
+
+        *(.bss.shim_stacks)
+        *(.bss.tf_base_xlat_table)
+        *(.bss.tf_mmap)
+        *xlat_tables_context.o(COMMON)
+	*xlat_tables_context.o(xlat_table)
+
+        . = NEXT(PAGE_SIZE);
+        __SHIM_BSS_END__ = .;
+    }
+
+    /*----------------- END S-EL1 SHIM ----------------*/
+
     .text : {
         __TEXT_START__ = .;
         *ivy_entrypoint.o(.text*)
@@ -32,6 +74,7 @@
         . = ALIGN(PAGE_SIZE);
         __RODATA_START__ = .;
         *(.rodata*)
+
         /*
          * Keep the .got section in the RO section as it is patched
          * prior to enabling the MMU, so having it in RO is better for
diff --git a/spm/ivy/ivy.mk b/spm/ivy/ivy.mk
index e762f99..7230a45 100644
--- a/spm/ivy/ivy.mk
+++ b/spm/ivy/ivy.mk
@@ -20,15 +20,20 @@
 	-Iinclude/lib/xlat_tables			\
 	-Iinclude/runtime_services			\
 	-Iinclude/runtime_services/secure_el0_payloads	\
-	-Ispm/ivy					\
+	-Ispm/ivy/app				\
+	-Ispm/ivy/shim					\
 	-Ispm/common
 
 IVY_SOURCES	:=					\
-	$(addprefix spm/ivy/,			\
+	$(addprefix spm/ivy/app/,			\
 		aarch64/ivy_entrypoint.S		\
-		aarch64/spm_shim_exceptions.S		\
 		ivy_main.c				\
 	)						\
+	$(addprefix spm/ivy/shim/,			\
+		aarch64/spm_shim_entrypoint.S		\
+		aarch64/spm_shim_exceptions.S		\
+		shim_main.c				\
+	)						\
 	$(addprefix spm/common/,			\
 		aarch64/sp_arch_helpers.S		\
 		sp_debug.c				\
@@ -69,10 +74,10 @@
 $(eval $(call add_define,IVY_DEFINES,PLAT_${PLAT}))
 
 $(IVY_DTB) : $(BUILD_PLAT)/ivy $(BUILD_PLAT)/ivy/ivy.elf
-$(IVY_DTB) : spm/ivy/ivy.dts
-	@echo "  DTBGEN  spm/ivy/ivy.dts"
+$(IVY_DTB) : spm/ivy/app/ivy.dts
+	@echo "  DTBGEN  spm/ivy/app/ivy.dts"
 	${Q}tools/generate_dtb/generate_dtb.sh \
-		ivy spm/ivy/ivy.dts $(BUILD_PLAT)
+		ivy spm/ivy/app/ivy.dts $(BUILD_PLAT)
 	@echo
 	@echo "Built $@ successfully"
 	@echo
diff --git a/spm/ivy/ivy_main.c b/spm/ivy/ivy_main.c
deleted file mode 100644
index 02f8be2..0000000
--- a/spm/ivy/ivy_main.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <debug.h>
-#include <drivers/console.h>
-#include <drivers/arm/pl011.h>
-#include <errno.h>
-#include <ivy_def.h>
-#include <plat_arm.h>
-#include <platform_def.h>
-#include <sp_helpers.h>
-
-#include "ivy.h"
-#include "ivy_def.h"
-
-/* Host machine information injected by the build system in the ELF file. */
-extern const char build_message[];
-extern const char version_string[];
-
-static void ivy_print_memory_layout(void)
-{
-	NOTICE("Secure Partition memory layout:\n");
-
-	NOTICE("  Image regions\n");
-	NOTICE("    Text region            : %p - %p\n",
-		(void *)IVY_TEXT_START, (void *)IVY_TEXT_END);
-	NOTICE("    Read-only data region  : %p - %p\n",
-		(void *)IVY_RODATA_START, (void *)IVY_RODATA_END);
-	NOTICE("    Data region            : %p - %p\n",
-		(void *)IVY_DATA_START, (void *)IVY_DATA_END);
-	NOTICE("    BSS region             : %p - %p\n",
-		(void *)IVY_BSS_START, (void *)IVY_BSS_END);
-	NOTICE("    Total image memory     : %p - %p\n",
-		(void *)IVY_IMAGE_BASE,
-		(void *)(IVY_IMAGE_BASE + IVY_IMAGE_SIZE));
-	NOTICE("  SPM regions\n");
-	NOTICE("    SPM <-> SP buffer      : %p - %p\n",
-		(void *)IVY_SPM_BUF_BASE,
-		(void *)(IVY_SPM_BUF_BASE + IVY_SPM_BUF_SIZE));
-	NOTICE("    NS <-> SP buffer       : %p - %p\n",
-		(void *)IVY_NS_BUF_BASE,
-		(void *)(IVY_NS_BUF_BASE + IVY_NS_BUF_SIZE));
-}
-
-void __dead2 ivy_main(void)
-{
-	u_register_t ret;
-	svc_args args;
-
-	console_init(PL011_UART3_BASE,
-		     PL011_UART3_CLK_IN_HZ,
-		     PL011_BAUDRATE);
-
-	NOTICE("Booting test Secure Partition Ivy\n");
-	NOTICE("%s\n", build_message);
-	NOTICE("%s\n", version_string);
-	NOTICE("Running at S-EL0\n");
-
-	ivy_print_memory_layout();
-
-init:
-	args = (svc_args){.fid = FFA_MSG_WAIT};
-	ret = sp_svc(&args);
-	while (1) {
-		if (ret != FFA_MSG_SEND_DIRECT_REQ_SMC32) {
-			ERROR("unknown FF-A request %lx\n", ret);
-			goto init;
-		}
-		VERBOSE("Received request: %lx\n", args.arg3);
-		args.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32;
-		args.arg1 = 0x80020000;
-		args.arg2 = 0;
-		args.arg3 = 0;
-		ret = sp_svc(&args);
-	}
-}
diff --git a/spm/ivy/shim/aarch64/spm_shim_entrypoint.S b/spm/ivy/shim/aarch64/spm_shim_entrypoint.S
new file mode 100644
index 0000000..55d8dd8
--- /dev/null
+++ b/spm/ivy/shim/aarch64/spm_shim_entrypoint.S
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <ivy_def.h>
+#include <platform_def.h>
+
+	.globl	shim_entrypoint
+
+.section .bss.shim_stacks
+	.balign CACHE_WRITEBACK_GRANULE
+	.fill	IVY_STACKS_SIZE
+shim_stacks_end:
+
+func shim_entrypoint
+
+	/* Setup the stack pointer. */
+	adr	x0, shim_stacks_end
+	mov	sp, x0
+
+	/* Setup vector base address */
+	adr	x0, spm_shim_exceptions_ptr
+	msr	vbar_el1, x0
+	isb
+
+	/*
+	 * Invalidate the data cache for the shim and whole partition.
+	 * This prevents re-use of stale data cache entries from prior
+	 * bootloader stages.
+	 */
+	adrp	x0, __SHIM_TEXT_START__
+	adrp	x1, __BSS_END__
+	sub	x1, x1, x0
+	bl	inv_dcache_range
+
+	/* Enable I-Cache */
+	mrs	x0, sctlr_el1
+	orr	x0, x0, #SCTLR_I_BIT
+	msr	sctlr_el1, x0
+	isb
+
+	/* Relocate symbols */
+shim_pie_fixup:
+	ldr	x0, =shim_pie_fixup
+	and	x0, x0, #~(0x1000 - 1)
+	mov	x1, #IVY_IMAGE_SIZE
+	add	x1, x1, x0
+	bl	fixup_gdt_reloc
+
+	/* Clear S-EL1 shim BSS */
+	adrp	x0, __SHIM_BSS_START__
+	adrp	x2, __SHIM_BSS_END__
+	sub	x2, x2, x0
+	mov	x1, xzr
+	bl	memset
+
+	/* Clear S-EL0 partition BSS */
+	adrp	x0, __BSS_START__
+	adrp	x2, __BSS_END__
+	sub	x2, x2, x0
+	mov	x1, xzr
+	bl	memset
+
+	/* And jump to the C entrypoint. */
+	bl	shim_main
+
+	/* Exception return to S-EL0 Ivy application code */
+	adrp	x0, ivy_entrypoint
+	msr	elr_el1, x0
+
+	/* AArch64 EL0t */
+	mov	x0, #((DAIF_FIQ_BIT | DAIF_IRQ_BIT) << SPSR_DAIF_SHIFT)
+	msr	spsr_el1, x0
+
+	/* TODO: clear GP/SIMD registers */
+	/* TODO: tune EL0 system registers */
+
+	eret
+
+endfunc shim_entrypoint
diff --git a/spm/ivy/aarch64/spm_shim_exceptions.S b/spm/ivy/shim/aarch64/spm_shim_exceptions.S
similarity index 100%
rename from spm/ivy/aarch64/spm_shim_exceptions.S
rename to spm/ivy/shim/aarch64/spm_shim_exceptions.S
diff --git a/spm/ivy/shim/shim_main.c b/spm/ivy/shim/shim_main.c
new file mode 100644
index 0000000..97df1cc
--- /dev/null
+++ b/spm/ivy/shim/shim_main.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <errno.h>
+#include <ffa_helpers.h>
+#include <lib/aarch64/arch_helpers.h>
+#include <lib/xlat_tables/xlat_mmu_helpers.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat_arm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <sp_debug.h>
+#include <sp_helpers.h>
+#include <std_svc.h>
+
+#include "ivy.h"
+#include "ivy_def.h"
+
+static void shim_print_memory_layout(void)
+{
+	NOTICE("Secure Partition memory layout:\n");
+
+	NOTICE("  Image regions\n");
+	NOTICE("    Text region            : %p - %p\n",
+		(void *)IVY_TEXT_START, (void *)IVY_TEXT_END);
+	NOTICE("    Read-only data region  : %p - %p\n",
+		(void *)IVY_RODATA_START, (void *)IVY_RODATA_END);
+	NOTICE("    Data region            : %p - %p\n",
+		(void *)IVY_DATA_START, (void *)IVY_DATA_END);
+	NOTICE("    BSS region             : %p - %p\n",
+		(void *)IVY_BSS_START, (void *)IVY_BSS_END);
+	NOTICE("    Total image memory     : %p - %p\n",
+		(void *)IVY_IMAGE_BASE,
+		(void *)(IVY_IMAGE_BASE + IVY_IMAGE_SIZE));
+	NOTICE("  SPM regions\n");
+	NOTICE("    SPM <-> SP buffer      : %p - %p\n",
+		(void *)IVY_SPM_BUF_BASE,
+		(void *)(IVY_SPM_BUF_BASE + IVY_SPM_BUF_SIZE));
+	NOTICE("    NS <-> SP buffer       : %p - %p\n",
+		(void *)IVY_NS_BUF_BASE,
+		(void *)(IVY_NS_BUF_BASE + IVY_NS_BUF_SIZE));
+}
+
+static void shim_plat_configure_mmu(void)
+{
+	mmap_add_region(SHIM_TEXT_START,
+			SHIM_TEXT_START,
+			SHIM_TEXT_END - SHIM_TEXT_START,
+			MT_CODE | MT_PRIVILEGED);
+	mmap_add_region(SHIM_RODATA_START,
+			SHIM_RODATA_START,
+			SHIM_RODATA_END - SHIM_RODATA_START,
+			MT_RO_DATA | MT_PRIVILEGED);
+	mmap_add_region(SHIM_DATA_START,
+			SHIM_DATA_START,
+			SHIM_DATA_END - SHIM_DATA_START,
+			MT_RW_DATA | MT_PRIVILEGED);
+	mmap_add_region(SHIM_BSS_START,
+			SHIM_BSS_START,
+			SHIM_BSS_END - SHIM_BSS_START,
+			MT_RW_DATA | MT_PRIVILEGED);
+	mmap_add_region(IVY_TEXT_START,
+			IVY_TEXT_START,
+			IVY_TEXT_END - IVY_TEXT_START,
+			MT_CODE | MT_USER);
+	mmap_add_region(IVY_RODATA_START,
+			IVY_RODATA_START,
+			IVY_RODATA_END - IVY_RODATA_START,
+			MT_RO_DATA | MT_USER);
+	mmap_add_region(IVY_DATA_START,
+			IVY_DATA_START,
+			IVY_DATA_END - IVY_DATA_START,
+			MT_RW_DATA | MT_USER);
+	mmap_add_region(IVY_BSS_START,
+			IVY_BSS_START,
+			IVY_BSS_END - IVY_BSS_START,
+			MT_RW_DATA | MT_USER);
+
+	init_xlat_tables();
+}
+
+int shim_main(void)
+{
+	assert(IS_IN_EL1() != 0);
+
+	/* Initialise console */
+	set_putc_impl(HVC_CALL_AS_STDOUT);
+
+	NOTICE("Booting S-EL1 Shim\n");
+
+	/* Configure and enable Stage-1 MMU, enable D-Cache */
+	shim_plat_configure_mmu();
+	enable_mmu_el1(0);
+
+	shim_print_memory_layout();
+
+	return 0;
+}