blob: aa174d13419e130bafc7d54443ab627dc36973ef [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 Meakin1978e7a2024-11-20 13:56:58 +0000320static const char *parse_min_width(const char *fmt,
321 struct va_list_wrapper *args,
Karl Meakine980e612024-03-28 17:46:32 +0000322 struct format_flags *flags, int *min_width)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100323{
Karl Meakine980e612024-03-28 17:46:32 +0000324 int width = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100325
Karl Meakine980e612024-03-28 17:46:32 +0000326 /* Read minimum width from arguments. */
327 if (*fmt == '*') {
328 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000329 width = va_arg(args->va, int);
Karl Meakine980e612024-03-28 17:46:32 +0000330 if (width < 0) {
331 width = -width;
332 flags->minus = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100333 }
Karl Meakine980e612024-03-28 17:46:32 +0000334 } else {
335 for (; *fmt >= '0' && *fmt <= '9'; fmt++) {
336 width = (width * 10) + (*fmt - '0');
337 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100338 }
Karl Meakine980e612024-03-28 17:46:32 +0000339
340 *min_width = width;
341
342 return fmt;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100343}
344
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100345/**
Karl Meakin70894da2024-03-30 21:06:12 +0000346 * Reinterpret an unsigned 64-bit integer as a potentially shorter unsigned
347 * integer according to the length modifier.
348 * Returns an unsigned integer suitable for passing to `print_int`.
349 */
350uint64_t reinterpret_unsigned_int(enum format_length length, uint64_t value)
351{
352 switch (length) {
353 case length8:
354 return (uint8_t)value;
355 case length16:
356 return (uint16_t)value;
357 case length32:
358 return (uint32_t)value;
359 case length64:
360 return value;
361 }
362}
363
364/**
365 * Reinterpret an unsigned 64-bit integer as a potentially shorter signed
366 * integer according to the length modifier.
367 *
368 * Returns an *unsigned* integer suitable for passing to `print_int`. If the
369 * reinterpreted value is negative, `flags.neg` is set and the absolute value is
370 * returned.
371 */
372uint64_t reinterpret_signed_int(enum format_length length, uint64_t value,
373 struct format_flags *flags)
374{
375 int64_t signed_value = (int64_t)reinterpret_unsigned_int(length, value);
376
377 switch (length) {
378 case length8:
379 if ((int8_t)signed_value < 0) {
380 flags->neg = true;
381 signed_value = (-signed_value) & 0xFF;
382 }
383 break;
384 case length16:
385 if ((int16_t)signed_value < 0) {
386 flags->neg = true;
387 signed_value = (-signed_value) & 0xFFFF;
388 }
389 break;
390 case length32:
391 if ((int32_t)signed_value < 0) {
392 flags->neg = true;
393 signed_value = (-signed_value) & 0xFFFFFFFF;
394 }
395 break;
396 case length64:
Karl Meakin66a38bd2024-05-28 16:00:56 +0100397 if (signed_value < 0) {
Karl Meakin70894da2024-03-30 21:06:12 +0000398 flags->neg = true;
399 signed_value = -signed_value;
400 }
401 break;
402 }
403
404 return signed_value;
405}
406
407/**
Andrew Scullfdd716e2018-12-20 05:37:31 +0000408 * Same as "dlog", except that arguments are passed as a va_list
Karl Meakind2ef6182024-05-22 11:23:12 +0100409 *
410 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100411 */
Karl Meakin1978e7a2024-11-20 13:56:58 +0000412size_t vdlog(const char *fmt, struct va_list_wrapper *args)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100413{
Karl Meakind2ef6182024-05-22 11:23:12 +0100414 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100415
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100416 lock();
Andrew Scullfdd716e2018-12-20 05:37:31 +0000417
Karl Meakine980e612024-03-28 17:46:32 +0000418 while (*fmt != '\0') {
419 switch (*fmt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100420 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100421 chars_written++;
Karl Meakine980e612024-03-28 17:46:32 +0000422 dlog_putchar(*fmt);
423 fmt++;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100424 break;
425
Karl Meakine980e612024-03-28 17:46:32 +0000426 case '%': {
427 struct format_flags flags = {0};
428 int min_width = 0;
Karl Meakin70894da2024-03-30 21:06:12 +0000429 enum format_length length = length32;
430 uint64_t value;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100431
Karl Meakine980e612024-03-28 17:46:32 +0000432 fmt++;
433 fmt = parse_flags(fmt, &flags);
434 fmt = parse_min_width(fmt, args, &flags, &min_width);
Karl Meakin70894da2024-03-30 21:06:12 +0000435 fmt = parse_length_modifier(fmt, &length);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100436
437 /* Handle the format specifier. */
Karl Meakine980e612024-03-28 17:46:32 +0000438 switch (*fmt) {
439 case '%':
440 fmt++;
441 chars_written++;
442 dlog_putchar('%');
443 break;
444
445 case 'c': {
Karl Meakin1978e7a2024-11-20 13:56:58 +0000446 char str[2] = {va_arg(args->va, int), '\0'};
Karl Meakine980e612024-03-28 17:46:32 +0000447
448 fmt++;
449 chars_written += print_string(
450 str, str, min_width, flags, ' ');
451 break;
452 }
453
Andrew Scull4f170f52018-07-19 12:58:20 +0100454 case 's': {
Karl Meakin1978e7a2024-11-20 13:56:58 +0000455 char *str = va_arg(args->va, char *);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000456
Karl Meakine980e612024-03-28 17:46:32 +0000457 fmt++;
458 chars_written += print_string(
459 str, str, min_width, flags, ' ');
460 break;
461 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100462
463 case 'd':
Andrew Scull4f170f52018-07-19 12:58:20 +0100464 case 'i': {
Karl Meakine980e612024-03-28 17:46:32 +0000465 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000466 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000467 value = reinterpret_signed_int(length, value,
468 &flags);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000469
Karl Meakin70894da2024-03-30 21:06:12 +0000470 chars_written += print_int(value, base10,
Karl Meakine980e612024-03-28 17:46:32 +0000471 min_width, flags);
472 break;
473 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100474
Karl Meakin7efc8372024-04-12 17:06:32 +0100475 case 'b':
476 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000477 value = va_arg(args->va, uint64_t);
Karl Meakin7efc8372024-04-12 17:06:32 +0100478 value = reinterpret_unsigned_int(length, value);
479
480 chars_written += print_int(value, base2,
481 min_width, flags);
482 break;
483
484 case 'B':
485 fmt++;
486 flags.upper = true;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000487 value = va_arg(args->va, uint64_t);
Karl Meakin7efc8372024-04-12 17:06:32 +0100488 value = reinterpret_unsigned_int(length, value);
489
490 chars_written += print_int(value, base2,
491 min_width, flags);
492 break;
493
Karl Meakin70894da2024-03-30 21:06:12 +0000494 case 'o':
Karl Meakine980e612024-03-28 17:46:32 +0000495 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000496 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000497 value = reinterpret_unsigned_int(length, value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100498
Karl Meakin70894da2024-03-30 21:06:12 +0000499 chars_written += print_int(value, base8,
500 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100501 break;
502
503 case 'x':
Karl Meakine980e612024-03-28 17:46:32 +0000504 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000505 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000506 value = reinterpret_unsigned_int(length, value);
507
508 chars_written += print_int(value, base16,
509 min_width, flags);
510 break;
511
512 case 'X':
513 fmt++;
514 flags.upper = true;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000515 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000516 value = reinterpret_unsigned_int(length, value);
517
518 chars_written += print_int(value, base16,
519 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100520 break;
521
522 case 'u':
Karl Meakine980e612024-03-28 17:46:32 +0000523 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000524 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000525 value = reinterpret_unsigned_int(length, value);
526
527 chars_written += print_int(value, base10,
528 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100529 break;
530
Karl Meakin70894da2024-03-30 21:06:12 +0000531 case 'p':
Karl Meakine980e612024-03-28 17:46:32 +0000532 fmt++;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000533 value = va_arg(args->va, uint64_t);
Karl Meakin70894da2024-03-30 21:06:12 +0000534 min_width = sizeof(size_t) * 2 + 2;
535 flags.zero = true;
536 flags.alt = true;
537
538 chars_written += print_int(value, base16,
539 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100540 break;
541
542 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100543 chars_written = -1;
544 goto out;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100545 }
Karl Meakine980e612024-03-28 17:46:32 +0000546 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100547 }
548 }
Karl Meakine980e612024-03-28 17:46:32 +0000549
Karl Meakind2ef6182024-05-22 11:23:12 +0100550out:
Kathleen Capellafd306bb2023-03-17 18:14:01 -0400551 stdout_flush();
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100552 unlock();
Karl Meakind2ef6182024-05-22 11:23:12 +0100553 return chars_written;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100554}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100555
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100556/**
557 * Prints the given format string to the debug log.
Karl Meakind2ef6182024-05-22 11:23:12 +0100558 *
Karl Meakine980e612024-03-28 17:46:32 +0000559 * The format string supported is the same as described in
560 * https://en.cppreference.com/w/c/io/fprintf, with the following exceptions:
561 * - Floating-point formatters (`%f`, `%F`, `%e`, `%E`, `%a`, `%A`, `%g`, `%G`,
562 * `%L`) are not supported because floats are not used in Hafnium and
563 * formatting them is too complicated.
564 * - `%n` is not supported because it is rarely used and potentially dangerous.
565 * - Precision modifiers (`%.*` and `%.` followed by an integer) are not
566 * supported.
567 *
Karl Meakind2ef6182024-05-22 11:23:12 +0100568 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100569 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100570size_t dlog(const char *fmt, ...)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100571{
Karl Meakind2ef6182024-05-22 11:23:12 +0100572 size_t chars_written = 0;
Karl Meakin1978e7a2024-11-20 13:56:58 +0000573 struct va_list_wrapper args;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100574
Karl Meakin1978e7a2024-11-20 13:56:58 +0000575 va_start(args.va, fmt);
576 chars_written = vdlog(fmt, &args);
577 va_end(args.va);
Karl Meakind2ef6182024-05-22 11:23:12 +0100578 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100579}