blob: 02164eee27015b19969b895902cfafbf5e7b0340 [file] [log] [blame]
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +01001/*
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +00002 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +01003 *
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);
Jackson Cooper-Driver57a13c62024-09-04 16:01:45 +000034 return NULL;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010035 }
36}
37
38static void output_char(tfm_log_output_str output_func, void *priv, char c)
39{
Antonio de Angelis4f021312024-11-09 21:02:33 +000040 output_func(priv, &c, 1);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010041}
42
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000043static inline void output_padding_chars(tfm_log_output_str output_func, void *priv,
44 uint16_t num_padding, char pad_char)
45{
46 uint16_t i;
47
48 for (i = 0; i < num_padding; i++) {
49 output_char(output_func, priv, pad_char);
50 }
51}
52
53static void output_str(tfm_log_output_str output_func, void *priv, const char *str, uint32_t len,
54 uint16_t num_padding, bool left_aligned, char pad_char,
55 bool calculate_length)
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010056{
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010057 const char *str_ptr = str;
58
Jackson Cooper-Driver9db08832025-01-24 11:24:20 +000059 if (calculate_length) {
60 len = 0;
61 while (*str_ptr++ != '\0') {
62 len++;
63 }
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010064 }
65
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000066 if (num_padding > len) {
67 num_padding -= len;
68 } else {
69 num_padding = 0;
70 }
71
72 if (!left_aligned) {
73 output_padding_chars(output_func, priv, num_padding, pad_char);
74 }
75
Antonio de Angelis4f021312024-11-09 21:02:33 +000076 output_func(priv, str, len);
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000077
78 if (left_aligned) {
79 output_padding_chars(output_func, priv, num_padding, pad_char);
80 }
81}
82
83static void output_str_not_formatted(tfm_log_output_str output_func, void *priv, const char *str)
84{
85 output_str(output_func, priv, str, 0, 0, false, 0, true);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010086}
87
88static void output_val(tfm_log_output_str output_func, void *priv, uint32_t val,
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000089 uint16_t num_padding, bool zero_padding, bool left_aligned, uint8_t base,
90 bool signed_specifier)
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010091{
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000092 uint8_t digit;
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +000093 /* uint32_t has maximum value of 4,294,967,295. Require enough space in buffer
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000094 * for 10 digits + '-'. Note that the buffer does not need to be NULL terminated
95 * as we pass the string length to output_str */
96 char buf[11] = { 0 };
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010097 char *const buf_end = &buf[sizeof(buf) - 1];
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +000098 char *buf_ptr = buf_end;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +010099 const char pad_char = zero_padding ? '0' : ' ';
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000100 const char negative_char = '-';
101 bool negative = false;
102
103 if (signed_specifier && ((int32_t)val < 0)) {
104 val = -val;
105 negative = true;
106 }
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100107
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100108 do {
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000109 digit = val % base;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100110
111 if (digit < 10) {
112 *buf_ptr-- = '0' + digit;
113 } else {
114 *buf_ptr-- = 'a' + digit - 10;
115 }
116
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000117 val /= base;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100118 } while (val);
119
Jackson Cooper-Driver9db08832025-01-24 11:24:20 +0000120 if (negative) {
121 if (!zero_padding) {
122 *buf_ptr-- = negative_char;
123 } else {
124 output_char(output_func, priv, negative_char);
125 }
126 }
127
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000128 output_str(output_func, priv, buf_ptr + 1, buf_end - buf_ptr, num_padding, left_aligned,
129 pad_char, false);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100130}
131
132/* Basic vprintf, understands:
133 * %s: output string
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000134 * %u: output uint32_t in decimal
135 * %d: output int32_t in decimal
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100136 * %x: output uint32_t in hex
137 */
138static void tfm_vprintf_internal(tfm_log_output_str output_func,
139 void *priv, const char *fmt, va_list args)
140{
141 char c;
142 bool formatting = false;
143 uint16_t num_padding = 0;
144 bool zero_padding = false;
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000145 bool left_aligned = false;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100146
147 while ((c = *fmt++) != '\0') {
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100148 if (!formatting) {
Jackson Cooper-Driver65940702024-09-04 15:57:12 +0000149 if (c == '%') {
150 zero_padding = false;
151 num_padding = 0;
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000152 left_aligned = false;
Jackson Cooper-Driver65940702024-09-04 15:57:12 +0000153 formatting = true;
154 } else {
155 if (c == '\n') {
156 output_char(output_func, priv, '\r');
157 }
158 output_char(output_func, priv, c);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100159 }
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100160 continue;
161 }
162
163 switch (c) {
164 case 'l':
165 continue;
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000166 case 'u':
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000167 output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
168 left_aligned, 10, false);
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000169 break;
170 case 'd':
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000171 output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
172 left_aligned, 10, true);
Jackson Cooper-Driverd6ddcb82025-01-21 11:39:28 +0000173 break;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100174 case 'x':
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000175 output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
176 left_aligned, 16, false);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100177 break;
178 case 's':
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000179 output_str(output_func, priv, va_arg(args, char *), 0, num_padding, left_aligned, ' ',
180 true);
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100181 break;
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000182 case '-':
183 left_aligned = true;
184 continue;
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100185 case '0':
186 if (num_padding == 0) {
187 zero_padding = true;
188 continue;
189 }
190 /* fallthrough */
191 case '1':
192 case '2':
193 case '3':
194 case '4':
195 case '5':
196 case '6':
197 case '7':
198 case '8':
199 case '9':
200 num_padding *= 10;
201 num_padding += c - '0';
202 continue;
203 case '%':
204 output_char(output_func, priv, '%');
205 break;
206 default:
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000207 output_str_not_formatted(output_func, priv, "[Unsupported]");
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100208 }
209
210 formatting = false;
211 }
212}
213
214void tfm_vprintf(tfm_log_output_str output_func, void *priv, const char *fmt, va_list args)
215{
216 uint8_t log_level;
217 const char spacer = ' ';
218
219 /* We expect the LOG_MARKER_* macro as the first character */
220 log_level = fmt[0];
221 fmt++;
222
Jackson Cooper-Driver44a51532025-03-14 10:24:22 +0000223 output_str_not_formatted(output_func, priv, get_log_prefix(log_level));
Jackson Cooper-Drivered984c92024-08-14 16:12:40 +0100224 output_char(output_func, priv, spacer);
225
226 tfm_vprintf_internal(output_func, priv, fmt, args);
227}