Integrate newlib into opteesp environment

Use newlib external component in opteesp targeted builds along the
necessary compiler and linker options. Also adding/modifying the source
files for startup, heap handling and trace features. The sp.ld.S file
is based on ta/arch/arm/ta.ld.S from optee_os
6be0dbcaa11394a2ad5a46ac77e2f76e31a41722.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: Ie9f3e8f0fb755bb88cc33feffda86fbbbf3c7fce
diff --git a/environments/opteesp/component.cmake b/environments/opteesp/component.cmake
index bd6e036..f6a65cd 100644
--- a/environments/opteesp/component.cmake
+++ b/environments/opteesp/component.cmake
@@ -10,24 +10,40 @@
 endif()
 
 target_sources(${TGT} PRIVATE
-	"${CMAKE_CURRENT_LIST_DIR}/libsp_entry.c"
+	"${CMAKE_CURRENT_LIST_DIR}/optee_sp_header.c"
+	"${CMAKE_CURRENT_LIST_DIR}/newlib_init.c"
+	"${CMAKE_CURRENT_LIST_DIR}/newlib_sp_assert.c"
+	"${CMAKE_CURRENT_LIST_DIR}/newlib_sp_heap.c"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_entry.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_trace.c"
-	)
+)
 
 target_include_directories(${TGT}
 	PUBLIC
 		"${CMAKE_CURRENT_LIST_DIR}/include"
 	)
 
-if (NOT DEFINED TRACE_PREFIX)
-	set(TRACE_PREFIX "SP" CACHE STRING "Trace prefix")
-endif()
-
-if (NOT DEFINED TRACE_LEVEL)
-	set(TRACE_LEVEL "TRACE_LEVEL_ERROR" CACHE STRING "Trace level")
-endif()
+# Default trace configuration, can be overwritten by setting the same variables
+# in the deployment specific file before including this file.
+set(TRACE_PREFIX "SP" CACHE STRING "Trace prefix")
+set(TRACE_LEVEL "TRACE_LEVEL_ERROR" CACHE STRING "Trace level")
 
 target_compile_definitions(${TGT} PRIVATE
 	TRACE_LEVEL=${TRACE_LEVEL}
 	TRACE_PREFIX="${TRACE_PREFIX}"
 )
+
+include(../../../external/newlib/newlib.cmake)
+
+target_link_libraries(${TGT} PRIVATE
+	c
+	nosys
+)
+
+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)
diff --git a/environments/opteesp/default_toolchain_file.cmake b/environments/opteesp/default_toolchain_file.cmake
index 34ca0c9..f0e0277 100644
--- a/environments/opteesp/default_toolchain_file.cmake
+++ b/environments/opteesp/default_toolchain_file.cmake
@@ -15,10 +15,6 @@
 set(CMAKE_SYSTEM_PROCESSOR arm)
 set(CMAKE_POSITION_INDEPENDENT_CODE True)
 
-#set(CMAKE_C_FLAGS_INIT --specs=nosys.specs)
-#set(CMAKE_CXX_FLAGS_INIT --specs=nosys.specs)
-#set(CMAKE_EXE_LINKER_FLAGS_INIT --specs=nosys.specs)
-
 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:
