Interface: TF-M specific log API

Provide a TF-M specific log API. Put the source in 'interface' folder
since this file are referenced by multiple components, such as bl2,
non-secure application and secure firmware. The sources are included
into SPRTL building and as part of SPRTL.
The fundamental API is 'tfm_log_printf' which supports basic formats
like 'sdicpuxX' and '%' as the format leading and escape.

Change-Id: I6d0f89ab16c3e00f8e71129a06f89dc206733733
Signed-off-by: Mingyang Sun <mingyang.sun@arm.com>
diff --git a/interface/include/log/tfm_log_raw.h b/interface/include/log/tfm_log_raw.h
new file mode 100644
index 0000000..7a5a942
--- /dev/null
+++ b/interface/include/log/tfm_log_raw.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __TFM_LOG_RAW_H__
+#define __TFM_LOG_RAW_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Prints log messages
+ *
+ * \param[in]   fmt     Formatted string
+ * \param[in]   ...     Viriable length argument
+ *
+ * \return              Number of chars printed
+ *
+ * \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_log_printf(const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TFM_LOG_RAW_H__ */
diff --git a/interface/src/log/tfm_log_raw.c b/interface/src/log/tfm_log_raw.c
new file mode 100644
index 0000000..1afb05b
--- /dev/null
+++ b/interface/src/log/tfm_log_raw.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include "log/tfm_log_raw.h"
+#include "uart_stdout.h"
+
+#define PRINT_BUFF_SIZE 32
+#define NUM_BUFF_SIZE 12
+
+struct formatted_buffer_t {
+    size_t pos;
+    uint8_t buf[PRINT_BUFF_SIZE];
+};
+
+const char hex_digits_lo[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                              '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+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. */
+        stdio_output_string(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_log_vprintf(const char *fmt, va_list ap)
+{
+    int count = 0;
+    struct formatted_buffer_t outputbuf;
+
+    outputbuf.pos = 0;
+
+    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 += stdio_output_string(outputbuf.buf, outputbuf.pos);
+    }
+
+    return count;
+}
+
+int tfm_log_printf(const char *fmt, ...)
+{
+    int count = 0;
+    va_list ap;
+
+    va_start(ap, fmt);
+    count = _tfm_log_vprintf(fmt, ap);
+    va_end(ap);
+
+    return count;
+}
diff --git a/platform/ext/common/uart_stdout.c b/platform/ext/common/uart_stdout.c
index 5a68697..ea892d6 100644
--- a/platform/ext/common/uart_stdout.c
+++ b/platform/ext/common/uart_stdout.c
@@ -28,7 +28,7 @@
 /* Imports USART driver */
 extern ARM_DRIVER_USART TFM_DRIVER_STDIO;
 
-static int uart_send_string(const unsigned char *str, uint32_t len)
+int stdio_output_string(const unsigned char *str, uint32_t len)
 {
     int32_t ret;
 
@@ -54,7 +54,7 @@
     (void)f;
 
     /* Send byte to USART */
-    (void)uart_send_string((const unsigned char *)&ch, 1);
+    (void)stdio_output_string((const unsigned char *)&ch, 1);
 
     /* Return character written */
     return ch;
@@ -66,13 +66,13 @@
     (void)fd;
 
     /* Send string and return the number of characters written */
-    return uart_send_string((const unsigned char *)str, (uint32_t)len);
+    return stdio_output_string((const unsigned char *)str, (uint32_t)len);
 }
 #elif defined(__ICCARM__)
 int putchar(int ch)
 {
     /* Send byte to USART */
-    (void)uart_send_string((const unsigned char *)&ch, 1);
+    (void)stdio_output_string((const unsigned char *)&ch, 1);
 
     /* Return character written */
     return ch;
@@ -104,4 +104,3 @@
     ret = TFM_DRIVER_STDIO.Uninitialize();
     ASSERT_HIGH(ret);
 }
-
diff --git a/platform/ext/common/uart_stdout.h b/platform/ext/common/uart_stdout.h
index 8feff31..d967c7c 100644
--- a/platform/ext/common/uart_stdout.h
+++ b/platform/ext/common/uart_stdout.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 ARM Limited
+ * Copyright (c) 2017-2019 ARM Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,4 +40,9 @@
  */
 void stdio_uninit(void);
 
+/**
+ * \brief Output buffer by STDIO.
+ */
+int stdio_output_string(const unsigned char *str, uint32_t len);
+
 #endif /* __UART_STDOUT_H__ */
diff --git a/secure_fw/lib/sprt/CMakeLists.inc b/secure_fw/lib/sprt/CMakeLists.inc
index 20aa1d6..05412d4 100644
--- a/secure_fw/lib/sprt/CMakeLists.inc
+++ b/secure_fw/lib/sprt/CMakeLists.inc
@@ -26,8 +26,12 @@
 
 set (LIBSPRT_C_SRC
     "${LIBSPRT_DIR}/tfm_libsprt_c_memcpy.c"
-    "${LIBSPRT_DIR}/tfm_libsprt_c_memmove.c")
+    "${LIBSPRT_DIR}/tfm_libsprt_c_memmove.c"
+    "${TFM_ROOT_DIR}/interface/src/log/tfm_log_raw.c")
 
 #Append all our source files to global lists.
 list(APPEND ALL_SRC_C_S ${LIBSPRT_C_SRC})
 unset(LIBSPRT_C_SRC)
+
+#Setting include directories
+embedded_include_directories(PATH ${TFM_ROOT_DIR}/interface/include ABSOLUTE)