blob: 0c9b5b77ed0e1e2d89a94e0ba44466ac273d0aab [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
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010011#include <stddef.h>
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010012
Andrew Scull18c78fc2018-08-20 12:57:41 +010013#include "hf/spinlock.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010014#include "hf/std.h"
David Brazdil52230432020-01-27 15:08:34 +000015#include "hf/stdout.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010016
Karl Meakine980e612024-03-28 17:46:32 +000017enum { DLOG_MAX_STRING_LENGTH = 64 };
18
19/* Keep fields aligned */
Andrew Scull4f170f52018-07-19 12:58:20 +010020/* clang-format off */
Karl Meakine980e612024-03-28 17:46:32 +000021struct format_flags {
22 bool minus : 1;
23 bool plus : 1;
24 bool space : 1;
25 bool alt : 1;
26 bool zero : 1;
27 bool upper : 1;
28 bool neg : 1;
29};
Andrew Scull4f170f52018-07-19 12:58:20 +010030/* clang-format on */
31
Karl Meakine980e612024-03-28 17:46:32 +000032enum format_base {
Karl Meakin7efc8372024-04-12 17:06:32 +010033 base2 = 2,
Karl Meakine980e612024-03-28 17:46:32 +000034 base8 = 8,
35 base10 = 10,
36 base16 = 16,
37};
38
Karl Meakin70894da2024-03-30 21:06:12 +000039enum format_length {
40 length8 = 8,
41 length16 = 16,
42 length32 = 32,
43 length64 = 64,
44};
45
46static_assert(sizeof(char) == sizeof(uint8_t),
47 "dlog expects char to be 8 bits wide");
48static_assert(sizeof(short) == sizeof(uint16_t),
49 "dlog expects short to be 16 bits wide");
50static_assert(sizeof(int) == sizeof(uint32_t),
51 "dlog expects int to be 32 bits wide");
52static_assert(sizeof(long) == sizeof(uint64_t),
53 "dlog expects long to be 64 bits wide");
54static_assert(sizeof(long long) == sizeof(uint64_t),
55 "dlog expects long long to be 64 bits wide");
56static_assert(sizeof(intmax_t) == sizeof(uint64_t),
57 "dlog expects intmax_t to be 64 bits wide");
58static_assert(sizeof(size_t) == sizeof(uint64_t),
59 "dlog expects size_t to be 64 bits wide");
60static_assert(sizeof(ptrdiff_t) == sizeof(uint64_t),
61 "dlog expects ptrdiff_t to be 64 bits wide");
62
Andrew Scullfdd716e2018-12-20 05:37:31 +000063static bool dlog_lock_enabled = false;
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010064static struct spinlock sl = SPINLOCK_INIT;
65
Andrew Walbranf3ac84d2019-07-26 16:10:02 +010066/*
67 * These global variables for the log buffer are not static because a test needs
68 * to access them directly.
69 */
70size_t dlog_buffer_offset;
71char dlog_buffer[DLOG_BUFFER_SIZE];
72
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010073/**
74 * Takes the lock, if it is enabled.
75 */
76static void lock(void)
77{
78 if (dlog_lock_enabled) {
79 sl_lock(&sl);
80 }
81}
82
83/**
84 * Releases the lock, if it is enabled.
85 */
86static void unlock(void)
87{
88 if (dlog_lock_enabled) {
89 sl_unlock(&sl);
90 }
91}
Andrew Scullfdd716e2018-12-20 05:37:31 +000092
93/**
94 * Enables the lock protecting the serial device.
95 */
96void dlog_enable_lock(void)
97{
98 dlog_lock_enabled = true;
99}
100
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100101static void dlog_putchar(char c)
102{
103 dlog_buffer[dlog_buffer_offset] = c;
104 dlog_buffer_offset = (dlog_buffer_offset + 1) % DLOG_BUFFER_SIZE;
David Brazdil52230432020-01-27 15:08:34 +0000105 stdout_putchar(c);
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100106}
107
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100108/**
Karl Meakine980e612024-03-28 17:46:32 +0000109 * Prints a literal string (i.e. '%' is not interpreted specially) to the debug
110 * log.
111 *
112 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100113 */
114static size_t print_raw_string(const char *str)
115{
116 const char *c = str;
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000117
Karl Meakine980e612024-03-28 17:46:32 +0000118 for (; *c != '\0'; c++) {
119 dlog_putchar(*c);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100120 }
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000121
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100122 return c - str;
123}
124
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100125/**
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100126 * Prints a formatted string to the debug log. The format includes a minimum
127 * width, the fill character, and flags (whether to align to left or right).
128 *
129 * str is the full string, while suffix is a pointer within str that indicates
130 * where the suffix begins. This is used when printing right-aligned numbers
131 * with a zero fill; for example, -10 with width 4 should be padded to -010,
132 * so suffix would point to index one of the "-10" string .
Karl Meakind2ef6182024-05-22 11:23:12 +0100133 *
134 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100135 */
Karl Meakine980e612024-03-28 17:46:32 +0000136static size_t print_string(const char *str, const char *suffix,
137 size_t min_width, struct format_flags flags,
138 char fill)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100139{
Karl Meakind2ef6182024-05-22 11:23:12 +0100140 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100141 size_t len = suffix - str;
142
143 /* Print the string up to the beginning of the suffix. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100144 while (str != suffix) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100145 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100146 dlog_putchar(*str++);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100147 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100148
Karl Meakine980e612024-03-28 17:46:32 +0000149 if (flags.minus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100150 /* Left-aligned. Print suffix, then print padding if needed. */
151 len += print_raw_string(suffix);
Karl Meakine980e612024-03-28 17:46:32 +0000152 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100153 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100154 dlog_putchar(' ');
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100155 len++;
156 }
Karl Meakind2ef6182024-05-22 11:23:12 +0100157 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100158 }
159
160 /* Fill until we reach the desired length. */
Andrew Scull4a867bc2019-04-08 10:15:11 +0100161 len += strnlen_s(suffix, DLOG_MAX_STRING_LENGTH);
Karl Meakine980e612024-03-28 17:46:32 +0000162 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100163 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100164 dlog_putchar(fill);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100165 len++;
166 }
167
168 /* Now print the rest of the string. */
Karl Meakind2ef6182024-05-22 11:23:12 +0100169 chars_written += print_raw_string(suffix);
170 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100171}
172
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100173/**
Karl Meakine980e612024-03-28 17:46:32 +0000174 * Prints an integer to the debug log. The caller specifies the base, its
175 * minimum width and printf-style flags.
Karl Meakind2ef6182024-05-22 11:23:12 +0100176 *
177 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100178 */
Karl Meakine980e612024-03-28 17:46:32 +0000179static size_t print_int(size_t value, enum format_base base, size_t min_width,
180 struct format_flags flags)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100181{
Karl Meakin7efc8372024-04-12 17:06:32 +0100182 static const char *digits_lower = "0123456789abcdefxb";
183 static const char *digits_upper = "0123456789ABCDEFXB";
Karl Meakine980e612024-03-28 17:46:32 +0000184 const char *digits = flags.upper ? digits_upper : digits_lower;
Andrew Scull4a867bc2019-04-08 10:15:11 +0100185 char buf[DLOG_MAX_STRING_LENGTH];
Andrew Scullf3d45592018-09-20 14:30:22 +0100186 char *ptr = &buf[sizeof(buf) - 1];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100187 char *num;
188 *ptr = '\0';
189 do {
190 --ptr;
Karl Meakine980e612024-03-28 17:46:32 +0000191 *ptr = digits[value % base];
192 value /= base;
193 } while (value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100194
195 /* Num stores where the actual number begins. */
196 num = ptr;
197
198 /* Add prefix if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000199 if (flags.alt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100200 switch (base) {
Karl Meakine980e612024-03-28 17:46:32 +0000201 case base16:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100202 ptr -= 2;
203 ptr[0] = '0';
Karl Meakine980e612024-03-28 17:46:32 +0000204 ptr[1] = digits[16];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100205 break;
206
Karl Meakin7efc8372024-04-12 17:06:32 +0100207 case base2:
208 ptr -= 2;
209 ptr[0] = '0';
210 ptr[1] = digits[17];
211 break;
212
Karl Meakine980e612024-03-28 17:46:32 +0000213 case base8:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100214 ptr--;
215 *ptr = '0';
216 break;
Karl Meakine980e612024-03-28 17:46:32 +0000217
218 case base10:
219 /* do nothing */
220 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100221 }
222 }
223
224 /* Add sign if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000225 if (flags.neg) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100226 *--ptr = '-';
Karl Meakine980e612024-03-28 17:46:32 +0000227 } else if (flags.plus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100228 *--ptr = '+';
Karl Meakine980e612024-03-28 17:46:32 +0000229 } else if (flags.space) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100230 *--ptr = ' ';
Andrew Scull7364a8e2018-07-19 15:39:29 +0100231 }
Karl Meakine980e612024-03-28 17:46:32 +0000232 return print_string(ptr, num, min_width, flags, flags.zero ? '0' : ' ');
233}
234
235/**
236 * Parses the optional flags field of a printf-style format. Returns a pointer
237 * to the first non-flag character in the string.
238 */
239static const char *parse_flags(const char *fmt, struct format_flags *flags)
240{
241 for (;; fmt++) {
242 switch (*fmt) {
243 case '-':
244 flags->minus = true;
245 break;
246
247 case '+':
248 flags->plus = true;
249 break;
250
251 case ' ':
252 flags->space = true;
253 break;
254
255 case '#':
256 flags->alt = true;
257 break;
258
259 case '0':
260 flags->zero = true;
261 break;
262
263 default:
264 return fmt;
265 }
Andrew Scull7364a8e2018-07-19 15:39:29 +0100266 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100267}
268
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100269/**
Karl Meakin70894da2024-03-30 21:06:12 +0000270 * Parses the optional length modifier field of a printf-style format.
271 *
272 * Returns a pointer to the first non-length modifier character in the string.
273 */
274static const char *parse_length_modifier(const char *fmt,
275 enum format_length *length)
276{
277 switch (*fmt) {
278 case 'h':
279 fmt++;
280 if (*fmt == 'h') {
281 fmt++;
282 *length = length8;
283 } else {
284 *length = length16;
285 }
286 break;
287 case 'l':
288 fmt++;
289 if (*fmt == 'l') {
290 fmt++;
291 *length = length64;
292 } else {
293 *length = length64;
294 }
295 break;
296
297 case 'j':
298 case 'z':
299 case 't':
300 fmt++;
301 *length = length64;
302 break;
303
304 default:
305 *length = length32;
306 break;
307 }
308
309 return fmt;
310}
311
312/**
Karl Meakine980e612024-03-28 17:46:32 +0000313 * Parses the optional minimum width field of a printf-style format.
314 * If the width is negative, `flags.minus` is set.
315 *
316 * Returns a pointer to the first non-digit character in the string.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100317 */
Karl Meakin1978e7a2024-11-20 13:56:58 +0000318static const char *parse_min_width(const char *fmt,
319 struct va_list_wrapper *args,
Karl Meakine980e612024-03-28 17:46:32 +0000320 struct format_flags *flags, int *min_width)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100321{
Karl Meakine980e612024-03-28 17:46:32 +0000322 int width = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100323
Karl Meakine980e612024-03-28 17:46:32 +0000324 /* Read minimum width from arguments. */
325 if (*fmt == '*') {
326 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000327 width = va_arg(args->va, int);
Karl Meakine980e612024-03-28 17:46:32 +0000328 if (width < 0) {
329 width = -width;
330 flags->minus = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100331 }
Karl Meakine980e612024-03-28 17:46:32 +0000332 } else {
333 for (; *fmt >= '0' && *fmt <= '9'; fmt++) {
334 width = (width * 10) + (*fmt - '0');
335 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100336 }
Karl Meakine980e612024-03-28 17:46:32 +0000337
338 *min_width = width;
339
340 return fmt;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100341}
342
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100343/**
Karl Meakin70894da2024-03-30 21:06:12 +0000344 * Reinterpret an unsigned 64-bit integer as a potentially shorter unsigned
345 * integer according to the length modifier.
346 * Returns an unsigned integer suitable for passing to `print_int`.
347 */
348uint64_t reinterpret_unsigned_int(enum format_length length, uint64_t value)
349{
350 switch (length) {
351 case length8:
352 return (uint8_t)value;
353 case length16:
354 return (uint16_t)value;
355 case length32:
356 return (uint32_t)value;
357 case length64:
358 return value;
359 }
360}
361
362/**
363 * Reinterpret an unsigned 64-bit integer as a potentially shorter signed
364 * integer according to the length modifier.
365 *
366 * Returns an *unsigned* integer suitable for passing to `print_int`. If the
367 * reinterpreted value is negative, `flags.neg` is set and the absolute value is
368 * returned.
369 */
370uint64_t reinterpret_signed_int(enum format_length length, uint64_t value,
371 struct format_flags *flags)
372{
373 int64_t signed_value = (int64_t)reinterpret_unsigned_int(length, value);
374
375 switch (length) {
376 case length8:
377 if ((int8_t)signed_value < 0) {
378 flags->neg = true;
379 signed_value = (-signed_value) & 0xFF;
380 }
381 break;
382 case length16:
383 if ((int16_t)signed_value < 0) {
384 flags->neg = true;
385 signed_value = (-signed_value) & 0xFFFF;
386 }
387 break;
388 case length32:
389 if ((int32_t)signed_value < 0) {
390 flags->neg = true;
391 signed_value = (-signed_value) & 0xFFFFFFFF;
392 }
393 break;
394 case length64:
Karl Meakin66a38bd2024-05-28 16:00:56 +0100395 if (signed_value < 0) {
Karl Meakin70894da2024-03-30 21:06:12 +0000396 flags->neg = true;
397 signed_value = -signed_value;
398 }
399 break;
400 }
401
402 return signed_value;
403}
404
405/**
Andrew Scullfdd716e2018-12-20 05:37:31 +0000406 * Same as "dlog", except that arguments are passed as a va_list
Karl Meakind2ef6182024-05-22 11:23:12 +0100407 *
408 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100409 */
Karl Meakin1978e7a2024-11-20 13:56:58 +0000410size_t vdlog(const char *fmt, struct va_list_wrapper *args)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100411{
Karl Meakind2ef6182024-05-22 11:23:12 +0100412 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100413
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100414 lock();
Andrew Scullfdd716e2018-12-20 05:37:31 +0000415
Karl Meakine980e612024-03-28 17:46:32 +0000416 while (*fmt != '\0') {
417 switch (*fmt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100418 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100419 chars_written++;
Karl Meakine980e612024-03-28 17:46:32 +0000420 dlog_putchar(*fmt);
421 fmt++;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100422 break;
423
Karl Meakine980e612024-03-28 17:46:32 +0000424 case '%': {
425 struct format_flags flags = {0};
426 int min_width = 0;
Karl Meakin70894da2024-03-30 21:06:12 +0000427 enum format_length length = length32;
428 uint64_t value;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100429
Karl Meakine980e612024-03-28 17:46:32 +0000430 fmt++;
431 fmt = parse_flags(fmt, &flags);
432 fmt = parse_min_width(fmt, args, &flags, &min_width);
Karl Meakin70894da2024-03-30 21:06:12 +0000433 fmt = parse_length_modifier(fmt, &length);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100434
435 /* Handle the format specifier. */
Karl Meakine980e612024-03-28 17:46:32 +0000436 switch (*fmt) {
437 case '%':
438 fmt++;
439 chars_written++;
440 dlog_putchar('%');
441 break;
442
443 case 'c': {
Karl Meakin1978e7a2024-11-20 13:56:58 +0000444 char str[2] = {va_arg(args->va, int), '\0'};
Karl Meakine980e612024-03-28 17:46:32 +0000445
446 fmt++;
447 chars_written += print_string(
448 str, str, min_width, flags, ' ');
449 break;
450 }
451
Andrew Scull4f170f52018-07-19 12:58:20 +0100452 case 's': {
Karl Meakin1978e7a2024-11-20 13:56:58 +0000453 char *str = va_arg(args->va, char *);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000454
Karl Meakine980e612024-03-28 17:46:32 +0000455 fmt++;
456 chars_written += print_string(
457 str, str, min_width, flags, ' ');
458 break;
459 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100460
461 case 'd':
Andrew Scull4f170f52018-07-19 12:58:20 +0100462 case 'i': {
Karl Meakine980e612024-03-28 17:46:32 +0000463 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000464 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000465 value = reinterpret_signed_int(length, value,
466 &flags);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000467
Karl Meakin70894da2024-03-30 21:06:12 +0000468 chars_written += print_int(value, base10,
Karl Meakine980e612024-03-28 17:46:32 +0000469 min_width, flags);
470 break;
471 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100472
Karl Meakin7efc8372024-04-12 17:06:32 +0100473 case 'b':
474 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000475 value = va_arg(args->va, uint64_t);
Karl Meakin7efc8372024-04-12 17:06:32 +0100476 value = reinterpret_unsigned_int(length, value);
477
478 chars_written += print_int(value, base2,
479 min_width, flags);
480 break;
481
482 case 'B':
483 fmt++;
484 flags.upper = true;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000485 value = va_arg(args->va, uint64_t);
Karl Meakin7efc8372024-04-12 17:06:32 +0100486 value = reinterpret_unsigned_int(length, value);
487
488 chars_written += print_int(value, base2,
489 min_width, flags);
490 break;
491
Karl Meakin70894da2024-03-30 21:06:12 +0000492 case 'o':
Karl Meakine980e612024-03-28 17:46:32 +0000493 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000494 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000495 value = reinterpret_unsigned_int(length, value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100496
Karl Meakin70894da2024-03-30 21:06:12 +0000497 chars_written += print_int(value, base8,
498 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100499 break;
500
501 case 'x':
Karl Meakine980e612024-03-28 17:46:32 +0000502 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000503 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000504 value = reinterpret_unsigned_int(length, value);
505
506 chars_written += print_int(value, base16,
507 min_width, flags);
508 break;
509
510 case 'X':
511 fmt++;
512 flags.upper = true;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000513 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000514 value = reinterpret_unsigned_int(length, value);
515
516 chars_written += print_int(value, base16,
517 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100518 break;
519
520 case 'u':
Karl Meakine980e612024-03-28 17:46:32 +0000521 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000522 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000523 value = reinterpret_unsigned_int(length, value);
524
525 chars_written += print_int(value, base10,
526 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100527 break;
528
Karl Meakin70894da2024-03-30 21:06:12 +0000529 case 'p':
Karl Meakine980e612024-03-28 17:46:32 +0000530 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000531 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000532 min_width = sizeof(size_t) * 2 + 2;
533 flags.zero = true;
534 flags.alt = true;
535
536 chars_written += print_int(value, base16,
537 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100538 break;
539
540 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100541 chars_written = -1;
542 goto out;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100543 }
Karl Meakine980e612024-03-28 17:46:32 +0000544 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100545 }
546 }
Karl Meakine980e612024-03-28 17:46:32 +0000547
Karl Meakind2ef6182024-05-22 11:23:12 +0100548out:
Kathleen Capellafd306bb2023-03-17 18:14:01 -0400549 stdout_flush();
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100550 unlock();
Karl Meakind2ef6182024-05-22 11:23:12 +0100551 return chars_written;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100552}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100553
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100554/**
555 * Prints the given format string to the debug log.
Karl Meakind2ef6182024-05-22 11:23:12 +0100556 *
Karl Meakine980e612024-03-28 17:46:32 +0000557 * The format string supported is the same as described in
558 * https://en.cppreference.com/w/c/io/fprintf, with the following exceptions:
559 * - Floating-point formatters (`%f`, `%F`, `%e`, `%E`, `%a`, `%A`, `%g`, `%G`,
560 * `%L`) are not supported because floats are not used in Hafnium and
561 * formatting them is too complicated.
562 * - `%n` is not supported because it is rarely used and potentially dangerous.
563 * - Precision modifiers (`%.*` and `%.` followed by an integer) are not
564 * supported.
565 *
Karl Meakind2ef6182024-05-22 11:23:12 +0100566 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100567 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100568size_t dlog(const char *fmt, ...)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100569{
Karl Meakind2ef6182024-05-22 11:23:12 +0100570 size_t chars_written = 0;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000571 struct va_list_wrapper args;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100572
Karl Meakin1978e7a2024-11-20 13:56:58 +0000573 va_start(args.va, fmt);
574 chars_written = vdlog(fmt, &args);
575 va_end(args.va);
Karl Meakind2ef6182024-05-22 11:23:12 +0100576 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100577}