SPRT: Rename the folder name to 'runtime'

The original name 'sprt' can be confusing if user did not read
SPRTL related document, hence rename it as 'runtime' to
indicate it is a secure partition runtime API set.

Signed-off-by: Ken Liu <Ken.Liu@arm.com>
Change-Id: I3ba7d5e80dd2ee32d52463bcdf012a2f5bf6017c
diff --git a/secure_fw/partitions/lib/runtime/CMakeLists.txt b/secure_fw/partitions/lib/runtime/CMakeLists.txt
new file mode 100644
index 0000000..395045e
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/CMakeLists.txt
@@ -0,0 +1,77 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 3.15)
+
+add_library(tfm_sprt STATIC)
+
+target_include_directories(tfm_sprt
+    PUBLIC
+        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+        ${CMAKE_SOURCE_DIR}/secure_fw/include
+)
+
+target_sources(tfm_sprt
+    PRIVATE
+        ./crt_memcmp.c
+        ./crt_memmove.c
+        ./crt_strnlen.c
+        ./service_api.c
+        ${CMAKE_SOURCE_DIR}/secure_fw/shared/crt_memcpy.c
+        ${CMAKE_SOURCE_DIR}/secure_fw/shared/crt_memset.c
+        $<$<BOOL:${CONFIG_TFM_PARTITION_META}>:./sprt_partition_metadata_indicator.c>
+        $<$<BOOL:${CONFIG_TFM_PARTITION_META}>:./rt_main.c>
+        $<$<BOOL:${CONFIG_TFM_SPM_BACKEND_IPC}>:./sfn_common_thread.c>
+)
+
+target_link_libraries(tfm_sprt
+    PUBLIC
+        $<$<BOOL:${TFM_SP_LOG_RAW_ENABLED}>:tfm_sp_log_raw>
+    PRIVATE
+        platform_s
+        tfm_secure_api
+        psa_interface
+        tfm_boot_status
+)
+
+target_compile_definitions(tfm_partition_defs
+    INTERFACE
+        TFM_PARTITION_LOG_LEVEL=${TFM_PARTITION_LOG_LEVEL}
+        $<$<BOOL:${TFM_SP_LOG_RAW_ENABLED}>:TFM_SP_LOG_RAW_ENABLED>
+)
+
+target_include_directories(tfm_partitions
+    INTERFACE
+        $<BUILD_INTERFACE:$<$<BOOL:${CONFIG_TFM_PARTITION_META}>:${CMAKE_CURRENT_SOURCE_DIR}/include>>
+)
+
+# Create a dedicated tfm_sp_log_raw library for some regression test modules
+# which don't include tfm_sprt.
+# tfm_sp_log_raw shall be controlled by TFM_SP_LOG_RAW_ENABLED.
+# Otherwise, build will fail if TFM_SP_LOG_RAW_ENABLED is disabled since some
+# definitions are unavailable with TFM_SP_LOG_RAW_ENABLED disabled.
+if (TFM_SP_LOG_RAW_ENABLED)
+    add_library(tfm_sp_log_raw INTERFACE)
+
+    target_sources(tfm_sp_log_raw
+        INTERFACE
+            ${CMAKE_CURRENT_SOURCE_DIR}/tfm_sp_log_raw.c
+            ${CMAKE_SOURCE_DIR}/platform/ext/common/tfm_hal_sp_logdev_periph.c
+    )
+
+    target_include_directories(tfm_sp_log_raw
+        INTERFACE
+            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+    )
+
+    target_link_libraries(tfm_sp_log_raw
+        INTERFACE
+            platform_s
+            tfm_partition_defs
+            tfm_secure_api
+    )
+endif()
diff --git a/secure_fw/partitions/lib/runtime/crt_memcmp.c b/secure_fw/partitions/lib/runtime/crt_memcmp.c
new file mode 100644
index 0000000..da17839
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_memcmp.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+    int result = 0;
+    const uint8_t *p1 = (const uint8_t *)s1;
+    const uint8_t *p2 = (const uint8_t *)s2;
+
+    while (n--) {
+        if ((*p1 != *p2) && (result == 0)) {
+            result = *p1 - *p2;
+        } else {
+            p1++;
+            p2++;
+        }
+    }
+    return result;
+}
diff --git a/secure_fw/partitions/lib/runtime/crt_memmove.c b/secure_fw/partitions/lib/runtime/crt_memmove.c
new file mode 100644
index 0000000..a4dbf7b
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_memmove.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <string.h>
+#include "crt_impl_private.h"
+
+static void *memcpy_r(void *dest, const void *src, size_t n)
+{
+    union composite_addr_t p_dst, p_src;
+
+    p_dst.uint_addr = (uintptr_t)dest + n;
+    p_src.uint_addr = (uintptr_t)src  + n;
+
+    /* Byte copy for unaligned address. check the last bit of address. */
+    while (n && (ADDR_WORD_UNALIGNED(p_dst.uint_addr) ||
+                 ADDR_WORD_UNALIGNED(p_src.uint_addr))) {
+        *(--p_dst.p_byte) = *(--p_src.p_byte);
+        n--;
+    }
+
+    /* Quad byte copy for aligned address. */
+    while (n >= sizeof(uint32_t)) {
+        *(--p_dst.p_word) = *(--p_src.p_word);
+        n -= sizeof(uint32_t);
+    }
+
+    /* Byte copy for the remaining bytes. */
+    while (n--) {
+        *(--p_dst.p_byte) = *(--p_src.p_byte);
+    }
+
+    return dest;
+}
+
+/* Mind the direction for copying in memcpy! */
+#define memcpy_f memcpy
+
+/*
+ * For overlapped memory area:
+ * 1) overlapped: use reverse memory move.
+ * 2) non-overlapped: use forward memory move.
+ */
+void *memmove(void *dest, const void *src, size_t n)
+{
+    if (src >= dest) {
+        return memcpy_f(dest, src, n);
+    } else {
+        return memcpy_r(dest, src, n);
+    }
+}
diff --git a/secure_fw/partitions/lib/runtime/crt_strnlen.c b/secure_fw/partitions/lib/runtime/crt_strnlen.c
new file mode 100644
index 0000000..13872c6
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/crt_strnlen.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stddef.h>
+
+size_t tfm_strnlen(const char *s, size_t maxlen)
+{
+    size_t idx;
+
+    for (idx = 0; idx < maxlen; idx++) {
+        if (s[idx] == '\0') {
+            return idx;
+        }
+    }
+
+    return idx;
+}
diff --git a/secure_fw/partitions/lib/runtime/include/rt_main.h b/secure_fw/partitions/lib/runtime/include/rt_main.h
new file mode 100644
index 0000000..22169ce
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/include/rt_main.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __RT_MAIN_H__
+#define __RT_MAIN_H__
+
+/* Common partition runtime entry - 'sprt_main' */
+void sprt_main(void);
+
+#endif /* __RT_MAIN_H__ */
diff --git a/secure_fw/partitions/lib/runtime/include/service_api.h b/secure_fw/partitions/lib/runtime/include/service_api.h
new file mode 100644
index 0000000..57f3e3d
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/include/service_api.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __SERVICE_API_H__
+#define __SERVICE_API_H__
+
+#include <stdint.h>
+#include "tfm_boot_status.h"
+
+/**
+ * \brief Retrieve secure partition related data from shared memory area, which
+ *        stores shared data between bootloader and runtime firmware.
+ *
+ * \param[in]  major_type  Major type.
+ * \param[out] boot_data   Pointer to boot data.
+ * \param[in]  len         The length of the boot data.
+ */
+int32_t tfm_core_get_boot_data(uint8_t major_type,
+                               struct tfm_boot_data *boot_data,
+                               uint32_t len);
+
+#endif /* __SERVICE_API_H__ */
diff --git a/secure_fw/partitions/lib/runtime/include/tfm_sp_log.h b/secure_fw/partitions/lib/runtime/include/tfm_sp_log.h
new file mode 100644
index 0000000..bf2f67d
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/include/tfm_sp_log.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_SP_LOG_H__
+#define __TFM_SP_LOG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The Secure Partition log levels */
+#define TFM_PARTITION_LOG_LEVEL_DEBUG     3  /* All log APIs output */
+#define TFM_PARTITION_LOG_LEVEL_INFO      2  /*
+                                              * All log APIs output except
+                                              * LOG_DBGFMT
+                                              */
+#define TFM_PARTITION_LOG_LEVEL_ERROR     1  /*
+                                              * Only LOG_ERRFMT APIs output.
+                                              */
+#define TFM_PARTITION_LOG_LEVEL_SILENCE   0  /* All log APIs are suppressed */
+
+#ifndef TFM_PARTITION_LOG_LEVEL
+#error "TFM_PARTITION_LOG_LEVEL not defined!"
+#endif
+
+#if (TFM_PARTITION_LOG_LEVEL > TFM_PARTITION_LOG_LEVEL_DEBUG)  || \
+    (TFM_PARTITION_LOG_LEVEL < TFM_PARTITION_LOG_LEVEL_SILENCE)
+#error "Incorrect TFM_PARTITION_LOG_LEVEL value!"
+#endif
+
+#if (TFM_PARTITION_LOG_LEVEL == TFM_PARTITION_LOG_LEVEL_DEBUG)
+#define LOG_DBGFMT(...) tfm_sp_log_printf(__VA_ARGS__)
+#else
+#define LOG_DBGFMT(...)
+#endif
+
+#if (TFM_PARTITION_LOG_LEVEL >= TFM_PARTITION_LOG_LEVEL_INFO)
+#define LOG_INFFMT(...) tfm_sp_log_printf(__VA_ARGS__)
+#else
+#define LOG_INFFMT(...)
+#endif
+
+#if (TFM_PARTITION_LOG_LEVEL >= TFM_PARTITION_LOG_LEVEL_ERROR)
+#define LOG_ERRFMT(...) tfm_sp_log_printf(__VA_ARGS__)
+#else
+#define LOG_ERRFMT(...)
+#endif
+
+/**
+ * \brief Print log messages
+ *
+ * \param[in]   fmt     Formatted string
+ * \param[in]   ...     Variable length argument
+ *
+ * \retval >= 0         Number of chars printed
+ * \retval < 0          TF-M HAL error code
+ *
+ * \note                This function has the similar input argument format as
+ *                      the 'printf' function. But it supports only some basic
+ *                      formats like 'sdicpuxX' and '%'. It will output
+ *                      "[Unsupported Tag]" when none of the above formats match
+ *
+ * \details             The following output formats are supported.
+ *                      %s - string
+ *                      %d - decimal signed integer (same for %i)
+ *                      %u - decimal unsigned integer
+ *                      %x - hex in lowercase
+ *                      %X - hex in uppercase
+ *                      %p - hex address of a pointer in lowercase
+ *                      %c - character
+ *                      %% - the '%' symbol
+ */
+int tfm_sp_log_printf(const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_SP_LOG_H__ */
diff --git a/secure_fw/partitions/lib/runtime/include/tfm_strnlen.h b/secure_fw/partitions/lib/runtime/include/tfm_strnlen.h
new file mode 100644
index 0000000..4b20c58
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/include/tfm_strnlen.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef __TFM_STRNLEN_H__
+#define __TFM_STRNLEN_H__
+
+/**
+ * \brief Return the length of a given string, up to a maximum of maxlen bytes.
+ *
+ * \param[in]  s           Points to the string to be examined.
+ * \param[in]  maxlen      The maximum number of characters to examine.
+ */
+size_t tfm_strnlen(const char *s, size_t maxlen);
+
+#endif /* __TFM_STRNLEN_H__ */
diff --git a/secure_fw/partitions/lib/runtime/rt_main.c b/secure_fw/partitions/lib/runtime/rt_main.c
new file mode 100644
index 0000000..e9ad7be
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/rt_main.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "compiler_ext_defs.h"
+#include "runtime_defs.h"
+#include "sprt_partition_metadata_indicator.h"
+#include "rt_main.h"
+
+extern void common_sfn_thread(void);
+
+__used static uintptr_t runtime_init_c(void)
+{
+    struct runtime_metadata_t *p_rt_meta;
+
+    p_rt_meta = PART_METADATA();
+
+    if (p_rt_meta->n_sfn == 0) {
+        /* IPC Partition */
+        return p_rt_meta->entry;
+    } else {
+        /* SFN Partition */
+        return (uintptr_t)common_sfn_thread;
+    }
+}
+
+#if defined(__ICCARM__)
+#pragma required = runtime_init_c
+#endif
+
+__naked void sprt_main(void)
+{
+    __asm volatile(
+#if !defined(__ICCARM__)
+        ".syntax unified    \n"
+#endif
+        "bl runtime_init_c  \n"
+        "bx r0              \n"
+    );
+}
diff --git a/secure_fw/partitions/lib/runtime/service_api.c b/secure_fw/partitions/lib/runtime/service_api.c
new file mode 100644
index 0000000..f145448
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/service_api.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "cmsis_compiler.h"
+#include "service_api.h"
+#ifdef TFM_PSA_API
+#include "psa/service.h"
+#include "svc_num.h"
+#else
+#include "tfm_core_svc.h"
+#endif /* TFM_PSA_API */
+#include "utilities.h"
+
+__attribute__((naked))
+int32_t tfm_core_get_boot_data(uint8_t major_type,
+                               struct tfm_boot_data *boot_status,
+                               uint32_t len)
+{
+    __ASM volatile(
+        "SVC    "M2S(TFM_SVC_GET_BOOT_DATA)"               \n"
+        "BX     lr                                         \n"
+        );
+}
+
+#if defined TFM_PSA_API && TFM_LVL != 1
+/* Entry point when Partition FLIH functions return */
+__attribute__((naked))
+void tfm_flih_func_return(psa_flih_result_t result)
+{
+    __ASM volatile("SVC "M2S(TFM_SVC_FLIH_FUNC_RETURN)"           \n"
+                   "BX  r0                                        \n"
+                   );
+}
+#endif /* TFM_PSA_API && TFM_LVL != 1 */
diff --git a/secure_fw/partitions/lib/runtime/sfn_common_thread.c b/secure_fw/partitions/lib/runtime/sfn_common_thread.c
new file mode 100644
index 0000000..2a2d649
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/sfn_common_thread.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include "runtime_defs.h"
+#include "sprt_partition_metadata_indicator.h"
+
+#include "psa/error.h"
+#include "psa/service.h"
+
+void common_sfn_thread(void)
+{
+    psa_signal_t sig_asserted, signal_mask, sig;
+    psa_msg_t msg;
+    struct runtime_metadata_t *meta;
+    service_fn_t *p_sfn_table;
+    sfn_init_fn_t sfn_init;
+
+    meta = PART_METADATA();
+    sfn_init = (sfn_init_fn_t)meta->entry;
+    p_sfn_table = (service_fn_t *)meta->sfn_table;
+    signal_mask = (1 << meta->n_sfn) - 1;
+
+    if (sfn_init && sfn_init() != PSA_SUCCESS) {
+        psa_panic();
+    }
+
+    while (1) {
+        sig_asserted = psa_wait(signal_mask, PSA_BLOCK);
+        /* Handle signals */
+        for (int i = 0; sig_asserted != 0 && i < meta->n_sfn; i++) {
+            sig = 1 << i;
+            if (sig_asserted & sig) {
+                /* The i bit signal asserted, index of SFN is i as well */
+                if (!p_sfn_table[i]) {
+                    /* No corresponding SFN */
+                    psa_panic();
+                }
+
+                psa_get(sig, &msg);
+                psa_reply(msg.handle, ((service_fn_t)p_sfn_table[i])(&msg));
+                sig_asserted &= ~sig;
+            }
+        }
+
+        if (sig_asserted != 0) {
+            /* Wrong signal asserted */
+            psa_panic();
+        }
+    }
+}
diff --git a/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.c b/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.c
new file mode 100644
index 0000000..8f1aaee
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+/*
+ * The address of Partition metadata, stored in TFM_SP_META_PTR region.
+ * All privilege RW. Gets updated by Scheduler when scheduling.
+ */
+__attribute__((section(".bss.SP_META_PTR_SPRTL_INST")))
+uintptr_t p_partition_metadata;
diff --git a/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.h b/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.h
new file mode 100644
index 0000000..b2ab390
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/sprt_partition_metadata_indicator.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __SPRT_PARTITION_METADATA_INDICATOR_H__
+#define __SPRT_PARTITION_METADATA_INDICATOR_H__
+
+#include <stdint.h>
+
+extern uintptr_t p_partition_metadata;
+
+/* Partition Metadata pointer */
+#define PART_METADATA() ((struct runtime_metadata_t *)p_partition_metadata)
+
+#endif /* __SPRT_PARTITION_METADATA_INDICATOR_H__ */
diff --git a/secure_fw/partitions/lib/runtime/tfm_sp_log_raw.c b/secure_fw/partitions/lib/runtime/tfm_sp_log_raw.c
new file mode 100644
index 0000000..8a8d462
--- /dev/null
+++ b/secure_fw/partitions/lib/runtime/tfm_sp_log_raw.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "tfm_hal_defs.h"
+#include "tfm_hal_sp_logdev.h"
+
+#define PRINT_BUFF_SIZE 32
+#define NUM_BUFF_SIZE 12
+
+struct formatted_buffer_t {
+    size_t pos;
+    uint8_t buf[PRINT_BUFF_SIZE];
+};
+
+static const char hex_digits_lo[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+static const char hex_digits_up[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+static void _tfm_flush_formatted_buffer(struct formatted_buffer_t *pb,
+                                        uint8_t data)
+{
+    pb->buf[pb->pos++] = data;
+    if (pb->pos >= PRINT_BUFF_SIZE) {
+        pb->pos = 0;
+        /* uart flush and print here. */
+        tfm_hal_output_sp_log(pb->buf, PRINT_BUFF_SIZE);
+    }
+}
+
+static int _tfm_string_output(struct formatted_buffer_t *pb,
+                              const char *str)
+{
+    int count = 0;
+
+    while (*str) {
+        _tfm_flush_formatted_buffer(pb, *str++);
+        count++;
+    }
+
+    return count;
+}
+
+static int _tfm_dec_num_output(struct formatted_buffer_t *pb,
+                               int32_t num, uint8_t sign)
+{
+    int count = 0;
+    uint8_t num_buff[NUM_BUFF_SIZE] = {0};
+    uint32_t number = (uint32_t)num;
+    uint32_t k = 0;
+
+    if (sign == 'd' && num < 0) {
+        _tfm_flush_formatted_buffer(pb, '-');
+        count++;
+        number = -num;
+    }
+
+    do {
+        num_buff[k++] = '0' + number % 10;
+        number /= 10;
+    } while (number);
+
+    while (k) {
+        _tfm_flush_formatted_buffer(pb, num_buff[--k]);
+        count++;
+    }
+
+    return count;
+}
+
+static int _tfm_hex_num_output(struct formatted_buffer_t *pb, uint32_t num,
+                               const char *hex_digits)
+{
+    int count = 0;
+    uint8_t num_buff[NUM_BUFF_SIZE] = {0};
+    uint32_t k = 0;
+
+    do {
+        num_buff[k++] = hex_digits[num & 0x0f];
+        num >>= 4;
+    } while (num);
+
+    while (k) {
+        _tfm_flush_formatted_buffer(pb, num_buff[--k]);
+        count++;
+    }
+
+    return count;
+}
+
+static int _tfm_sp_log_vprintf(const char *fmt, va_list ap)
+{
+    int count = 0;
+    struct formatted_buffer_t outputbuf;
+
+    outputbuf.pos = 0;
+
+    if (fmt == NULL) {
+        return TFM_HAL_ERROR_INVALID_INPUT;
+    }
+
+    while (*fmt) {
+        if (*fmt == '%') {
+            switch (*(++fmt)) {
+            case 'd':
+            case 'i':
+                count += _tfm_dec_num_output(&outputbuf,
+                                             va_arg(ap, int32_t), 'd');
+                break;
+            case 'u':
+                count += _tfm_dec_num_output(&outputbuf,
+                                             va_arg(ap, int32_t), 'u');
+                break;
+            case 'x':
+                count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t),
+                                             hex_digits_lo);
+                break;
+            case 'X':
+                count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t),
+                                             hex_digits_up);
+                break;
+            case 'p':
+                count += _tfm_string_output(&outputbuf, "0x");
+                count += _tfm_hex_num_output(&outputbuf, va_arg(ap, uint32_t),
+                                             hex_digits_lo);
+                break;
+            case 's':
+                count += _tfm_string_output(&outputbuf, va_arg(ap, char*));
+                break;
+            case 'c':
+                _tfm_flush_formatted_buffer(&outputbuf,
+                                            (uint8_t)va_arg(ap, int32_t));
+                count++;
+                break;
+            case '%':
+                _tfm_flush_formatted_buffer(&outputbuf, '%');
+                count++;
+                break;
+            default:
+                count += _tfm_string_output(&outputbuf, "[Unsupported Tag]");
+                continue;
+            }
+            fmt++;
+        } else {
+            _tfm_flush_formatted_buffer(&outputbuf, *fmt++);
+            count++;
+        }
+    }
+
+    /* End of printf, flush buf */
+    if (outputbuf.pos) {
+        count += tfm_hal_output_sp_log(outputbuf.buf, outputbuf.pos);
+    }
+
+    return count;
+}
+
+int tfm_sp_log_printf(const char *fmt, ...)
+{
+    int count = 0;
+    va_list ap;
+
+    va_start(ap, fmt);
+    count = _tfm_sp_log_vprintf(fmt, ap);
+    va_end(ap);
+
+    return count;
+}