Build: Create an TF-M NS example app for split build

Change-Id: If932adb8baff36e21146ed690e0a74e3b6e0b181
Signed-off-by: Awadhy Mohammed <awadhy.mohammed@arm.com>
Co-authored-by: Kevin Peng <kevin.peng@arm.com>
diff --git a/examples/tf-m-example-ns-app/CMakeLists.txt b/examples/tf-m-example-ns-app/CMakeLists.txt
new file mode 100644
index 0000000..386ea77
--- /dev/null
+++ b/examples/tf-m-example-ns-app/CMakeLists.txt
@@ -0,0 +1,68 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.15)
+
+if (NOT DEFINED CONFIG_SPE_PATH OR NOT EXISTS ${CONFIG_SPE_PATH})
+    message(FATAL_ERROR "CONFIG_SPE_PATH = ${CONFIG_SPE_PATH} is not defined or incorrect. Please provide full path to TF-M build artifacts using -DCONFIG_SPE_PATH=")
+endif()
+
+list(APPEND CMAKE_MODULE_PATH ${CONFIG_SPE_PATH}/cmake)
+
+# A platform specific MCPU and architecture flags for NS side
+include(${CONFIG_SPE_PATH}/platform/cpuarch.cmake)
+# Include common configs exported from TF-M
+include(${CONFIG_SPE_PATH}/cmake/spe_config.cmake)
+
+# Select toolchain file if it is not specified via command line or the absolutate path
+# is unavailable.
+if (NOT DEFINED TFM_TOOLCHAIN_FILE)
+    set(TFM_TOOLCHAIN_FILE    ${CONFIG_SPE_PATH}/cmake/toolchain_ns_GNUARM.cmake)
+endif()
+
+if(NOT EXISTS ${TFM_TOOLCHAIN_FILE})
+    message(FATAL_ERROR "TFM_TOOLCHAIN_FILE ${TFM_TOOLCHAIN_FILE} doesn't exist."
+                        "If it's relative path then please change to absolute path.")
+endif()
+
+include(${TFM_TOOLCHAIN_FILE})
+
+project("TF-M Example"  LANGUAGES C)
+tfm_toolchain_reload_compiler()
+
+# The exported TF-M interfaces
+add_subdirectory(${CONFIG_SPE_PATH} ${CMAKE_BINARY_DIR}/spe)
+
+add_executable(tfm_ns
+    main.c
+    ${CONFIG_SPE_PATH}/interface/src/os_wrapper/tfm_ns_interface_bare_metal.c
+    # GNU Arm compiler version greater equal than *11.3.Rel1*
+    # has a linker issue that required system calls are missing,
+    # such as _read and _write. Add stub functions of required
+    # system calls to solve this issue.
+    $<$<BOOL:${CONFIG_GNU_SYSCALL_STUB_ENABLED}>:syscalls_stub.c>
+)
+
+target_link_libraries(tfm_ns
+    PRIVATE
+        tfm_api_ns
+)
+
+set_target_properties(tfm_ns PROPERTIES
+    SUFFIX ".axf"
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
+)
+
+target_add_scatter_file(tfm_ns ${CONFIG_SPE_PATH}/platform/linker_scripts)
+
+target_link_options(tfm_ns
+    PRIVATE
+        $<$<C_COMPILER_ID:GNU>:-Wl,-Map=${CMAKE_BINARY_DIR}/bin/tfm_ns.map>
+        $<$<C_COMPILER_ID:ARMClang>:--map>
+        $<$<C_COMPILER_ID:IAR>:--map\;${CMAKE_BINARY_DIR}/bin/tfm_ns.map>
+)
+
+add_convert_to_bin_target(tfm_ns)
diff --git a/examples/tf-m-example-ns-app/main.c b/examples/tf-m-example-ns-app/main.c
new file mode 100644
index 0000000..8c1f7dc
--- /dev/null
+++ b/examples/tf-m-example-ns-app/main.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include "cmsis_compiler.h"
+#include "psa/client.h"
+#include "psa/crypto.h"
+#include "tfm_plat_ns.h"
+#include "Driver_USART.h"
+#include "uart_stdout.h"
+
+/**
+ * \brief Modified table template for user defined SVC functions
+ *
+ * \details RTX has a weak definition of osRtxUserSVC, which
+ *          is overridden here
+ */
+#if defined(__ARMCC_VERSION)
+#if (__ARMCC_VERSION == 6110004)
+/* Workaround needed for a bug in Armclang 6.11, more details at:
+ * http://www.keil.com/support/docs/4089.htm
+ */
+__attribute__((section(".gnu.linkonce")))
+#endif
+
+/* Avoids the semihosting issue */
+#if (__ARMCC_VERSION >= 6010050)
+__asm("  .global __ARM_use_no_argv\n");
+#endif
+#endif
+
+/**
+ * \brief Platform peripherals and devices initialization.
+ *        Can be overridden for platform specific initialization.
+ *
+ * \return  ARM_DRIVER_OK if the initialization succeeds
+ */
+__WEAK int32_t tfm_ns_platform_init(void)
+{
+    stdio_init();
+
+    return ARM_DRIVER_OK;
+}
+
+/**
+ * \brief main() function
+ */
+#ifndef __GNUC__
+__attribute__((noreturn))
+#endif
+int main(void)
+{
+    if (tfm_ns_platform_init() != ARM_DRIVER_OK) {
+        /* Avoid undefined behavior if platform init failed */
+        while(1);
+    }
+
+    printf("Non-Secure system starting...\r\n");
+    printf("Hello TF-M world\r\n");
+
+    uint32_t fw_version = psa_framework_version();
+    printf("FW  version = %d\r\n", fw_version);
+
+    uint8_t number;
+    printf("Testing psa get random number...\r\n");
+    for (int i = 1; i <= 5; i++) {
+        if (psa_generate_random(&number, sizeof(number)) == PSA_SUCCESS) {
+            printf("%d: psa_generate_random() = %d\r\n", i, number);
+        } else {
+            printf("psa_generate_random() failed.\r\n");
+        }
+    }
+
+    printf("End of TF-M example App\r\n");
+
+    for (;;) {
+    }
+}
diff --git a/examples/tf-m-example-ns-app/readme.rst b/examples/tf-m-example-ns-app/readme.rst
new file mode 100644
index 0000000..873a416
--- /dev/null
+++ b/examples/tf-m-example-ns-app/readme.rst
@@ -0,0 +1,44 @@
+########################
+TF-M Example Application
+########################
+
+This sub-directory provides a bare metal example NS application, demonstrating how to use the
+artifacts exported by TF-M build.
+
+The application outputs "Hello TF-M world" and uses a PSA service function to demonstrate
+that a NS application can be successfully run.
+
+*****************
+The Build Process
+*****************
+
+1. Clone the TF-M repository at anywhere, assume the root directory is ``<TF-M Source Dir>``
+
+2. Create a build folder, for example ``build``.
+
+3. Build the TF-M with the following command:
+
+..code-block::bash
+
+  cmake -S <TF-M Source Dir> -B build/spe -DTFM_PLATFORM=arm/mps2/an521 -DTFM_PROFILE=profile_small
+  cmake --build build/spe -- install
+
+4. The files necessary to build TF-M will appear in ``build/spe/api_ns``
+
+5. Build this example application:
+
+..code-block::bash
+
+  cmake -S <path_to_this_example> -B build/nspe \
+        -DCONFIG_SPE_PATH=<absolute_path_to>/build/spe/api_ns
+  cmake --build build/nspe
+
+*******************
+Run the Application
+*******************
+The output binary for the application will be located in ``build/spe/bin`` and ``build/nspe``.
+The application can be run using the SSE-200 fast-model using FVP_MPS2_AEMv8M provided by Arm
+Development Studio.
+Add ``bl2.axf`` and ``tfm_s_ns_signed.bin`` to the symbol files in the Debug Configuration menu.
+
+*Copyright (c) 2023, Arm Limited. All rights reserved.*
diff --git a/examples/tf-m-example-ns-app/syscalls_stub.c b/examples/tf-m-example-ns-app/syscalls_stub.c
new file mode 100644
index 0000000..9ebe78e
--- /dev/null
+++ b/examples/tf-m-example-ns-app/syscalls_stub.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/*
+ * NOTE: When GNU Arm compiler version greater equal than *11.3.Rel1*, there is a linker issue that
+ * some system calls are not implemented, such as _close, _fstat and _getpid etc. So add this file
+ * including stub functions of system calls to avoid the above linker issue.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+__attribute__((weak))
+void _close(void)
+{
+}
+
+__attribute__((weak))
+void _fstat(void)
+{
+}
+
+__attribute__((weak))
+void _getpid(void)
+{
+}
+
+__attribute__((weak))
+void _isatty(void)
+{
+}
+
+__attribute__((weak))
+void _kill(void)
+{
+}
+
+__attribute__((weak))
+void _lseek(void)
+{
+}
+
+__attribute__((weak))
+void _read(void)
+{
+}
+
+__attribute__((weak))
+void _write(void)
+{
+}