blob: 3d4abd90dc6987464bc80347253c3e9bbae973ad [file] [log] [blame]
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +01001/*
2 * Copyright (c) 2017-2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7/*
8 * Based on TF-A common/tf_log.c
9 */
10
11#include <assert.h>
12#include <stdarg.h>
13#include <stdint.h>
14#include <stddef.h>
15
16#include "tfm_vprintf.h"
17
18static inline const char *get_log_prefix(uint8_t log_level)
19{
20 switch(log_level) {
21 case LOG_LEVEL_ERROR:
22 return "[ERR]";
23 case LOG_LEVEL_NOTICE:
24 return "[NOT]";
25 case LOG_LEVEL_WARNING:
26 return "[WAR]";
27 case LOG_LEVEL_INFO:
28 return "[INF]";
29 case LOG_LEVEL_VERBOSE:
30 return "[VER]";
31 default:
32 /* String must start with LOG_MARKER_* */
33 assert(0);
34 }
35}
36
37static void output_char(tfm_log_output_str output_func, void *priv, char c)
38{
39 output_func(priv, (const unsigned char *)&c, 1);
40}
41
42static void output_str(tfm_log_output_str output_func, void *priv, const char *str)
43{
44 uint32_t len = 0;
45 const char *str_ptr = str;
46
47 while (*str_ptr++ != '\0') {
48 len++;
49 }
50
51 output_func(priv, (const unsigned char *)str, len);
52}
53
54static void output_val(tfm_log_output_str output_func, void *priv, uint32_t val,
55 uint16_t num_padding, bool zero_padding)
56{
57 uint8_t digit, chars_to_print;
58 uint16_t i;
59 char buf[9];
60 char *const buf_end = &buf[sizeof(buf) - 1];
61 char *buf_ptr = buf_end;
62 const char pad_char = zero_padding ? '0' : ' ';
63
64 /* Ensure buffer ends with NULL character */
65 *buf_ptr-- = '\0';
66
67 do {
68 digit = val & 0xf;
69
70 if (digit < 10) {
71 *buf_ptr-- = '0' + digit;
72 } else {
73 *buf_ptr-- = 'a' + digit - 10;
74 }
75
76 val >>= 4;
77 } while (val);
78
79 chars_to_print = (buf_end - 1) - buf_ptr;
80 if (num_padding > chars_to_print) {
81 num_padding -= chars_to_print;
82 } else {
83 num_padding = 0;
84 }
85
86 for (i = 0; i < num_padding; i++) {
87 output_char(output_func, priv, pad_char);
88 }
89
90 output_str(output_func, priv, buf_ptr + 1);
91}
92
93/* Basic vprintf, understands:
94 * %s: output string
95 * %x: output uint32_t in hex
96 */
97static void tfm_vprintf_internal(tfm_log_output_str output_func,
98 void *priv, const char *fmt, va_list args)
99{
100 char c;
101 bool formatting = false;
102 uint16_t num_padding = 0;
103 bool zero_padding = false;
104
105 while ((c = *fmt++) != '\0') {
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100106 if (!formatting) {
Jackson Cooper-Driver65940702024-09-04 15:57:12 +0000107 if (c == '%') {
108 zero_padding = false;
109 num_padding = 0;
110 formatting = true;
111 } else {
112 if (c == '\n') {
113 output_char(output_func, priv, '\r');
114 }
115 output_char(output_func, priv, c);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100116 }
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100117 continue;
118 }
119
120 switch (c) {
121 case 'l':
122 continue;
123 case 'x':
124 output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding);
125 break;
126 case 's':
127 output_str(output_func, priv, va_arg(args, char *));
128 break;
129 case '0':
130 if (num_padding == 0) {
131 zero_padding = true;
132 continue;
133 }
134 /* fallthrough */
135 case '1':
136 case '2':
137 case '3':
138 case '4':
139 case '5':
140 case '6':
141 case '7':
142 case '8':
143 case '9':
144 num_padding *= 10;
145 num_padding += c - '0';
146 continue;
147 case '%':
148 output_char(output_func, priv, '%');
149 break;
150 default:
151 output_str(output_func, priv, "[Unsupported]");
152 }
153
154 formatting = false;
155 }
156}
157
158void tfm_vprintf(tfm_log_output_str output_func, void *priv, const char *fmt, va_list args)
159{
160 uint8_t log_level;
161 const char spacer = ' ';
162
163 /* We expect the LOG_MARKER_* macro as the first character */
164 log_level = fmt[0];
165 fmt++;
166
167 output_str(output_func, priv, get_log_prefix(log_level));
168 output_char(output_func, priv, spacer);
169
170 tfm_vprintf_internal(output_func, priv, fmt, args);
171}