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)