diff --git a/environments/opteesp/include/libc_init.h b/environments/opteesp/include/libc_init.h
new file mode 100644
index 0000000..232c3c0
--- /dev/null
+++ b/environments/opteesp/include/libc_init.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBC_INIT_H_
+#define LIBC_INIT_H_
+
+void libc_init(void);
+
+#endif /* LIBC_INIT_H_ */
diff --git a/environments/opteesp/include/optee_sp_internal_api.h b/environments/opteesp/include/optee_sp_internal_api.h
new file mode 100644
index 0000000..d275caa
--- /dev/null
+++ b/environments/opteesp/include/optee_sp_internal_api.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef OPTEE_SP_INTERNAL_API_H_
+#define OPTEE_SP_INTERNAL_API_H_
+
+#include <stdint.h>
+
+/*
+ * The file describes the API between the OP-TEE and the SP.
+ * The SP code base should also contain a header file named
+ * "optee_sp_user_defines.h" for passing the following definitions to the SP dev
+ * kit:
+ * * OPTEE_SP_HEAP_SIZE: Heap size in bytes
+ * * OPTEE_SP_UUID: UUID of the SP as an sp_uuid structure
+ * * OPTEE_SP_STACK_SIZE: Stack size in bytes
+ * * OPTEE_SP_FLAGS: SP attributes (currently none available, set to zero)
+ */
+
+/*
+ * SP header types
+ */
+struct optee_sp_uuid {
+	uint32_t timeLow;
+	uint16_t timeMid;
+	uint16_t timeHiAndVersion;
+	uint8_t clockSeqAndNode[8];
+};
+
+struct optee_sp_head {
+	struct optee_sp_uuid uuid;
+	uint32_t stack_size;
+	uint32_t flags;
+	uint64_t reserved;
+};
+
+#endif /* OPTEE_SP_INTERNAL_API_H_ */
diff --git a/environments/opteesp/libsp_entry.c b/environments/opteesp/libsp_entry.c
deleted file mode 100644
index 68f410b..0000000
--- a/environments/opteesp/libsp_entry.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include "ffa_internal_api.h"
-#include "optee_sp_internal_api.h"
-#include "sp_api.h"
-
-void __noreturn optee_sp_entry(uintptr_t a0, uintptr_t a1, uintptr_t a2,
-			 uintptr_t a3)
-{
-	(void)a1;
-	(void)a2;
-	(void)a3;
-
-	sp_main((struct ffa_init_info *)a0);
-}
-
-void __noreturn optee_sp_panic(void)
-{
-	while (1)
-		;
-}
diff --git a/environments/opteesp/newlib_init.c b/environments/opteesp/newlib_init.c
new file mode 100644
index 0000000..9450a68
--- /dev/null
+++ b/environments/opteesp/newlib_init.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, 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/opteesp/newlib_sp_assert.c b/environments/opteesp/newlib_sp_assert.c
new file mode 100644
index 0000000..5a2d428
--- /dev/null
+++ b/environments/opteesp/newlib_sp_assert.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <assert.h>
+#include "compiler.h"
+#include "trace.h"
+
+/*
+ * The generic trace function called on assert fail.
+ */
+void __noreturn __assert_func(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/opteesp/newlib_sp_heap.c b/environments/opteesp/newlib_sp_heap.c
new file mode 100644
index 0000000..77a288a
--- /dev/null
+++ b/environments/opteesp/newlib_sp_heap.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "compiler.h"
+#include "optee_sp_user_defines.h"
+#include <errno.h>
+#include <stdint.h>
+#include <unistd.h>
+
+/* Allocating heap area */
+#ifndef OPTEE_SP_HEAP_SIZE
+#error "OPTEE_SP_HEAP_SIZE is not defined in SP"
+#endif
+
+static uint8_t sp_heap[OPTEE_SP_HEAP_SIZE] __aligned(16);
+static uint8_t *program_break = sp_heap;
+
+/**
+ * Basic sbrk implementation which increases the program break through the
+ * sp_heap buffer.
+ */
+void *_sbrk(ptrdiff_t incr)
+{
+	uint8_t *previous_break = program_break;
+	uint8_t *new_break = program_break + incr;
+
+	if ((new_break < sp_heap) || (new_break > (sp_heap + sizeof(sp_heap)))) {
+		errno = ENOMEM;
+		return (void *)(uintptr_t) -1;
+	}
+
+	program_break += incr;
+
+	return (void *) previous_break;
+}
diff --git a/environments/opteesp/optee_sp_header.c b/environments/opteesp/optee_sp_header.c
new file mode 100644
index 0000000..25056da
--- /dev/null
+++ b/environments/opteesp/optee_sp_header.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <compiler.h>
+#include "optee_sp_internal_api.h"
+#include "optee_sp_user_defines.h"
+
+#ifndef OPTEE_SP_UUID
+#error "OPTEE_SP_UUID is not defined in SP"
+#endif
+
+#ifndef OPTEE_SP_STACK_SIZE
+#error "OPTEE_SP_STACK_SIZE is not defined in SP"
+#endif
+
+#ifndef OPTEE_SP_FLAGS
+#error "OPTEE_SP_FLAGS is not defined in SP"
+#endif
+
+const struct optee_sp_head sp_head __section(".sp_head") = {
+	.uuid = OPTEE_SP_UUID,
+	.stack_size = OPTEE_SP_STACK_SIZE,
+	.flags = OPTEE_SP_FLAGS,
+	.reserved = UINT64_MAX
+};
diff --git a/environments/opteesp/sp.ld.S b/environments/opteesp/sp.ld.S
new file mode 100644
index 0000000..a1f3fb3
--- /dev/null
+++ b/environments/opteesp/sp.ld.S
@@ -0,0 +1,94 @@
+/* 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, 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
+
+EXTERN(sp_head)
+ENTRY(__sp_entry)
+
+SECTIONS {
+	.sp_head : {*(.sp_head)}
+	.text : {
+		__text_start = .;
+		*(.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) }
+
+	/* 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) }
+	.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) }
+	.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) }
+
+	.data : { *(.data .data.* .gnu.linkonce.d.*) }
+	.bss : {
+		*(.bss .bss.* .gnu.linkonce.b.* COMMON)
+	}
+
+	/DISCARD/ : { *(.interp) }
+}
diff --git a/environments/opteesp/sp_entry.c b/environments/opteesp/sp_entry.c
new file mode 100644
index 0000000..6249407
--- /dev/null
+++ b/environments/opteesp/sp_entry.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, 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);
+}