Test: Add NS test suite for SFN backend

Test can be opened via only enabling the SFN partitions.

Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
Change-Id: I0aca16be5b58b9eb697da8cbc884ea79a868b06b
diff --git a/test/config/check_config.cmake b/test/config/check_config.cmake
index 171f6d2..1d08884 100644
--- a/test/config/check_config.cmake
+++ b/test/config/check_config.cmake
@@ -26,6 +26,7 @@
 message(STATUS "TEST_NS_FLIH_IRQ is set as ${TEST_NS_FLIH_IRQ}")
 message(STATUS "TEST_NS_MULTI_CORE is set as ${TEST_NS_MULTI_CORE}")
 message(STATUS "TEST_NS_MANAGE_NSID is set as ${TEST_NS_MANAGE_NSID}")
+message(STATUS "TEST_NS_SFN_BACKEND is set as ${TEST_NS_SFN_BACKEND}")
 message(STATUS "TEST_S_ATTESTATION is set as ${TEST_S_ATTESTATION}")
 message(STATUS "TEST_S_AUDIT is set as ${TEST_S_AUDIT}")
 message(STATUS "TEST_S_CRYPTO is set as ${TEST_S_CRYPTO}")
diff --git a/test/framework/non_secure_suites.c b/test/framework/non_secure_suites.c
index 4f6f5f4..5a0e7a2 100755
--- a/test/framework/non_secure_suites.c
+++ b/test/framework/non_secure_suites.c
@@ -56,6 +56,9 @@
 #if defined(TEST_NS_SLIH_IRQ) || defined(TEST_NS_FLIH_IRQ)
 #include "irq_testsuite.h"
 #endif
+#ifdef TEST_NS_SFN_BACKEND
+#include "sfn_ns_tests.h"
+#endif
 #ifdef EXTRA_NS_TEST_SUITE
 #include "extra_ns_tests.h"
 #endif
@@ -139,6 +142,10 @@
     {&register_testsuite_irq_test, 0, 0, 0},
 #endif
 
+#ifdef TEST_NS_SFN_BACKEND
+    {&register_testsuite_ns_sfn_interface, 0, 0, 0},
+#endif
+
     /* End of test suites */
     {0, 0, 0, 0}
 };
diff --git a/test/suites/CMakeLists.txt b/test/suites/CMakeLists.txt
index 691f1fd..41977ed 100644
--- a/test/suites/CMakeLists.txt
+++ b/test/suites/CMakeLists.txt
@@ -85,6 +85,7 @@
 add_subdirectory(multi_core/non_secure)
 add_subdirectory(nsid)
 add_subdirectory(fpu)
+add_subdirectory(sfn)
 
 if (TFM_FUZZER_TOOL_TESTS AND TEST_FRAMEWORK_NS)
     if (NOT DEFINED TFM_FUZZER_TOOL_TESTS_CMAKE_INC_PATH)
