ivy: Introduce new test Secure Partition

In order to test multiple partitions it is needed to have at least two
different partitions with different services. This way it isn't possible
to accidentally call partition A with a service of partition B and have
it work correctly.

Cactus is meant to be the main test Secure Partition. It is the one
meant to have most of the tests that a Secure Partition has to do. Ivy
is meant to be more minimalistic. In the future, Cactus may be modified
to be a S-EL1 partition while Ivy will remain as a S-EL0 partition.

Change-Id: I29d09b9f9400b58568f9b90344a4034332a6e6e1
Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
diff --git a/Makefile b/Makefile
index 4321ed0..c0d1354 100644
--- a/Makefile
+++ b/Makefile
@@ -115,6 +115,7 @@
 include fwu/ns_bl1u/ns_bl1u.mk
 include fwu/ns_bl2u/ns_bl2u.mk
 include spm/cactus/cactus.mk
+include spm/ivy/ivy.mk
 
 # Include platform specific makefile last because:
 # - the platform makefile may use all previous definitions in this file.
@@ -223,6 +224,11 @@
 CACTUS_ASFLAGS		+= ${COMMON_ASFLAGS}
 CACTUS_LDFLAGS		+= ${COMMON_LDFLAGS}
 
+IVY_INCLUDES		+= ${PLAT_INCLUDES}
+IVY_CFLAGS		+= ${COMMON_CFLAGS}
+IVY_ASFLAGS		+= ${COMMON_ASFLAGS}
+IVY_LDFLAGS		+= ${COMMON_LDFLAGS}
+
 .PHONY: locate-checkpatch
 locate-checkpatch:
 ifndef CHECKPATCH
@@ -289,6 +295,11 @@
 cactus:
 	@echo "ERROR: $@ is supported only on AArch64 FVP."
 	@exit 1
+
+.PHONY: ivy
+ivy:
+	@echo "ERROR: $@ is supported only on AArch64 FVP."
+	@exit 1
 endif
 
 MAKE_DEP = -Wp,-MD,$(DEP) -MT $$@
@@ -415,6 +426,7 @@
 
 ifeq (${ARCH}-${PLAT},aarch64-fvp)
   $(eval $(call MAKE_IMG,cactus))
+  $(eval $(call MAKE_IMG,ivy))
 endif
 
 # The EL3 test payload is only supported in AArch64. It has an independent build
@@ -436,7 +448,7 @@
 
 .PHONY: help
 help:
-	@echo "usage: ${MAKE} PLAT=<${PLATFORMS}> <all|tftf|ns_bl1u|ns_bl2u|cactus|el3_payload|distclean|clean|checkcodebase|checkpatch>"
+	@echo "usage: ${MAKE} PLAT=<${PLATFORMS}> <all|tftf|ns_bl1u|ns_bl2u|cactus|ivy|el3_payload|distclean|clean|checkcodebase|checkpatch>"
 	@echo ""
 	@echo "PLAT is used to specify which platform you wish to build."
 	@echo "If no platform is specified, PLAT defaults to: ${DEFAULT_PLAT}"
@@ -448,6 +460,7 @@
 	@echo "  ns_bl1u        Build the NS_BL1U image"
 	@echo "  ns_bl2u        Build the NS_BL2U image"
 	@echo "  cactus         Build the Cactus image (Test S-EL0 payload)."
+	@echo "  ivy            Build the Ivy image (Test S-EL0 payload)."
 	@echo "  el3_payload    Build the EL3 test payload"
 	@echo "  checkcodebase  Check the coding style of the entire source tree"
 	@echo "  checkpatch     Check the coding style on changes in the current"
diff --git a/include/common/debug.h b/include/common/debug.h
index c5b0f8e..bfbff09 100644
--- a/include/common/debug.h
+++ b/include/common/debug.h
@@ -11,7 +11,7 @@
 
 /* TODO: Deal with per-image printf functions in a cleaner way. */
 
