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 */
diff --git a/tools/cmake/compiler/GCC.cmake b/tools/cmake/compiler/GCC.cmake
index 33200a1..5a8fa59 100644
--- a/tools/cmake/compiler/GCC.cmake
+++ b/tools/cmake/compiler/GCC.cmake
@@ -182,7 +182,7 @@
#]===]
function(compiler_generate_binary_output)
set(options)
- set(oneValueArgs TARGET)
+ set(oneValueArgs TARGET NAME RES)
set(multiValueArgs)
cmake_parse_arguments(MY "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
@@ -190,9 +190,9 @@
TARGET ${MY_TARGET} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary
$<TARGET_FILE:${MY_TARGET}>
- $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_TARGET}.bin)
+ $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME})
if (MY_RES)
- set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_TARGET}.bin PARENT_SCOPE)
+ set(${MY_RES} $<TARGET_FILE_DIR:${MY_TARGET}>/${MY_NAME} PARENT_SCOPE)
endif()
endfunction()