SPRTL: Add log API for Secure Partitions

SPM and Secure Partitions(SP) will use different log implementations.
This patch adds the implementations for SP:
 - SP log HAL API
 - SP log interface

The log implementations re-use the currently shared log implementations.

Change-Id: I3e87e9424e6ea2a51e534bdab85406e4007c8261
Signed-off-by: Kevin Peng <kevin.peng@arm.com>
Co-authored-by: Summer Qin <summer.qin@arm.com>
Co-authored-by: Shawn Shan <shawn.shan@arm.com>
diff --git a/platform/ext/common/tfm_hal_sp_logdev.h b/platform/ext/common/tfm_hal_sp_logdev.h
new file mode 100644
index 0000000..e31dbea
--- /dev/null
+++ b/platform/ext/common/tfm_hal_sp_logdev.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_HAL_SP_LOGDEV_H__
+#define __TFM_HAL_SP_LOGDEV_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+/**
+ * \brief HAL API for Secure Partition(SP) log system
+ *
+ * \param[in]  str       The string to output
+ * \param[in]  len       Length of the string in bytes
+ *
+ * \retval >= 0          Number of chars output.
+ * \retval < 0           TF-M HAL error code.
+ */
+int32_t tfm_hal_output_sp_log(const unsigned char *str, size_t len);
+
+#endif /* __TFM_HAL_SP_LOGDEV_H__ */
diff --git a/platform/ext/common/tfm_hal_sp_logdev_periph.c b/platform/ext/common/tfm_hal_sp_logdev_periph.c
new file mode 100644
index 0000000..9c9313b
--- /dev/null
+++ b/platform/ext/common/tfm_hal_sp_logdev_periph.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "tfm_hal_sp_logdev.h"
+#include "uart_stdout.h"
+
+int32_t tfm_hal_output_sp_log(const unsigned char *str, size_t len)
+{
+    /* Peripheral based log function call the stdio_output_string directly */
+    return stdio_output_string(str, len);
+}
diff --git a/secure_fw/partitions/crypto/CMakeLists.txt b/secure_fw/partitions/crypto/CMakeLists.txt
index 9a0e654..80ed6d5 100644
--- a/secure_fw/partitions/crypto/CMakeLists.txt
+++ b/secure_fw/partitions/crypto/CMakeLists.txt
@@ -47,6 +47,7 @@
         platform_s
         crypto_service_mbedcrypto
         psa_interface
+        tfm_sprt
 )
 target_compile_definitions(tfm_partition_crypto
     PUBLIC
diff --git a/secure_fw/partitions/crypto/crypto_init.c b/secure_fw/partitions/crypto/crypto_init.c
index 648b76a..9b93ea8 100644
--- a/secure_fw/partitions/crypto/crypto_init.c
+++ b/secure_fw/partitions/crypto/crypto_init.c
@@ -9,7 +9,7 @@
 
 #include "tfm_crypto_api.h"
 #include "tfm_crypto_defs.h"
-#include "log/tfm_log.h"
+#include "tfm_sp_log.h"
 
 /*
  * \brief This Mbed TLS include is needed to initialise the memory allocator
@@ -278,7 +278,7 @@
 {
     /* Log unsafe entropy source */
 #if defined (MBEDTLS_TEST_NULL_ENTROPY)
-    LOG_MSG("\033[1;34m[Crypto] MBEDTLS_TEST_NULL_ENTROPY is not suitable for production!\033[0m\r\n");
+    LOG_INFFMT("\033[1;34m[Crypto] MBEDTLS_TEST_NULL_ENTROPY is not suitable for production!\033[0m\r\n");
 #endif
 
     /* Initialise the Mbed Crypto memory allocator to use static
diff --git a/secure_fw/partitions/lib/sprt/CMakeLists.txt b/secure_fw/partitions/lib/sprt/CMakeLists.txt
index 66a92f2..2e78e6a 100644
--- a/secure_fw/partitions/lib/sprt/CMakeLists.txt
+++ b/secure_fw/partitions/lib/sprt/CMakeLists.txt
@@ -21,6 +21,8 @@
         ./crt_memmove.c
         ./crt_memset.c
         ./service_api.c
+        ./tfm_sp_log_raw.c
+        ${CMAKE_SOURCE_DIR}/platform/ext/common/tfm_hal_sp_logdev_periph.c
 )
 
 target_link_libraries(tfm_sprt
diff --git a/secure_fw/partitions/lib/sprt/include/tfm_sp_log.h b/secure_fw/partitions/lib/sprt/include/tfm_sp_log.h
new file mode 100644
index 0000000..dfdd981
--- /dev/null
+++ b/secure_fw/partitions/lib/sprt/include/tfm_sp_log.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020, 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
+
+#define LOG_INFFMT(...) tfm_sp_log_printf(__VA_ARGS__)
+
+/**
+ * \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/sprt/tfm_sp_log_raw.c b/secure_fw/partitions/lib/sprt/tfm_sp_log_raw.c
new file mode 100644
index 0000000..bf39b3d
--- /dev/null
+++ b/secure_fw/partitions/lib/sprt/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;
+}