-#ifdef IMAGE_CACTUS
+#if defined(IMAGE_CACTUS) || defined(IMAGE_IVY)
 /*
  * The register MPIDR_EL1 can't be read from EL0, which means that mp_printf()
  * can't be used.
diff --git a/spm/ivy/aarch64/ivy_entrypoint.S b/spm/ivy/aarch64/ivy_entrypoint.S
new file mode 100644
index 0000000..c6cb8b3
--- /dev/null
+++ b/spm/ivy/aarch64/ivy_entrypoint.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <ivy_def.h>
+#include <platform_def.h>
+
+	.globl	ivy_entrypoint
+
+.section .bss.stacks
+	.balign CACHE_WRITEBACK_GRANULE
+	.fill	IVY_STACKS_SIZE
+stacks_end:
+
+func ivy_entrypoint
+
+	/* Setup the stack pointer. */
+	adr	x0, stacks_end
+	mov	sp, x0
+
+	/* And jump to the C entrypoint. */
+	b	ivy_main
+
+endfunc ivy_entrypoint
diff --git a/spm/ivy/ivy.dts b/spm/ivy/ivy.dts
new file mode 100644
index 0000000..4c5a11a
--- /dev/null
+++ b/spm/ivy/ivy.dts
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <sp_res_desc_def.h>
+
+#include "ivy_def.h"
+
+/* 4 KiB pages */
+#define PAGE_SIZE			U(0x1000)
+
+/*
+ * FVP platform layout. The defines are hardcoded here because including the
+ * platform headers have too many dependencies.
+ * TODO: Move this to the platform layer.
+ */
+#define V2M_IOFPGA_BASE			ULL(0x1c000000)
+#define V2M_IOFPGA_SIZE			ULL(0x03000000)
+
+/* Aggregate of all devices in the first GB. */
+#define DEVICE0_BASE			ULL(0x20000000)
+#define DEVICE0_SIZE			ULL(0x0c200000)
+
+/dts-v1/;
+
+/ {
+	compatible = "arm,sp_rd";
+
+	attribute {
+		version = <0x00000001>;
+		sp_type = <RD_ATTR_TYPE_UP_MIGRATABLE>;
+		pe_mpidr = <0>; /* Unused */
+		runtime_el = <RD_ATTR_RUNTIME_SEL0>;
+		exec_type = <RD_ATTR_RUNTIME>;
+		panic_policy = <RD_ATTR_PANIC_ONESHOT>;
+		xlat_granule = <RD_ATTR_XLAT_GRANULE_4KB>;
+		binary_size = <IVY_IMAGE_SIZE>;
+		load_address = <0x00000000 IVY_IMAGE_BASE>;
+		entrypoint = <0x00000000 IVY_IMAGE_BASE>;
+	};
+
+	memory_regions {
+		v2m_iofpga {
+			str = "V2M IOFPGA";
+			base = <0x00000000 V2M_IOFPGA_BASE>;
+			size = <0x00000000 V2M_IOFPGA_SIZE>;
+			attr = <RD_MEM_DEVICE>;
+		};
+
+		device0 {
+			str = "Device 0";
+			base = <0x00000000 DEVICE0_BASE>;
+			size = <0x00000000 DEVICE0_SIZE>;
+			attr = <RD_MEM_DEVICE>;
+		};
+
+		spm_buffer {
+			str = "SPM buffer";
+			base = <0x00000000 IVY_SPM_BUF_BASE>;
+			size = <0x00000000 IVY_SPM_BUF_SIZE>;
+			attr = <RD_MEM_NORMAL_SPM_SP_SHARED_MEM>;
+		};
+
+		ns_buffer {
+			str = "NS buffer";
+			base = <0x00000000 IVY_NS_BUF_BASE>;
+			size = <0x00000000 IVY_NS_BUF_SIZE>;
+			attr = <RD_MEM_NORMAL_CLIENT_SHARED_MEM>;
+		};
+	};
+
+	notifications {
+		notification_0 {
+			attr = <0>;
+			pe = <0>;
+		};
+	};
+
+	services {
+		test_service_1 {
+			uuid = <IVY_SERVICE1_UUID_RD>;
+
+			accessibility = <(RD_SERV_ACCESS_SECURE |
+					  RD_SERV_ACCESS_EL3 |
+					  RD_SERV_ACCESS_NORMAL)>;
+			request_type = <(RD_SERV_SUPPORT_BLOCKING |
+					 RD_SERV_SUPPORT_NON_BLOCKING)>;
+			connection_quota = <10>;
+			sec_mem_size = <0>;
+			interrupt_num = <0>;
+		};
+	};
+};
diff --git a/spm/ivy/ivy.h b/spm/ivy/ivy.h
new file mode 100644
index 0000000..b312540
--- /dev/null
+++ b/spm/ivy/ivy.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IVY_H
+#define IVY_H
+
+#include <types.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
new file mode 100644
index 0000000..634db15
--- /dev/null
+++ b/spm/ivy/ivy.ld.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <ivy_def.h>
+#include <platform_def.h>
+#include <xlat_tables_defs.h>
+
+OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
+OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
+ENTRY(ivy_entrypoint)
+
+SECTIONS
+{
+    . = IVY_IMAGE_BASE;
+
+    ASSERT(. == ALIGN(PAGE_SIZE),
+           "TEXT_START address is not aligned to PAGE_SIZE.")
+
+    .text : {
+        __TEXT_START__ = .;
+        *ivy_entrypoint.o(.text*)
+        *(.text*)
+        *(.vectors)
+        . = NEXT(PAGE_SIZE);
+        __TEXT_END__ = .;
+    }
+
+    .rodata : {
+        . = ALIGN(PAGE_SIZE);
+        __RODATA_START__ = .;
+        *(.rodata*)
+        . = NEXT(PAGE_SIZE);
+        __RODATA_END__ = .;
+    }
+
+    .data : {
+        . = ALIGN(PAGE_SIZE);
+        __DATA_START__ = .;
+        *(.data*)
+        . = NEXT(PAGE_SIZE);
+        __DATA_END__ = .;
+    }
+
+    .bss (NOLOAD) : {
+        . = ALIGN(PAGE_SIZE);
+        __BSS_START__ = .;
+        *(SORT_BY_ALIGNMENT(.bss*))
+        *(COMMON)
+        . = NEXT(PAGE_SIZE);
+        __BSS_END__ = .;
+    }
+}
diff --git a/spm/ivy/ivy.mk b/spm/ivy/ivy.mk
new file mode 100644
index 0000000..2f17433
--- /dev/null
+++ b/spm/ivy/ivy.mk
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2018, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include lib/sprt/sprt_client.mk
+
+IVY_INCLUDES :=					\
+	-Iinclude					\
+	-Iinclude/common				\
+	-Iinclude/common/${ARCH}			\
+	-Iinclude/drivers				\
+	-Iinclude/drivers/arm				\
+	-Iinclude/lib					\
+	-Iinclude/lib/${ARCH}				\
+	-Iinclude/lib/stdlib				\
+	-Iinclude/lib/stdlib/sys			\
+	-Iinclude/lib/sprt				\
+	-Iinclude/lib/utils				\
+	-Iinclude/lib/xlat_tables			\
+	-Iinclude/runtime_services			\
+	-Iinclude/runtime_services/secure_el0_payloads	\
+	-Ispm/ivy					\
+	-Ispm/common					\
+	${SPRT_LIB_INCLUDES}
+
+IVY_SOURCES	:=					\
+	$(addprefix spm/ivy/,			\
+		aarch64/ivy_entrypoint.S		\
+		ivy_main.c				\
+	)						\
+	$(addprefix spm/common/,			\
+		aarch64/sp_arch_helpers.S		\
+		sp_helpers.c				\
+	)						\
+
+STDLIB_SOURCES	:=	$(addprefix lib/stdlib/,	\
+	assert.c					\
+	mem.c						\
+	putchar.c					\
+	printf.c					\
+	rand.c						\
+	strlen.c					\
+	subr_prf.c					\
+)
+
+# TODO: Remove dependency on TFTF files.
+IVY_SOURCES	+=					\
+	tftf/framework/debug.c				\
+	tftf/framework/${ARCH}/asm_debug.S
+
+IVY_SOURCES	+= 	drivers/arm/pl011/${ARCH}/pl011_console.S	\
+			lib/${ARCH}/cache_helpers.S			\
+			lib/${ARCH}/misc_helpers.S			\
+			${STDLIB_SOURCES}				\
+			${SPRT_LIB_SOURCES}
+
+IVY_LINKERFILE	:=	spm/ivy/ivy.ld.S
+
+IVY_DEFINES	:=
+
+$(eval $(call add_define,IVY_DEFINES,DEBUG))
+$(eval $(call add_define,IVY_DEFINES,ENABLE_ASSERTIONS))
+$(eval $(call add_define,IVY_DEFINES,LOG_LEVEL))
+$(eval $(call add_define,IVY_DEFINES,PLAT_${PLAT}))
+ifeq (${ARCH},aarch32)
+        $(eval $(call add_define,IVY_DEFINES,AARCH32))
+else
+        $(eval $(call add_define,IVY_DEFINES,AARCH64))
+endif
+
+ivy: ${AUTOGEN_DIR}/tests_list.h
diff --git a/spm/ivy/ivy_def.h b/spm/ivy/ivy_def.h
new file mode 100644
index 0000000..11eeacf
--- /dev/null
+++ b/spm/ivy/ivy_def.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IVY_DEF_H
+#define IVY_DEF_H
+
+/*
+ * Layout of the Secure Partition image.
+ */
+
+/* Up to 2 MiB at an arbitrary address that doesn't overlap the devices. */
+#define IVY_IMAGE_BASE			ULL(0x90000000)
+#define IVY_IMAGE_SIZE			ULL(0x200000)
+
+/* Memory reserved for stacks */
+#define IVY_STACKS_SIZE			ULL(0x1000)
+
+/* Memory shared between EL3 and S-EL0 (64 KiB). */
+#define IVY_SPM_BUF_BASE		(IVY_IMAGE_BASE + IVY_IMAGE_SIZE)
+#define IVY_SPM_BUF_SIZE		ULL(0x10000)
+
+/* Memory shared between Normal world and S-EL0 (64 KiB). */
+#define IVY_NS_BUF_BASE			(IVY_SPM_BUF_BASE + IVY_SPM_BUF_SIZE)
+#define IVY_NS_BUF_SIZE			ULL(0x10000)
+
+/*
+ * UUIDs of Secure Services provided by Cactus
+ */
+
+#define IVY_SERVICE1_UUID	U(0x76543210), U(0x89ABCDEF), U(0x76543210), U(0xFEDCBA98)
+
+#define IVY_SERVICE1_UUID_RD	U(0x76543210) U(0x89ABCDEF) U(0x76543210) U(0xFEDCBA98)
+
+/*
+ * Service IDs
+ */
+/* Print a magic number unique to IVY and return */
+#define IVY_PRINT_MAGIC			U(1001)
+/* Return a magic number unique to IVY */
+#define IVY_GET_MAGIC			U(1002)
+
+#define IVY_MAGIC_NUMBER		U(0x97531842)
+
+#endif /* IVY_DEF_H */
diff --git a/spm/ivy/ivy_main.c b/spm/ivy/ivy_main.c
new file mode 100644
index 0000000..cd81e88
--- /dev/null
+++ b/spm/ivy/ivy_main.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2018, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <ivy_def.h>
+#include <pl011.h>
+#include <plat_arm.h>
+#include <platform_def.h>
+#include <sprt_client.h>
+#include <sprt_svc.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 ivy_message_handler(struct sprt_queue_entry_message *message)
+{
+	u_register_t ret0 = 0U, ret1 = 0U, ret2 = 0U, ret3 = 0U;
+
+	if (message->type == SPRT_MSG_TYPE_SERVICE_REQUEST) {
+		switch (message->args[1]) {
+
+		case IVY_PRINT_MAGIC:
+			INFO("IVY: Magic: 0x%x\n", IVY_MAGIC_NUMBER);
+			ret0 = SPRT_SUCCESS;
+			break;
+
+		case IVY_GET_MAGIC:
+			ret1 = IVY_MAGIC_NUMBER;
+			ret0 = SPRT_SUCCESS;
+			break;
+
+		default:
+			NOTICE("IVY: Unhandled Service ID 0x%x\n",
+			       (unsigned int)message->args[1]);
+			ret0 = SPRT_NOT_SUPPORTED;
+			break;
+		}
+	} else {
+		NOTICE("Ivy: Unhandled Service type 0x%x\n",
+		       (unsigned int)message->type);
+		ret0 = SPRT_NOT_SUPPORTED;
+	}
+
+
+	sprt_message_end(message, ret0, ret1, ret2, ret3);
+}
+
+void __dead2 ivy_main(void)
+{
+	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();
+
+	/*
+	 * Handle secure service requests.
+	 */
+	sprt_initialize_queues((void *)IVY_SPM_BUF_BASE);
+
+	while (1) {
+		struct sprt_queue_entry_message message;
+
+		/*
+		 * Try to fetch a message from the blocking requests queue. If
+		 * it is empty, try to fetch from the non-blocking requests
+		 * queue. Repeat until both of them are empty.
+		 */
+		while (1) {
+			int err = sprt_get_next_message(&message,
+					SPRT_QUEUE_NUM_BLOCKING);
+			if (err == -ENOENT) {
+				err = sprt_get_next_message(&message,
+						SPRT_QUEUE_NUM_NON_BLOCKING);
+				if (err == -ENOENT) {
+					break;
+				} else {
+					assert(err == 0);
+					ivy_message_handler(&message);
+				}
+			} else {
+				assert(err == 0);
+				ivy_message_handler(&message);
+			}
+		}
+
+		sprt_wait_for_messages();
+	}
+}