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/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();
+	}
+}