1#include <uacpi/internal/stdlib.h>
2#include <uacpi/internal/utilities.h>
3
4#ifndef uacpi_memcpy
5void *uacpi_memcpy(void *dest, const void *src, size_t count)
6{
7 uacpi_char *cd = dest;
8 const uacpi_char *cs = src;
9
10 while (count--)
11 *cd++ = *cs++;
12
13 return dest;
14}
15#endif
16
17#ifndef uacpi_memmove
18void *uacpi_memmove(void *dest, const void *src, uacpi_size count)
19{
20 uacpi_char *cd = dest;
21 const uacpi_char *cs = src;
22
23 if (src < dest) {
24 cs += count;
25 cd += count;
26
27 while (count--)
28 *--cd = *--cs;
29 } else {
30 while (count--)
31 *cd++ = *cs++;
32 }
33
34 return dest;
35}
36#endif
37
38#ifndef uacpi_memset
39void *uacpi_memset(void *dest, uacpi_i32 ch, uacpi_size count)
40{
41 uacpi_u8 fill = ch;
42 uacpi_u8 *cdest = dest;
43
44 while (count--)
45 *cdest++ = fill;
46
47 return dest;
48}
49#endif
50
51#ifndef uacpi_memcmp
52uacpi_i32 uacpi_memcmp(const void *lhs, const void *rhs, uacpi_size count)
53{
54 const uacpi_u8 *byte_lhs = lhs;
55 const uacpi_u8 *byte_rhs = rhs;
56 uacpi_size i;
57
58 for (i = 0; i < count; ++i) {
59 if (byte_lhs[i] != byte_rhs[i])
60 return byte_lhs[i] - byte_rhs[i];
61 }
62
63 return 0;
64}
65#endif
66
67#ifndef uacpi_strlen
68uacpi_size uacpi_strlen(const uacpi_char *str)
69{
70 const uacpi_char *str1;
71
72 for (str1 = str; *str1; str1++);
73
74 return str1 - str;
75}
76#endif
77
78#ifndef uacpi_strnlen
79uacpi_size uacpi_strnlen(const uacpi_char *str, uacpi_size max)
80{
81 const uacpi_char *str1;
82
83 for (str1 = str; max-- && *str1; str1++);
84
85 return str1 - str;
86}
87#endif
88
89#ifndef uacpi_strcmp
90uacpi_i32 uacpi_strcmp(const uacpi_char *lhs, const uacpi_char *rhs)
91{
92 uacpi_size i = 0;
93 typedef const uacpi_u8 *cucp;
94
95 while (lhs[i] && rhs[i]) {
96 if (lhs[i] != rhs[i])
97 return *(cucp)&lhs[i] - *(cucp)&rhs[i];
98
99 i++;
100 }
101
102 return *(cucp)&lhs[i] - *(cucp)&rhs[i];
103}
104#endif
105
106#ifndef uacpi_vsnprintf
107struct fmt_buf_state {
108 uacpi_char *buffer;
109 uacpi_size capacity;
110 uacpi_size bytes_written;
111};
112
113struct fmt_spec {
114 uacpi_u8 is_signed : 1;
115 uacpi_u8 prepend : 1;
116 uacpi_u8 uppercase : 1;
117 uacpi_u8 left_justify : 1;
118 uacpi_u8 alternate_form : 1;
119 uacpi_char pad_char;
120 uacpi_char prepend_char;
121 uacpi_u64 min_width;
122 uacpi_u64 precision;
123 uacpi_u32 base;
124};
125
126static void write_one(struct fmt_buf_state *fb_state, uacpi_char c)
127{
128 if (fb_state->bytes_written < fb_state->capacity)
129 fb_state->buffer[fb_state->bytes_written] = c;
130
131 fb_state->bytes_written++;
132}
133
134static void write_many(
135 struct fmt_buf_state *fb_state, const uacpi_char *string, uacpi_size count
136)
137{
138 if (fb_state->bytes_written < fb_state->capacity) {
139 uacpi_size count_to_write;
140
141 count_to_write = UACPI_MIN(
142 count, fb_state->capacity - fb_state->bytes_written
143 );
144 uacpi_memcpy(
145 dest: &fb_state->buffer[fb_state->bytes_written], src: string, count: count_to_write
146 );
147 }
148
149 fb_state->bytes_written += count;
150}
151
152static uacpi_char hex_char(uacpi_bool upper, uacpi_u64 value)
153{
154 static const uacpi_char upper_hex[] = "0123456789ABCDEF";
155 static const uacpi_char lower_hex[] = "0123456789abcdef";
156
157 return (upper ? upper_hex : lower_hex)[value];
158}
159
160static void write_padding(
161 struct fmt_buf_state *fb_state, struct fmt_spec *fm, uacpi_size repr_size
162)
163{
164 uacpi_u64 mw = fm->min_width;
165
166 if (mw <= repr_size)
167 return;
168
169 mw -= repr_size;
170
171 while (mw--)
172 write_one(fb_state, c: fm->left_justify ? ' ' : fm->pad_char);
173}
174
175#define REPR_BUFFER_SIZE 32
176
177static void write_integer(
178 struct fmt_buf_state *fb_state, struct fmt_spec *fm, uacpi_u64 value
179)
180{
181 uacpi_char repr_buffer[REPR_BUFFER_SIZE];
182 uacpi_size index = REPR_BUFFER_SIZE;
183 uacpi_u64 remainder;
184 uacpi_char repr;
185 uacpi_bool negative = UACPI_FALSE;
186 uacpi_size repr_size;
187
188 if (fm->is_signed) {
189 uacpi_i64 as_ll = value;
190
191 if (as_ll < 0) {
192 value = -as_ll;
193 negative = UACPI_TRUE;
194 }
195 }
196
197 if (fm->prepend || negative)
198 write_one(fb_state, c: negative ? '-' : fm->prepend_char);
199
200 while (value) {
201 remainder = value % fm->base;
202 value /= fm->base;
203
204 if (fm->base == 16) {
205 repr = hex_char(upper: fm->uppercase, value: remainder);
206 } else if (fm->base == 8 || fm->base == 10) {
207 repr = remainder + '0';
208 } else {
209 repr = '?';
210 }
211
212 repr_buffer[--index] = repr;
213 }
214 repr_size = REPR_BUFFER_SIZE - index;
215
216 if (repr_size == 0) {
217 repr_buffer[--index] = '0';
218 repr_size = 1;
219 }
220
221 if (fm->alternate_form) {
222 if (fm->base == 16) {
223 repr_buffer[--index] = fm->uppercase ? 'X' : 'x';
224 repr_buffer[--index] = '0';
225 repr_size += 2;
226 } else if (fm->base == 8) {
227 repr_buffer[--index] = '0';
228 repr_size += 1;
229 }
230 }
231
232 if (fm->left_justify) {
233 write_many(fb_state, string: &repr_buffer[index], count: repr_size);
234 write_padding(fb_state, fm, repr_size);
235 } else {
236 write_padding(fb_state, fm, repr_size);
237 write_many(fb_state, string: &repr_buffer[index], count: repr_size);
238 }
239}
240
241static uacpi_bool string_has_at_least(
242 const uacpi_char *string, uacpi_size characters
243)
244{
245 while (*string) {
246 if (--characters == 0)
247 return UACPI_TRUE;
248
249 string++;
250 }
251
252 return UACPI_FALSE;
253}
254
255static uacpi_bool consume_digits(
256 const uacpi_char **string, uacpi_size *out_size
257)
258{
259 uacpi_size size = 0;
260
261 for (;;) {
262 char c = **string;
263 if (c < '0' || c > '9')
264 break;
265
266 size++;
267 *string += 1;
268 }
269
270 if (size == 0)
271 return UACPI_FALSE;
272
273 *out_size = size;
274 return UACPI_TRUE;
275}
276
277enum parse_number_mode {
278 PARSE_NUMBER_MODE_MAYBE,
279 PARSE_NUMBER_MODE_MUST,
280};
281
282static uacpi_bool parse_number(
283 const uacpi_char **fmt, enum parse_number_mode mode, uacpi_u64 *out_value
284)
285{
286 uacpi_status ret;
287 uacpi_size num_digits;
288 const uacpi_char *digits = *fmt;
289
290 if (!consume_digits(string: fmt, out_size: &num_digits))
291 return mode != PARSE_NUMBER_MODE_MUST;
292
293 ret = uacpi_string_to_integer(str: digits, max_chars: num_digits, base: UACPI_BASE_DEC, out_value);
294 return ret == UACPI_STATUS_OK;
295}
296
297static uacpi_bool consume(const uacpi_char **string, const uacpi_char *token)
298{
299 uacpi_size token_size;
300
301 token_size = uacpi_strlen(str: token);
302
303 if (!string_has_at_least(string: *string, characters: token_size))
304 return UACPI_FALSE;
305
306 if (!uacpi_memcmp(lhs: *string, rhs: token, count: token_size)) {
307 *string += token_size;
308 return UACPI_TRUE;
309 }
310
311 return UACPI_FALSE;
312}
313
314static uacpi_bool is_one_of(uacpi_char c, const uacpi_char *list)
315{
316 for (; *list; list++) {
317 if (c == *list)
318 return UACPI_TRUE;
319 }
320
321 return UACPI_FALSE;
322}
323
324static uacpi_bool consume_one_of(
325 const uacpi_char **string, const uacpi_char *list, uacpi_char *consumed_char
326)
327{
328 uacpi_char c = **string;
329 if (!c)
330 return UACPI_FALSE;
331
332 if (is_one_of(c, list)) {
333 *consumed_char = c;
334 *string += 1;
335 return UACPI_TRUE;
336 }
337
338 return UACPI_FALSE;
339}
340
341static uacpi_u32 base_from_specifier(uacpi_char specifier)
342{
343 switch (specifier)
344 {
345 case 'x':
346 case 'X':
347 return 16;
348 case 'o':
349 return 8;
350 default:
351 return 10;
352 }
353}
354
355static uacpi_bool is_uppercase_specifier(uacpi_char specifier)
356{
357 return specifier == 'X';
358}
359
360static const uacpi_char *find_next_conversion(
361 const uacpi_char *fmt, uacpi_size *offset
362)
363{
364 *offset = 0;
365
366 while (*fmt) {
367 if (*fmt == '%')
368 return fmt;
369
370 fmt++;
371 *offset += 1;
372 }
373
374 return UACPI_NULL;
375}
376
377uacpi_i32 uacpi_vsnprintf(
378 uacpi_char *buffer, uacpi_size capacity, const uacpi_char *fmt,
379 uacpi_va_list vlist
380)
381{
382 struct fmt_buf_state fb_state = {
383 .buffer = buffer,
384 .capacity = capacity,
385 .bytes_written = 0
386 };
387
388 uacpi_u64 value;
389 const uacpi_char *next_conversion;
390 uacpi_size next_offset;
391 uacpi_char flag;
392
393 while (*fmt) {
394 struct fmt_spec fm = {
395 .pad_char = ' ',
396 .base = 10,
397 .precision = 0xFFFFFFFFFFFFFFFF,
398 };
399 next_conversion = find_next_conversion(fmt, offset: &next_offset);
400
401 if (next_offset)
402 write_many(fb_state: &fb_state, string: fmt, count: next_offset);
403
404 if (!next_conversion)
405 break;
406
407 fmt = next_conversion;
408 if (consume(string: &fmt, token: "%%")) {
409 write_one(fb_state: &fb_state, c: '%');
410 continue;
411 }
412
413 // consume %
414 fmt++;
415
416 while (consume_one_of(string: &fmt, list: "+- 0#", consumed_char: &flag)) {
417 switch (flag) {
418 case '+':
419 case ' ':
420 fm.prepend = UACPI_TRUE;
421 fm.prepend_char = flag;
422 continue;
423 case '-':
424 fm.left_justify = UACPI_TRUE;
425 continue;
426 case '0':
427 fm.pad_char = '0';
428 continue;
429 case '#':
430 fm.alternate_form = UACPI_TRUE;
431 continue;
432 default:
433 return -1;
434 }
435 }
436
437 if (consume(string: &fmt, token: "*")) {
438 fm.min_width = uacpi_va_arg(vlist, int);
439 } else if (!parse_number(fmt: &fmt, mode: PARSE_NUMBER_MODE_MAYBE, out_value: &fm.min_width)) {
440 return -1;
441 }
442
443 if (consume(string: &fmt, token: ".")) {
444 if (consume(string: &fmt, token: "*")) {
445 fm.precision = uacpi_va_arg(vlist, int);
446 } else {
447 if (!parse_number(fmt: &fmt, mode: PARSE_NUMBER_MODE_MUST, out_value: &fm.precision))
448 return -1;
449 }
450 }
451
452 flag = 0;
453
454 if (consume(string: &fmt, token: "c")) {
455 uacpi_char c = uacpi_va_arg(vlist, int);
456 write_one(fb_state: &fb_state, c);
457 continue;
458 }
459
460 if (consume(string: &fmt, token: "s")) {
461 const uacpi_char *string = uacpi_va_arg(vlist, uacpi_char*);
462 uacpi_size i;
463
464 for (i = 0; i < fm.precision && string[i]; ++i)
465 write_one(fb_state: &fb_state, c: string[i]);
466
467 continue;
468 }
469
470 if (consume(string: &fmt, token: "p")) {
471 value = (uacpi_uintptr)uacpi_va_arg(vlist, void*);
472 fm.base = 16;
473 fm.min_width = UACPI_POINTER_SIZE * 2;
474 fm.pad_char = '0';
475 goto write_int;
476 }
477
478 if (consume(string: &fmt, token: "hh")) {
479 if (consume(string: &fmt, token: "d") || consume(string: &fmt, token: "i")) {
480 value = (signed char)uacpi_va_arg(vlist, int);
481 fm.is_signed = UACPI_TRUE;
482 } else if (consume_one_of(string: &fmt, list: "oxXu", consumed_char: &flag)) {
483 value = (unsigned char)uacpi_va_arg(vlist, int);
484 } else {
485 return -1;
486 }
487 goto write_int;
488 }
489
490 if (consume(string: &fmt, token: "h")) {
491 if (consume(string: &fmt, token: "d") || consume(string: &fmt, token: "i")) {
492 value = (signed short)uacpi_va_arg(vlist, int);
493 fm.is_signed = UACPI_TRUE;
494 } else if (consume_one_of(string: &fmt, list: "oxXu", consumed_char: &flag)) {
495 value = (unsigned short)uacpi_va_arg(vlist, int);
496 } else {
497 return -1;
498 }
499 goto write_int;
500 }
501
502 if (consume(string: &fmt, token: "ll") ||
503 (sizeof(uacpi_size) == sizeof(long long) && consume(string: &fmt, token: "z"))) {
504 if (consume(string: &fmt, token: "d") || consume(string: &fmt, token: "i")) {
505 value = uacpi_va_arg(vlist, long long);
506 fm.is_signed = UACPI_TRUE;
507 } else if (consume_one_of(string: &fmt, list: "oxXu", consumed_char: &flag)) {
508 value = uacpi_va_arg(vlist, unsigned long long);
509 } else {
510 return -1;
511 }
512 goto write_int;
513 }
514
515 if (consume(string: &fmt, token: "l") ||
516 (sizeof(uacpi_size) == sizeof(long) && consume(string: &fmt, token: "z"))) {
517 if (consume(string: &fmt, token: "d") || consume(string: &fmt, token: "i")) {
518 value = uacpi_va_arg(vlist, long);
519 fm.is_signed = UACPI_TRUE;
520 } else if (consume_one_of(string: &fmt, list: "oxXu", consumed_char: &flag)) {
521 value = uacpi_va_arg(vlist, unsigned long);
522 } else {
523 return -1;
524 }
525 goto write_int;
526 }
527
528 if (consume(string: &fmt, token: "d") || consume(string: &fmt, token: "i")) {
529 value = uacpi_va_arg(vlist, uacpi_i32);
530 fm.is_signed = UACPI_TRUE;
531 } else if (consume_one_of(string: &fmt, list: "oxXu", consumed_char: &flag)) {
532 value = uacpi_va_arg(vlist, uacpi_u32);
533 } else {
534 return -1;
535 }
536
537 write_int:
538 if (flag != 0) {
539 fm.base = base_from_specifier(specifier: flag);
540 fm.uppercase = is_uppercase_specifier(specifier: flag);
541 }
542
543 write_integer(fb_state: &fb_state, fm: &fm, value);
544 }
545
546 if (fb_state.capacity) {
547 uacpi_size last_char;
548
549 last_char = UACPI_MIN(fb_state.bytes_written, fb_state.capacity - 1);
550 fb_state.buffer[last_char] = '\0';
551 }
552
553 return fb_state.bytes_written;
554}
555#endif
556
557#ifndef uacpi_snprintf
558uacpi_i32 uacpi_snprintf(
559 uacpi_char *buffer, uacpi_size capacity, const uacpi_char *fmt, ...
560)
561{
562 uacpi_va_list vlist;
563 uacpi_i32 ret;
564
565 uacpi_va_start(vlist, fmt);
566 ret = uacpi_vsnprintf(buffer, capacity, fmt, vlist);
567 uacpi_va_end(vlist);
568
569 return ret;
570}
571#endif
572
573void uacpi_memcpy_zerout(void *dst, const void *src,
574 uacpi_size dst_size, uacpi_size src_size)
575{
576 uacpi_size bytes_to_copy = UACPI_MIN(src_size, dst_size);
577
578 if (bytes_to_copy)
579 uacpi_memcpy(dest: dst, src, count: bytes_to_copy);
580
581 if (dst_size > bytes_to_copy)
582 uacpi_memzero((uacpi_u8*)dst + bytes_to_copy, dst_size - bytes_to_copy);
583}
584
585uacpi_u8 uacpi_bit_scan_forward(uacpi_u64 value)
586{
587#ifdef _MSC_VER
588 unsigned char ret;
589 unsigned long index;
590
591#ifdef _WIN64
592 ret = _BitScanForward64(&index, value);
593 if (ret == 0)
594 return 0;
595
596 return (uacpi_u8)index + 1;
597#else
598 ret = _BitScanForward(&index, value);
599 if (ret == 0) {
600 ret = _BitScanForward(&index, value >> 32);
601 if (ret == 0)
602 return 0;
603
604 return (uacpi_u8)index + 33;
605 }
606
607 return (uacpi_u8)index + 1;
608#endif
609
610#else
611 return __builtin_ffsll(value);
612#endif
613}
614
615uacpi_u8 uacpi_bit_scan_backward(uacpi_u64 value)
616{
617#ifdef _MSC_VER
618 unsigned char ret;
619 unsigned long index;
620
621#ifdef _WIN64
622 ret = _BitScanReverse64(&index, value);
623 if (ret == 0)
624 return 0;
625
626 return (uacpi_u8)index + 1;
627#else
628 ret = _BitScanReverse(&index, value >> 32);
629 if (ret == 0) {
630 ret = _BitScanReverse(&index, value);
631 if (ret == 0)
632 return 0;
633
634 return (uacpi_u8)index + 1;
635 }
636
637 return (uacpi_u8)index + 33;
638#endif
639
640#else
641 if (value == 0)
642 return 0;
643
644 return 64 - __builtin_clzll(value);
645#endif
646}
647
648uacpi_u8 uacpi_popcount(uacpi_u64 value)
649{
650#ifdef _MSC_VER
651
652#ifdef _WIN64
653 return __popcnt64(value);
654#else
655 return __popcnt(value) + __popcnt(value >> 32);
656#endif
657
658#else
659 return __builtin_popcountll(value);
660#endif
661}
662
663#ifndef UACPI_FORMATTED_LOGGING
664
665#ifndef UACPI_PLAIN_LOG_BUFFER_SIZE
666 #define UACPI_PLAIN_LOG_BUFFER_SIZE 128
667#endif
668
669UACPI_BUILD_BUG_ON_WITH_MSG(
670 UACPI_PLAIN_LOG_BUFFER_SIZE < 16,
671 "configured log buffer size is too small (expecting at least 16 bytes)"
672);
673
674void uacpi_log(uacpi_log_level lvl, const uacpi_char *str, ...)
675{
676 uacpi_char buf[UACPI_PLAIN_LOG_BUFFER_SIZE];
677 int ret;
678
679 uacpi_va_list vlist;
680 uacpi_va_start(vlist, str);
681
682 ret = uacpi_vsnprintf(buffer: buf, capacity: sizeof(buf), fmt: str, vlist);
683 if (uacpi_unlikely(ret < 0))
684 return;
685
686 /*
687 * If this log message is too large for the configured buffer size, cut off
688 * the end and transform into "...\n" to indicate that it didn't fit and
689 * prevent the newline from being truncated.
690 */
691 if (uacpi_unlikely(ret >= UACPI_PLAIN_LOG_BUFFER_SIZE)) {
692 buf[UACPI_PLAIN_LOG_BUFFER_SIZE - 5] = '.';
693 buf[UACPI_PLAIN_LOG_BUFFER_SIZE - 4] = '.';
694 buf[UACPI_PLAIN_LOG_BUFFER_SIZE - 3] = '.';
695 buf[UACPI_PLAIN_LOG_BUFFER_SIZE - 2] = '\n';
696 }
697
698 uacpi_kernel_log(lvl, buf);
699
700 uacpi_va_end(vlist);
701}
702#endif
703