Create generic FF-A SP environment

Currently the boot method of SPs is SPMC specific. Each SPMC uses a
different binary format and different boot method. An SPMC agonistic
binary format and boot method has been defined, to remove
fragmentation. This is called "generic FF-A SP" here. All SPMC
implementations developed or contributed by Arm will add support for
this format. This change adds a new environment to capture the SPMC
independent binary format and boot method specifics.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I60b6a7103ee2a8188b0676a0ded5fe2a8bdf9cf9
diff --git a/environments/sp/component.cmake b/environments/sp/component.cmake
new file mode 100644
index 0000000..87f813a
--- /dev/null
+++ b/environments/sp/component.cmake
@@ -0,0 +1,53 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+if (NOT DEFINED TRACE_PREFIX)
+	message(FATAL_ERROR "mandatory parameter TRACE_PREFIX is not defined.")
+endif()
+
+if (NOT DEFINED SP_HEAP_SIZE)
+	message(FATAL_ERROR "mandatory parameter SP_HEAP_SIZE is not defined.")
+endif()
+
+if (NOT DEFINED SP_STACK_SIZE)
+	message(FATAL_ERROR "mandatory parameter SP_STACK_SIZE is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/entry.S"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_assert.c"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_entry.c"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_trace.c"
+)
+
+# Default trace level configuration, can be overwritten by setting the same
+# variable in the deployment specific file before including this file.
+set(TRACE_LEVEL "TRACE_LEVEL_ERROR" CACHE STRING "Trace level")
+
+target_compile_definitions(${TGT} PRIVATE
+	TRACE_LEVEL=${TRACE_LEVEL}
+	TRACE_PREFIX="${TRACE_PREFIX}"
+	SP_HEAP_SIZE=${SP_HEAP_SIZE}
+)
+
+include(../../../external/newlib/newlib.cmake)
+
+target_link_libraries(${TGT} PRIVATE
+	stdlib::c
+)
+
+target_link_options(${TGT} PRIVATE
+	-Wl,--hash-style=sysv
+	-Wl,--as-needed
+	-Wl,--gc-sections
+)
+
+compiler_set_linker_script(TARGET ${TGT} FILE ${CMAKE_CURRENT_LIST_DIR}/sp.ld.S DEF ARM64=1 SP_STACK_SIZE=${SP_STACK_SIZE})
diff --git a/environments/sp/default_toolchain_file.cmake b/environments/sp/default_toolchain_file.cmake
new file mode 100644
index 0000000..5e0a888
--- /dev/null
+++ b/environments/sp/default_toolchain_file.cmake
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#GNUARM v8 and v9 compilers use a different triplet.
+if(NOT CROSS_COMPILE AND NOT DEFINED ENV{CROSS_COMPILE})
+	set(CROSS_COMPILE "aarch64-elf-;aarch64-none-elf-;aarch64-linux-gnu-;aarch64-none-linux-gnu-" CACHE STRING "List of GCC prefix triplets to use.")
+endif()
+
+set(CMAKE_CROSSCOMPILING True)
+set(CMAKE_SYSTEM_NAME Generic)
+set(CMAKE_SYSTEM_PROCESSOR arm)
+set(CMAKE_POSITION_INDEPENDENT_CODE True)
+
+include($ENV{TS_ROOT}/tools/cmake/compiler/GCC.cmake REQUIRED)
+include($ENV{TS_ROOT}/tools/cmake/compiler/config_iface.cmake REQUIRED)
+# Set mandatory compiler and linker flags for this environment:
+#   - Compile position independent code
+string(APPEND CMAKE_C_FLAGS_INIT " -fpie")
+#   - Disable startup files and default libraries.
+#   - Link position independent executable
+string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " -Wl,-pie -Wl,--no-dynamic-linker")
+
+#   -link libgcc with full PATH to work around disabled linker search paths.
+gcc_get_lib_location("libgcc.a" _TMP_VAR)
+string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " ${_TMP_VAR} ")
+unset(_TMP_VAR)
diff --git a/environments/sp/entry.S b/environments/sp/entry.S
new file mode 100644
index 0000000..5fc0af3
--- /dev/null
+++ b/environments/sp/entry.S
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <asm.S>
+
+#define	R_AARCH64_RELATIVE	1027
+
+/**
+ * The following code is responsible for setting the initial value of the stack
+ * pointer and doing relocation on SP boot.
+ */
+FUNC __sp_entry, :
+	/* Use __stack_end linker symbol to set the load relative stack address. */
+	adrp	x4, __stack_end
+	add	x4, x4, :lo12:__stack_end
+	mov	sp, x4
+
+	/*
+	 * X4 = load address
+	 * X5 = relocation table start
+	 * X6 = relocation table end
+	 */
+	adr	x4, __sp_entry
+	adrp	x5, __rela_start
+	add	x5, x5, :lo12:__rela_start
+	adrp	x6, __rela_end
+	add	x6, x6, :lo12:__rela_end
+
+	/* Iterating through relocation entries */
+	cmp	x5, x6
+	beq	2f
+
+	/*
+	 * Loading relocation entry
+	 * X7 = r_offset
+	 * X8 = r_info
+	 * X9 = r_addend
+	 */
+1:	ldp	x7, x8, [x5], #16
+	ldr	x9, [x5], #8
+
+	/* Only R_AARCH64_RELATIVE type is supported */
+	cmp	w8, #R_AARCH64_RELATIVE
+	bne	3f	/* Error */
+
+	/*
+	 * Apply relative adjustment on address
+	 * *(load_address + r_offset) = load_address + r_addend
+	 */
+	add	x9, x9, x4
+	str	x9, [x7, x4]
+
+	cmp	x5, x6
+	bne	1b
+
+2:
+	b	_sp_entry
+
+3:
+	adr	X0,	error_invalid_relocation
+	bl	trace_puts
+	b	.
+
+	.align 8
+error_invalid_relocation:
+	.asciz "Only R_AARCH64_RELATIVE type relocation is supported"
+	.align 8
+END_FUNC __sp_entry
diff --git a/environments/sp/env.cmake b/environments/sp/env.cmake
new file mode 100644
index 0000000..bff1236
--- /dev/null
+++ b/environments/sp/env.cmake
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+#-------------------------------------------------------------------------------
+#  Environment file for generic SP deployments. This is a cross-compiled
+#  environment where built executables run within secure partitions with
+#  standard binary format that can be loaded by any secure partition manager.
+#-------------------------------------------------------------------------------
+set(TS_ENV "sp" CACHE STRING "Environment identifier")
+
+# Default to using the base toolcahin file for the environment
+set(TS_BASE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/default_toolchain_file.cmake" CACHE STRING "Base toolchainfile")
+
+# Replicate in environment variable for access from child cmake contexts
+set(ENV{TS_BASE_TOOLCHAIN_FILE} "${TS_BASE_TOOLCHAIN_FILE}")
+
+# Set toolchain files to use
+set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/default_toolchain_file.cmake" CACHE STRING "Toolchain file")
+set(TS_EXTERNAL_LIB_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" CACHE STRING "External lib Toolchain file")
diff --git a/environments/sp/newlib_init.c b/environments/sp/newlib_init.c
new file mode 100644
index 0000000..9adf0f2
--- /dev/null
+++ b/environments/sp/newlib_init.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "libc_init.h"
+
+/* Comes from libc */
+void __libc_init_array(void);
+
+void _init(void)
+{
+	/* Dummy */
+}
+
+void libc_init(void)
+{
+	/* Initializing global variables, calling constructors */
+	__libc_init_array();
+}
diff --git a/environments/sp/sp.ld.S b/environments/sp/sp.ld.S
new file mode 100644
index 0000000..e0380e3
--- /dev/null
+++ b/environments/sp/sp.ld.S
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: BSD-2-Clause AND BSD-3-Clause */
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V. All rights reserved.
+ * Copyright (c) 2015, Linaro Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+#ifdef ARM32
+OUTPUT_FORMAT("elf32-littlearm")
+OUTPUT_ARCH(arm)
+#endif
+#ifdef ARM64
+OUTPUT_FORMAT("elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+#endif
+
+ENTRY(__sp_entry)
+
+SECTIONS {
+	.text : {
+		__text_start = .;
+		*(.text.__sp_entry)
+		*(.text .text.*)
+		*(.stub)
+		*(.glue_7)
+		*(.glue_7t)
+		*(.gnu.linkonce.t.*)
+		/* Workaround for an erratum in ARM's VFP11 coprocessor */
+		*(.vfp11_veneer)
+		__text_end = .;
+	}
+	.plt : { *(.plt) }
+
+	.eh_frame_hdr : {
+		*(.eh_frame_hdr)
+		*(.eh_frame_entry .eh_frame_entry.*)
+	}
+	.eh_frame : { KEEP(*(.eh_frame)) *(.eh_frame.*) }
+	.gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+	.rodata : {
+		*(.gnu.linkonce.r.*)
+		*(.rodata .rodata.*)
+	}
+	.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+	/* .ARM.exidx is sorted, so has to go in its own output section.  */
+	PROVIDE_HIDDEN(__exidx_start = .);
+	.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+	PROVIDE_HIDDEN(__exidx_end = .);
+	.ctors : { *(.ctors) }
+	.dtors : { *(.dtors) }
+	.dynsym : { *(.dynsym) }
+	.dynstr : { *(.dynstr) }
+	.hash : { *(.hash) }
+	.note.gnu.build-id : { *(.note.gnu.build-id) }
+
+	. = ALIGN(8);
+	__rela_start = .;
+	.rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }
+	.rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }
+	.rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }
+	.rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }
+	.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+	.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+	.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+	.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+	.rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
+	.rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+	.rel.dyn : { *(.rel.dyn) }
+	.rel.got : { *(.rel.got) }
+	.rela.got : { *(.rela.got) }
+	.rela.dyn : { *(.rela.dyn) }
+	.rel.ctors : { *(.rel.ctors) }
+	.rela.ctors : { *(.rela.ctors) }
+	.rel.dtors : { *(.rel.dtors) }
+	.rela.dtors : { *(.rela.dtors) }
+	.rel.init : { *(.rel.init) }
+	.rela.init : { *(.rela.init) }
+	.rel.fini : { *(.rel.fini) }
+	.rela.fini : { *(.rela.fini) }
+	.rel.bss : { *(.rel.bss) }
+	.rela.bss : { *(.rela.bss) }
+	.rel.plt : { *(.rel.plt) }
+	.rela.plt : { *(.rela.plt) }
+	__rela_end = .;
+
+	/* Page align to allow dropping execute bit for RW data */
+	. = ALIGN(4096);
+
+	.dynamic : { *(.dynamic) }
+	.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+	.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+	.got : { *(.got.plt) *(.got) }
+
+	.data : { *(.data .data.* .gnu.linkonce.d.*) }
+	.bss : {
+		*(.bss .bss.* .gnu.linkonce.b.* COMMON)
+	}
+	.stack : {
+		. = ALIGN(4);
+		__stack_start = .;
+		. += SP_STACK_SIZE;
+		. = ALIGN(4);
+		__stack_end = .;
+	}
+
+	/DISCARD/ : { *(.interp) }
+}
+
+ASSERT(__sp_entry == 0,
+	"__sp_entry must be at address 0. Please check input sections and linker settings.");
diff --git a/environments/sp/sp_assert.c b/environments/sp/sp_assert.c
new file mode 100644
index 0000000..8f336e7
--- /dev/null
+++ b/environments/sp/sp_assert.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "assert_fail_handler.h"
+#include "compiler.h"
+#include "trace.h"
+
+/*
+ * The generic trace function called on assert fail.
+ */
+void __noreturn assert_fail_handler(const char *file, int line,
+				    const char *func, const char *failedexpr)
+{
+#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
+	trace_printf(func, line, TRACE_LEVEL_ERROR, "assertion %s failed", failedexpr);
+#endif /* TRACE_LEVEL */
+
+	while (1)
+		;
+}
diff --git a/environments/sp/sp_entry.c b/environments/sp/sp_entry.c
new file mode 100644
index 0000000..0a709c2
--- /dev/null
+++ b/environments/sp/sp_entry.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include "compiler.h"
+#include "libc_init.h"
+#include "sp_api.h"
+
+/*
+ * According to the FF-A specification an optional initialization descriptor can
+ * be passed to the SP in w0/x0-w3/x3 registers (a0-a3 parameters). As the exact
+ * register is implementation defined the first four registers are forwarded to
+ * the user code.
+ */
+void __noreturn _sp_entry(uintptr_t a0, uintptr_t a1,
+			   uintptr_t a2, uintptr_t a3);
+void __noreturn _sp_entry(uintptr_t a0, uintptr_t a1,
+			   uintptr_t a2, uintptr_t a3)
+{
+	(void)a1;
+	(void)a2;
+	(void)a3;
+
+	libc_init();
+
+	sp_main((struct ffa_init_info *)a0);
+}
diff --git a/environments/sp/sp_pkg.json.in b/environments/sp/sp_pkg.json.in
new file mode 100644
index 0000000..f424a1d
--- /dev/null
+++ b/environments/sp/sp_pkg.json.in
@@ -0,0 +1,7 @@
+{
+	"@EXPORT_SP_NAME@": {
+		"image": "../bin/@EXPORT_SP_UUID@.bin",
+		"pm": "../manifest/@EXPORT_SP_UUID@.dts",
+		"uuid": "@EXPORT_SP_UUID@"
+	}
+}
\ No newline at end of file
diff --git a/environments/sp/sp_trace.c b/environments/sp/sp_trace.c
new file mode 100644
index 0000000..606e45d
--- /dev/null
+++ b/environments/sp/sp_trace.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "trace.h"
+#include "ffa_internal_api.h"
+
+#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
+
+void trace_puts(const char *str)
+{
+	struct ffa_params resp;
+
+	ffa_svc(0xdeadbeef, (uintptr_t)str, 0, 0, 0, 0, 0, 0, &resp);
+}
+
+#endif  /* TRACE_LEVEL >= TRACE_LEVEL_ERROR */