blob: 5a1232763cee0f8f7ce92a7ce11359d63a932aea [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "hf/dlog.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010010
11#include <stdbool.h>
12#include <stddef.h>
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010013
Andrew Scull18c78fc2018-08-20 12:57:41 +010014#include "hf/spinlock.h"
Karl Meakin70894da2024-03-30 21:06:12 +000015#include "hf/static_assert.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010016#include "hf/std.h"
David Brazdil52230432020-01-27 15:08:34 +000017#include "hf/stdout.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018
Karl Meakine980e612024-03-28 17:46:32 +000019enum { DLOG_MAX_STRING_LENGTH = 64 };
20
21/* Keep fields aligned */
Andrew Scull4f170f52018-07-19 12:58:20 +010022/* clang-format off */
Karl Meakine980e612024-03-28 17:46:32 +000023struct format_flags {
24 bool minus : 1;
25 bool plus : 1;
26 bool space : 1;
27 bool alt : 1;
28 bool zero : 1;
29 bool upper : 1;
30 bool neg : 1;
31};
Andrew Scull4f170f52018-07-19 12:58:20 +010032/* clang-format on */
33
Karl Meakine980e612024-03-28 17:46:32 +000034enum format_base {
Karl Meakin7efc8372024-04-12 17:06:32 +010035 base2 = 2,
Karl Meakine980e612024-03-28 17:46:32 +000036 base8 = 8,
37 base10 = 10,
38 base16 = 16,
39};
40
Karl Meakin70894da2024-03-30 21:06:12 +000041enum format_length {
42 length8 = 8,
43 length16 = 16,
44 length32 = 32,
45 length64 = 64,
46};
47
48static_assert(sizeof(char) == sizeof(uint8_t),
49 "dlog expects char to be 8 bits wide");
50static_assert(sizeof(short) == sizeof(uint16_t),
51 "dlog expects short to be 16 bits wide");
52static_assert(sizeof(int) == sizeof(uint32_t),
53 "dlog expects int to be 32 bits wide");
54static_assert(sizeof(long) == sizeof(uint64_t),
55 "dlog expects long to be 64 bits wide");
56static_assert(sizeof(long long) == sizeof(uint64_t),
57 "dlog expects long long to be 64 bits wide");
58static_assert(sizeof(intmax_t) == sizeof(uint64_t),
59 "dlog expects intmax_t to be 64 bits wide");
60static_assert(sizeof(size_t) == sizeof(uint64_t),
61 "dlog expects size_t to be 64 bits wide");
62static_assert(sizeof(ptrdiff_t) == sizeof(uint64_t),
63 "dlog expects ptrdiff_t to be 64 bits wide");
64
Andrew Scullfdd716e2018-12-20 05:37:31 +000065static bool dlog_lock_enabled = false;
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010066static struct spinlock sl = SPINLOCK_INIT;
67
Andrew Walbranf3ac84d2019-07-26 16:10:02 +010068/*
69 * These global variables for the log buffer are not static because a test needs
70 * to access them directly.
71 */
72size_t dlog_buffer_offset;
73char dlog_buffer[DLOG_BUFFER_SIZE];
74
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010075/**
76 * Takes the lock, if it is enabled.
77 */
78static void lock(void)
79{
80 if (dlog_lock_enabled) {
81 sl_lock(&sl);
82 }
83}
84
85/**
86 * Releases the lock, if it is enabled.
87 */
88static void unlock(void)
89{
90 if (dlog_lock_enabled) {
91 sl_unlock(&sl);
92 }
93}
Andrew Scullfdd716e2018-12-20 05:37:31 +000094
95/**
96 * Enables the lock protecting the serial device.
97 */
98void dlog_enable_lock(void)
99{
100 dlog_lock_enabled = true;
101}
102
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100103static void dlog_putchar(char c)
104{
105 dlog_buffer[dlog_buffer_offset] = c;
106 dlog_buffer_offset = (dlog_buffer_offset + 1) % DLOG_BUFFER_SIZE;
David Brazdil52230432020-01-27 15:08:34 +0000107 stdout_putchar(c);
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100108}
109
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100110/**
Karl Meakine980e612024-03-28 17:46:32 +0000111 * Prints a literal string (i.e. '%' is not interpreted specially) to the debug
112 * log.
113 *
114 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100115 */
116static size_t print_raw_string(const char *str)
117{
118 const char *c = str;
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000119
Karl Meakine980e612024-03-28 17:46:32 +0000120 for (; *c != '\0'; c++) {
121 dlog_putchar(*c);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100122 }
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000123
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100124 return c - str;
125}
126
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100127/**
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100128 * Prints a formatted string to the debug log. The format includes a minimum
129 * width, the fill character, and flags (whether to align to left or right).
130 *
131 * str is the full string, while suffix is a pointer within str that indicates
132 * where the suffix begins. This is used when printing right-aligned numbers
133 * with a zero fill; for example, -10 with width 4 should be padded to -010,
134 * so suffix would point to index one of the "-10" string .
Karl Meakind2ef6182024-05-22 11:23:12 +0100135 *
136 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100137 */
Karl Meakine980e612024-03-28 17:46:32 +0000138static size_t print_string(const char *str, const char *suffix,
139 size_t min_width, struct format_flags flags,
140 char fill)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100141{
Karl Meakind2ef6182024-05-22 11:23:12 +0100142 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100143 size_t len = suffix - str;
144
145 /* Print the string up to the beginning of the suffix. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100146 while (str != suffix) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100147 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100148 dlog_putchar(*str++);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100149 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100150
Karl Meakine980e612024-03-28 17:46:32 +0000151 if (flags.minus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100152 /* Left-aligned. Print suffix, then print padding if needed. */
153 len += print_raw_string(suffix);
Karl Meakine980e612024-03-28 17:46:32 +0000154 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100155 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100156 dlog_putchar(' ');
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100157 len++;
158 }
Karl Meakind2ef6182024-05-22 11:23:12 +0100159 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100160 }
161
162 /* Fill until we reach the desired length. */
Andrew Scull4a867bc2019-04-08 10:15:11 +0100163 len += strnlen_s(suffix, DLOG_MAX_STRING_LENGTH);
Karl Meakine980e612024-03-28 17:46:32 +0000164 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100165 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100166 dlog_putchar(fill);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100167 len++;
168 }
169
170 /* Now print the rest of the string. */
Karl Meakind2ef6182024-05-22 11:23:12 +0100171 chars_written += print_raw_string(suffix);
172 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100173}
174
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100175/**
Karl Meakine980e612024-03-28 17:46:32 +0000176 * Prints an integer to the debug log. The caller specifies the base, its
177 * minimum width and printf-style flags.
Karl Meakind2ef6182024-05-22 11:23:12 +0100178 *
179 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100180 */
Karl Meakine980e612024-03-28 17:46:32 +0000181static size_t print_int(size_t value, enum format_base base, size_t min_width,
182 struct format_flags flags)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100183{
Karl Meakin7efc8372024-04-12 17:06:32 +0100184 static const char *digits_lower = "0123456789abcdefxb";
185 static const char *digits_upper = "0123456789ABCDEFXB";
Karl Meakine980e612024-03-28 17:46:32 +0000186 const char *digits = flags.upper ? digits_upper : digits_lower;
Andrew Scull4a867bc2019-04-08 10:15:11 +0100187 char buf[DLOG_MAX_STRING_LENGTH];
Andrew Scullf3d45592018-09-20 14:30:22 +0100188 char *ptr = &buf[sizeof(buf) - 1];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100189 char *num;
190 *ptr = '\0';
191 do {
192 --ptr;
Karl Meakine980e612024-03-28 17:46:32 +0000193 *ptr = digits[value % base];
194 value /= base;
195 } while (value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100196
197 /* Num stores where the actual number begins. */
198 num = ptr;
199
200 /* Add prefix if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000201 if (flags.alt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100202 switch (base) {
Karl Meakine980e612024-03-28 17:46:32 +0000203 case base16:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100204 ptr -= 2;
205 ptr[0] = '0';
Karl Meakine980e612024-03-28 17:46:32 +0000206 ptr[1] = digits[16];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100207 break;
208
Karl Meakin7efc8372024-04-12 17:06:32 +0100209 case base2:
210 ptr -= 2;
211 ptr[0] = '0';
212 ptr[1] = digits[17];
213 break;
214
Karl Meakine980e612024-03-28 17:46:32 +0000215 case base8:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100216 ptr--;
217 *ptr = '0';
218 break;
Karl Meakine980e612024-03-28 17:46:32 +0000219
220 case base10:
221 /* do nothing */
222 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100223 }
224 }
225
226 /* Add sign if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000227 if (flags.neg) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100228 *--ptr = '-';
Karl Meakine980e612024-03-28 17:46:32 +0000229 } else if (flags.plus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100230 *--ptr = '+';
Karl Meakine980e612024-03-28 17:46:32 +0000231 } else if (flags.space) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100232 *--ptr = ' ';
Andrew Scull7364a8e2018-07-19 15:39:29 +0100233 }
Karl Meakine980e612024-03-28 17:46:32 +0000234 return print_string(ptr, num, min_width, flags, flags.zero ? '0' : ' ');
235}
236
237/**
238 * Parses the optional flags field of a printf-style format. Returns a pointer
239 * to the first non-flag character in the string.
240 */
241static const char *parse_flags(const char *fmt, struct format_flags *flags)
242{
243 for (;; fmt++) {
244 switch (*fmt) {
245 case '-':
246 flags->minus = true;
247 break;
248
249 case '+':
250 flags->plus = true;
251 break;
252
253 case ' ':
254 flags->space = true;
255 break;
256
257 case '#':
258 flags->alt = true;
259 break;
260
261 case '0':
262 flags->zero = true;
263 break;
264
265 default:
266 return fmt;
267 }
Andrew Scull7364a8e2018-07-19 15:39:29 +0100268 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100269}
270
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100271/**
Karl Meakin70894da2024-03-30 21:06:12 +0000272 * Parses the optional length modifier field of a printf-style format.
273 *
274 * Returns a pointer to the first non-length modifier character in the string.
275 */
276static const char *parse_length_modifier(const char *fmt,
277 enum format_length *length)
278{
279 switch (*fmt) {
280 case 'h':
281 fmt++;
282 if (*fmt == 'h') {
283 fmt++;
284 *length = length8;
285 } else {
286 *length = length16;
287 }
288 break;
289 case 'l':
290 fmt++;
291 if (*fmt == 'l') {
292 fmt++;
293 *length = length64;
294 } else {
295 *length = length64;
296 }
297 break;
298
299 case 'j':
300 case 'z':
301 case 't':
302 fmt++;
303 *length = length64;
304 break;
305
306 default:
307 *length = length32;
308 break;
309 }
310
311 return fmt;
312}
313
314/**
Karl Meakine980e612024-03-28 17:46:32 +0000315 * Parses the optional minimum width field of a printf-style format.
316 * If the width is negative, `flags.minus` is set.
317 *
318 * Returns a pointer to the first non-digit character in the string.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100319 */
Karl Meakine980e612024-03-28 17:46:32 +0000320static const char *parse_min_width(const char *fmt, va_list args,
321 struct format_flags *flags, int *min_width)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100322{
Karl Meakine980e612024-03-28 17:46:32 +0000323 int width = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100324
Karl Meakine980e612024-03-28 17:46:32 +0000325 /* Read minimum width from arguments. */
326 if (*fmt == '*') {
327 fmt++;
328 width = va_arg(args, int);
329 if (width < 0) {
330 width = -width;
331 flags->minus = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100332 }
Karl Meakine980e612024-03-28 17:46:32 +0000333 } else {
334 for (; *fmt >= '0' && *fmt <= '9'; fmt++) {
335 width = (width * 10) + (*fmt - '0');
336 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100337 }
Karl Meakine980e612024-03-28 17:46:32 +0000338
339 *min_width = width;
340
341 return fmt;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100342}
343
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100344/**
Karl Meakin70894da2024-03-30 21:06:12 +0000345 * Reinterpret an unsigned 64-bit integer as a potentially shorter unsigned
346 * integer according to the length modifier.
347 * Returns an unsigned integer suitable for passing to `print_int`.
348 */
349uint64_t reinterpret_unsigned_int(enum format_length length, uint64_t value)
350{
351 switch (length) {
352 case length8:
353 return (uint8_t)value;
354 case length16:
355 return (uint16_t)value;
356 case length32:
357 return (uint32_t)value;
358 case length64:
359 return value;
360 }
361}
362
363/**
364 * Reinterpret an unsigned 64-bit integer as a potentially shorter signed
365 * integer according to the length modifier.
366 *
367 * Returns an *unsigned* integer suitable for passing to `print_int`. If the
368 * reinterpreted value is negative, `flags.neg` is set and the absolute value is
369 * returned.
370 */
371uint64_t reinterpret_signed_int(enum format_length length, uint64_t value,
372 struct format_flags *flags)
373{
374 int64_t signed_value = (int64_t)reinterpret_unsigned_int(length, value);
375
376 switch (length) {
377 case length8:
378 if ((int8_t)signed_value < 0) {
379 flags->neg = true;
380 signed_value = (-signed_value) & 0xFF;
381 }
382 break;
383 case length16:
384 if ((int16_t)signed_value < 0) {
385 flags->neg = true;
386 signed_value = (-signed_value) & 0xFFFF;
387 }
388 break;
389 case length32:
390 if ((int32_t)signed_value < 0) {
391 flags->neg = true;
392 signed_value = (-signed_value) & 0xFFFFFFFF;
393 }
394 break;
395 case length64:
396 if ((int64_t)signed_value < 0) {
397 flags->neg = true;
398 signed_value = -signed_value;
399 }
400 break;
401 }
402
403 return signed_value;
404}
405
406/**
Andrew Scullfdd716e2018-12-20 05:37:31 +0000407 * Same as "dlog", except that arguments are passed as a va_list
Karl Meakind2ef6182024-05-22 11:23:12 +0100408 *
409 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100410 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100411size_t vdlog(const char *fmt, va_list args)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100412{
Karl Meakind2ef6182024-05-22 11:23:12 +0100413 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100414
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100415 lock();
Andrew Scullfdd716e2018-12-20 05:37:31 +0000416
Karl Meakine980e612024-03-28 17:46:32 +0000417 while (*fmt != '\0') {
418 switch (*fmt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100419 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100420 chars_written++;
Karl Meakine980e612024-03-28 17:46:32 +0000421 dlog_putchar(*fmt);
422 fmt++;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100423 break;
424
Karl Meakine980e612024-03-28 17:46:32 +0000425 case '%': {
426 struct format_flags flags = {0};
427 int min_width = 0;
Karl Meakin70894da2024-03-30 21:06:12 +0000428 enum format_length length = length32;
429 uint64_t value;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100430
Karl Meakine980e612024-03-28 17:46:32 +0000431 fmt++;
432 fmt = parse_flags(fmt, &flags);
433 fmt = parse_min_width(fmt, args, &flags, &min_width);
Karl Meakin70894da2024-03-30 21:06:12 +0000434 fmt = parse_length_modifier(fmt, &length);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100435
436 /* Handle the format specifier. */
Karl Meakine980e612024-03-28 17:46:32 +0000437 switch (*fmt) {
438 case '%':
439 fmt++;
440 chars_written++;
441 dlog_putchar('%');
442 break;
443
444 case 'c': {
445 char str[2] = {va_arg(args, int), 0};
446
447 fmt++;
448 chars_written += print_string(
449 str, str, min_width, flags, ' ');
450 break;
451 }
452
Andrew Scull4f170f52018-07-19 12:58:20 +0100453 case 's': {
454 char *str = va_arg(args, char *);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000455
Karl Meakine980e612024-03-28 17:46:32 +0000456 fmt++;
457 chars_written += print_string(
458 str, str, min_width, flags, ' ');
459 break;
460 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100461
462 case 'd':
Andrew Scull4f170f52018-07-19 12:58:20 +0100463 case 'i': {
Karl Meakine980e612024-03-28 17:46:32 +0000464 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000465 value = va_arg(args, uint64_t);
466 value = reinterpret_signed_int(length, value,
467 &flags);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000468
Karl Meakin70894da2024-03-30 21:06:12 +0000469 chars_written += print_int(value, base10,
Karl Meakine980e612024-03-28 17:46:32 +0000470 min_width, flags);
471 break;
472 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100473
Karl Meakin7efc8372024-04-12 17:06:32 +0100474 case 'b':
475 fmt++;
476 value = va_arg(args, uint64_t);
477 value = reinterpret_unsigned_int(length, value);
478
479 chars_written += print_int(value, base2,
480 min_width, flags);
481 break;
482
483 case 'B':
484 fmt++;
485 flags.upper = true;
486 value = va_arg(args, uint64_t);
487 value = reinterpret_unsigned_int(length, value);
488
489 chars_written += print_int(value, base2,
490 min_width, flags);
491 break;
492
Karl Meakin70894da2024-03-30 21:06:12 +0000493 case 'o':
Karl Meakine980e612024-03-28 17:46:32 +0000494 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000495 value = va_arg(args, uint64_t);
496 value = reinterpret_unsigned_int(length, value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100497
Karl Meakin70894da2024-03-30 21:06:12 +0000498 chars_written += print_int(value, base8,
499 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100500 break;
501
502 case 'x':
Karl Meakine980e612024-03-28 17:46:32 +0000503 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000504 value = va_arg(args, uint64_t);
505 value = reinterpret_unsigned_int(length, value);
506
507 chars_written += print_int(value, base16,
508 min_width, flags);
509 break;
510
511 case 'X':
512 fmt++;
513 flags.upper = true;
514 value = va_arg(args, uint64_t);
515 value = reinterpret_unsigned_int(length, value);
516
517 chars_written += print_int(value, base16,
518 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100519 break;
520
521 case 'u':
Karl Meakine980e612024-03-28 17:46:32 +0000522 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000523 value = va_arg(args, uint64_t);
524 value = reinterpret_unsigned_int(length, value);
525
526 chars_written += print_int(value, base10,
527 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100528 break;
529
Karl Meakin70894da2024-03-30 21:06:12 +0000530 case 'p':
Karl Meakine980e612024-03-28 17:46:32 +0000531 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000532 value = va_arg(args, uint64_t);
533 min_width = sizeof(size_t) * 2 + 2;
534 flags.zero = true;
535 flags.alt = true;
536
537 chars_written += print_int(value, base16,
538 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100539 break;
540
541 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100542 chars_written = -1;
543 goto out;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100544 }
Karl Meakine980e612024-03-28 17:46:32 +0000545 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100546 }
547 }
Karl Meakine980e612024-03-28 17:46:32 +0000548
Karl Meakind2ef6182024-05-22 11:23:12 +0100549out:
Kathleen Capellafd306bb2023-03-17 18:14:01 -0400550 stdout_flush();
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100551 unlock();
Karl Meakind2ef6182024-05-22 11:23:12 +0100552 return chars_written;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100553}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100554
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100555/**
556 * Prints the given format string to the debug log.
Karl Meakind2ef6182024-05-22 11:23:12 +0100557 *
Karl Meakine980e612024-03-28 17:46:32 +0000558 * The format string supported is the same as described in
559 * https://en.cppreference.com/w/c/io/fprintf, with the following exceptions:
560 * - Floating-point formatters (`%f`, `%F`, `%e`, `%E`, `%a`, `%A`, `%g`, `%G`,
561 * `%L`) are not supported because floats are not used in Hafnium and
562 * formatting them is too complicated.
563 * - `%n` is not supported because it is rarely used and potentially dangerous.
564 * - Precision modifiers (`%.*` and `%.` followed by an integer) are not
565 * supported.
566 *
Karl Meakind2ef6182024-05-22 11:23:12 +0100567 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100568 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100569size_t dlog(const char *fmt, ...)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100570{
Karl Meakind2ef6182024-05-22 11:23:12 +0100571 size_t chars_written = 0;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100572 va_list args;
573
574 va_start(args, fmt);
Karl Meakind2ef6182024-05-22 11:23:12 +0100575 chars_written = vdlog(fmt, args);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100576 va_end(args);
Karl Meakind2ef6182024-05-22 11:23:12 +0100577 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100578}