diff --git a/test/suites/sfn/CMakeLists.txt b/test/suites/sfn/CMakeLists.txt
new file mode 100644
index 0000000..f1428c2
--- /dev/null
+++ b/test/suites/sfn/CMakeLists.txt
@@ -0,0 +1,43 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_policy(SET CMP0079 NEW)
+
+####################### Non Secure #############################################
+
+if (TEST_NS_SFN_BACKEND)
+    add_library(tfm_test_suite_sfn_ns STATIC EXCLUDE_FROM_ALL)
+
+    target_sources(tfm_test_suite_sfn_ns
+        PRIVATE
+            non_secure/sfn_backend_ns_testsuite.c
+    )
+
+    target_include_directories(tfm_test_suite_sfn_ns
+        PUBLIC
+            non_secure
+        PRIVATE
+            ${CMAKE_CURRENT_SOURCE_DIR}/../../test_services/tfm_test_sfn_partitions
+    )
+
+    target_compile_definitions(tfm_test_suite_sfn_ns
+        PRIVATE
+            DOMAIN_NS=1
+        INTERFACE
+            TEST_NS_SFN_BACKEND
+    )
+
+    target_link_libraries(tfm_test_suite_sfn_ns
+        PRIVATE
+            tfm_test_framework_ns
+    )
+
+    target_link_libraries(tfm_ns_tests
+        INTERFACE
+            tfm_test_suite_sfn_ns
+    )
+endif()
diff --git a/test/suites/sfn/non_secure/sfn_backend_ns_testsuite.c b/test/suites/sfn/non_secure/sfn_backend_ns_testsuite.c
new file mode 100644
index 0000000..b1056b1
--- /dev/null
+++ b/test/suites/sfn/non_secure/sfn_backend_ns_testsuite.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "sfn_ns_tests.h"
+#include "psa/client.h"
+#include "test_framework_helpers.h"
+#include "psa_manifest/sid.h"
+#include "tfm_sfn_test_defs.h"
+
+/* List of tests */
+static void tfm_sfn_test_1001(struct test_result_t *ret);
+static void tfm_sfn_test_1002(struct test_result_t *ret);
+static void tfm_sfn_test_1003(struct test_result_t *ret);
+static void tfm_sfn_test_1004(struct test_result_t *ret);
+
+static struct test_t sfn_veneers_tests[] = {
+    {&tfm_sfn_test_1001, "TFM_NS_SFN_TEST_1001",
+     "Get PSA framework version", {TEST_PASSED}},
+    {&tfm_sfn_test_1002, "TFM_NS_SFN_TEST_1002",
+     "Get version of an RoT Service", {TEST_PASSED}},
+    {&tfm_sfn_test_1003, "TFM_NS_SFN_TEST_1003",
+     "Request a connection-based RoT Service", {TEST_PASSED}},
+    {&tfm_sfn_test_1004, "TFM_NS_SFN_TEST_1004",
+     "Request a stateless RoT Service", {TEST_PASSED}},
+};
+
+void register_testsuite_ns_sfn_interface(struct test_suite_t *p_test_suite)
+{
+    uint32_t list_size;
+
+    list_size = (sizeof(sfn_veneers_tests) / sizeof(sfn_veneers_tests[0]));
+
+    set_testsuite("SFN non-secure interface test (TFM_NS_SFN_TEST_1XXX)",
+                  sfn_veneers_tests, list_size, p_test_suite);
+}
+
+/**
+ * \brief Retrieve the version of the PSA Framework API.
+ */
+static void tfm_sfn_test_1001(struct test_result_t *ret)
+{
+    uint32_t version;
+
+    version = psa_framework_version();
+    if (version == PSA_FRAMEWORK_VERSION) {
+        TEST_LOG("The version of the PSA Framework API is %d.\r\n", version);
+    } else {
+        TEST_FAIL("The version of the PSA Framework API is not valid!\r\n");
+    }
+}
+
+/**
+ * \brief Retrieve the version of an RoT Service.
+ */
+static void tfm_sfn_test_1002(struct test_result_t *ret)
+{
+    uint32_t version;
+
+    version = psa_version(TFM_SFN1_SERVICE1_SID);
+    if (version == PSA_VERSION_NONE) {
+        TEST_FAIL("RoT Service is not implemented or caller is not authorized" \
+                  " to access it!\r\n");
+    } else {
+        /* Valid version number */
+        TEST_LOG("The service version is %d.\r\n", version);
+        ret->val = TEST_PASSED;
+    }
+}
+
+/**
+ * \brief Request a connection-based RoT Service
+ */
+static void tfm_sfn_test_1003(struct test_result_t *ret)
+{
+    char in_str[SFN_SERVICE_BUFFER_LEN] = "It's a SFN service test.";
+    uint32_t in_len = strlen(in_str) + 1;
+    char out_str[SFN_SERVICE_BUFFER_LEN] = {'\0'};
+    psa_invec invecs[] = {{in_str, in_len}};
+    psa_outvec outvecs[] = {{out_str, sizeof(out_str)}};
+    psa_handle_t handle;
+    psa_status_t status;
+
+    handle = psa_connect(TFM_SFN2_SERVICE1_SID, TFM_SFN2_SERVICE1_VERSION);
+    if (!PSA_HANDLE_IS_VALID(handle)) {
+        TEST_FAIL("Connecting to a connection-based service fails.\r\n");
+        return;
+    }
+
+    status = psa_call(handle, PSA_IPC_CALL, invecs, IOVEC_LEN(invecs),
+                      outvecs, IOVEC_LEN(outvecs));
+    if (status != PSA_SUCCESS) {
+        TEST_FAIL("psa_call fails!\r\n");
+        return;
+    }
+
+    /* Check the data in outvec is correct */
+    if (memcmp(invecs[0].base, outvecs[0].base, in_len) == 0) {
+        TEST_LOG("Request succeeds. Outvec is: %s\r\n", outvecs[0].base);
+    } else {
+        TEST_FAIL("Outvec data length is too long.\r\n");
+    }
+
+    psa_close(handle);
+    ret->val = TEST_PASSED;
+}
+
+/**
+ * \brief Request a stateless RoT Service
+ */
+static void tfm_sfn_test_1004(struct test_result_t *ret)
+{
+    uint32_t data = SFN_SERVICE_MAGIC;
+    psa_handle_t handle;
+    psa_status_t status;
+    psa_invec invecs[] = {{&data, sizeof(data)}};
+
+    /* Connecting to a stateless service should fail. */
+    handle = psa_connect(TFM_SFN1_SERVICE1_SID, TFM_SFN1_SERVICE1_VERSION);
+    if (PSA_HANDLE_IS_VALID(handle)) {
+        TEST_FAIL("Connecting to a stateless service should not succeed.\r\n");
+        return;
+    }
+
+    status = psa_call(TFM_SFN1_SERVICE1_HANDLE, PSA_IPC_CALL,
+                      invecs, IOVEC_LEN(invecs), NULL, 0);
+    if (status != PSA_SUCCESS) {
+        TEST_FAIL("Calling a stateless service test fails.\r\n");
+        return;
+    }
+
+    ret->val = TEST_PASSED;
+}
diff --git a/test/suites/sfn/non_secure/sfn_ns_tests.h b/test/suites/sfn/non_secure/sfn_ns_tests.h
new file mode 100644
index 0000000..81820b3
--- /dev/null
+++ b/test/suites/sfn/non_secure/sfn_ns_tests.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __SFN_NS_TESTS_H__
+#define __SFN_NS_TESTS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "test_framework.h"
+
+/**
+ * \brief Register testsuite for sfn non-secure interface.
+ *
+ * \param[in] p_test_suite The test suite to be executed.
+ */
+void register_testsuite_ns_sfn_interface(struct test_suite_t *p_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SFN_NS_TESTS_H__ */
diff --git a/test/test_services/CMakeLists.txt b/test/test_services/CMakeLists.txt
index 6c179c7..091e268 100644
--- a/test/test_services/CMakeLists.txt
+++ b/test/test_services/CMakeLists.txt
@@ -44,3 +44,8 @@
 if (TEST_S_FPU)
     add_subdirectory(tfm_fpu_service)
 endif()
+
+if (TEST_NS_SFN_BACKEND)
+    add_subdirectory(tfm_test_sfn_partitions/sfn_partition1)
+    add_subdirectory(tfm_test_sfn_partitions/sfn_partition2)
+endif()
diff --git a/test/test_services/tfm_test_sfn_partitions/CMakeLists.txt b/test/test_services/tfm_test_sfn_partitions/CMakeLists.txt
deleted file mode 100644
index 5d5618f..0000000
--- a/test/test_services/tfm_test_sfn_partitions/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-#-------------------------------------------------------------------------------
-# Copyright (c) 2021, Arm Limited. All rights reserved.
-#
-# SPDX-License-Identifier: BSD-3-Clause
-#
-#-------------------------------------------------------------------------------
-
-if (TFM_PARTITION_SFN1)
-    add_subdirectory(sfn_partition1)
-endif()
-
-if (TFM_PARTITION_SFN2)
-    add_subdirectory(sfn_partition2)
-endif()
diff --git a/test/test_services/tfm_test_sfn_partitions/sfn_partition1/CMakeLists.txt b/test/test_services/tfm_test_sfn_partitions/sfn_partition1/CMakeLists.txt
index 31e68b0..136e0d7 100644
--- a/test/test_services/tfm_test_sfn_partitions/sfn_partition1/CMakeLists.txt
+++ b/test/test_services/tfm_test_sfn_partitions/sfn_partition1/CMakeLists.txt
@@ -1,14 +1,9 @@
-
 #-------------------------------------------------------------------------------
 # Copyright (c) 2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
-if (NOT TFM_PARTITION_SFN1)
-    return()
-endif()
-
 cmake_minimum_required(VERSION 3.15)
 cmake_policy(SET CMP0079 NEW)
 
@@ -38,6 +33,7 @@
     PRIVATE
         $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
         ${CMAKE_BINARY_DIR}/generated/test_services/sfn_partition1
+        ${CMAKE_CURRENT_SOURCE_DIR}/../
 )
 
 target_link_libraries(tfm_app_rot_partition_sfn1
diff --git a/test/test_services/tfm_test_sfn_partitions/sfn_partition1/sfn_partition1.c b/test/test_services/tfm_test_sfn_partitions/sfn_partition1/sfn_partition1.c
index 3118b8d..2ac518c 100644
--- a/test/test_services/tfm_test_sfn_partitions/sfn_partition1/sfn_partition1.c
+++ b/test/test_services/tfm_test_sfn_partitions/sfn_partition1/sfn_partition1.c
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2021, Arm Limited. All rights reserved.
  *
@@ -10,22 +9,36 @@
 #include "psa/service.h"
 #include "psa_manifest/sfn_partition1.h"
 #include "tfm_sp_log.h"
+#include "tfm_sfn_test_defs.h"
 
 /**
- * \brief An example service implementation that prints out a message.
+ * \brief An example stateless service implementation that prints
+ *        a received magic number 0xFFFFABCD.
  */
 psa_status_t tfm_sfn1_service1_sfn(const psa_msg_t* msg)
 {
-    psa_status_t status;
-
-    if (msg == NULL) {
-        psa_panic();
-    }
+    psa_status_t status = PSA_ERROR_PROGRAMMER_ERROR;
+    uint32_t in_data = 0;
 
     /* Decode the message */
     switch (msg->type) {
     case PSA_IPC_CALL:
-        LOG_INFFMT("[SFN1 partition] Service in SFN1 called!\r\n");
+        LOG_DBGFMT("[SFN1 partition] Service in SFN1 called!\r\n");
+        /* This service can be called without input data or with a number. */
+        if (msg->in_size[0] == sizeof(in_data)) {
+            if (psa_read(msg->handle, 0, &in_data, sizeof(in_data))
+                                                        != sizeof(in_data)) {
+                status = PSA_ERROR_PROGRAMMER_ERROR;
+                break;
+            }
+            if (in_data == SFN_SERVICE_MAGIC) {
+                LOG_DBGFMT("[SFN1 partition] Correct input: %x\r\n", in_data);
+            } else {
+                LOG_DBGFMT("[SFN1 partition] Wrong input: %x\r\n", in_data);
+                status = PSA_ERROR_PROGRAMMER_ERROR;
+                break;
+            }
+        }
         status = PSA_SUCCESS;
         break;
     default:
@@ -41,6 +54,6 @@
  */
 psa_status_t sfn_partition_example1_init(void)
 {
-    LOG_INFFMT("[SFN1 partition] SFN1 initialized.\r\n");
+    LOG_DBGFMT("[SFN1 partition] SFN1 initialized.\r\n");
     return PSA_SUCCESS;
 }
diff --git a/test/test_services/tfm_test_sfn_partitions/sfn_partition2/CMakeLists.txt b/test/test_services/tfm_test_sfn_partitions/sfn_partition2/CMakeLists.txt
index 486efaf..0ed1db9 100644
--- a/test/test_services/tfm_test_sfn_partitions/sfn_partition2/CMakeLists.txt
+++ b/test/test_services/tfm_test_sfn_partitions/sfn_partition2/CMakeLists.txt
@@ -1,14 +1,9 @@
-
 #-------------------------------------------------------------------------------
 # Copyright (c) 2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
 #-------------------------------------------------------------------------------
-if (NOT TFM_PARTITION_SFN2)
-    return()
-endif()
-
 cmake_minimum_required(VERSION 3.15)
 cmake_policy(SET CMP0079 NEW)
 
@@ -38,6 +33,7 @@
     PRIVATE
         $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
         ${CMAKE_BINARY_DIR}/generated/test_services/sfn_partition2
+        ${CMAKE_CURRENT_SOURCE_DIR}/../
 )
 
 target_link_libraries(tfm_app_rot_partition_sfn2
diff --git a/test/test_services/tfm_test_sfn_partitions/sfn_partition2/sfn_partition2.c b/test/test_services/tfm_test_sfn_partitions/sfn_partition2/sfn_partition2.c
index fa5023f..0b04109 100644
--- a/test/test_services/tfm_test_sfn_partitions/sfn_partition2/sfn_partition2.c
+++ b/test/test_services/tfm_test_sfn_partitions/sfn_partition2/sfn_partition2.c
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2021, Arm Limited. All rights reserved.
  *
@@ -11,17 +10,17 @@
 #include "psa_manifest/sfn_partition2.h"
 #include "tfm_sp_log.h"
 #include "psa_manifest/sid.h"
+#include "tfm_sfn_test_defs.h"
 
 /**
- * \brief An example service implementation that prints out a message.
+ * \brief An example service implementation that writes the received data back
+ *        to the client.
  */
 psa_status_t tfm_sfn2_service1_sfn(const psa_msg_t* msg)
 {
-    psa_status_t status;
-
-    if (msg == NULL) {
-        psa_panic();
-    }
+    psa_status_t status = PSA_ERROR_PROGRAMMER_ERROR;
+    uint32_t i, str_size;
+    uint8_t buf[SFN_SERVICE_BUFFER_LEN] = {'\0'};
 
     /* Decode the message */
     switch (msg->type) {
@@ -30,8 +29,21 @@
         status = PSA_SUCCESS;
         break;
     case PSA_IPC_CALL:
-        LOG_INFFMT("[Example SFN2 partition] Service in SFN2 called!\r\n");
-        status = PSA_SUCCESS;
+        LOG_DBGFMT("[SFN2 partition] Service in SFN2 called!\r\n");
+        /* Read string message from the invec[0]. */
+        str_size = msg->in_size[0];
+        if (str_size != 0) {
+            if (psa_read(msg->handle, 0, buf, SFN_SERVICE_BUFFER_LEN)
+                                                        != str_size) {
+                status = PSA_ERROR_PROGRAMMER_ERROR;
+                break;
+            }
+        }
+        /* Write the string message back to outvec[0]. */
+        if (msg->out_size[0] >= str_size) {
+            psa_write(msg->handle, 0, buf, str_size);
+            status = PSA_SUCCESS;
+        }
         break;
     default:
         /* Invalid message type */
@@ -46,7 +58,6 @@
  */
 psa_status_t sfn_partition_example2_init(void)
 {
-    LOG_INFFMT("[SFN2 partition] SFN2 initialized.\r\n");
-    return psa_call(TFM_SFN1_SERVICE1_HANDLE, PSA_IPC_CALL,
-                    NULL, 0, NULL, 0);
+    LOG_DBGFMT("[SFN2 partition] SFN2 initialized.\r\n");
+    return psa_call(TFM_SFN1_SERVICE1_HANDLE, PSA_IPC_CALL, NULL, 0, NULL, 0);
 }
diff --git a/test/test_services/tfm_test_sfn_partitions/tfm_sfn_test_defs.h b/test/test_services/tfm_test_sfn_partitions/tfm_sfn_test_defs.h
new file mode 100644
index 0000000..be01e19
--- /dev/null
+++ b/test/test_services/tfm_test_sfn_partitions/tfm_sfn_test_defs.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SFN_TEST_DEFS_H__
+#define __TFM_SFN_TEST_DEFS_H__
+
+/* This header file includes the definitions for SFN test client and service. */
+
+#define SFN_SERVICE_BUFFER_LEN    32
+#define SFN_SERVICE_MAGIC         0xFFFFABCD
+
+#endif /* __TFM_SFN_TEST_DEFS_H__ */