1 /*
2 * stdlib support routines for self-contained images.
3 *
4 * Copyright (C) 2020, Broadcom.
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Dual:>>
22 */
23
24 /*
25 * bcmstdlib.c file should be used only to construct an OSL or alone without any OSL
26 * It should not be used with any orbitarary OSL's as there could be a conflict
27 * with some of the routines defined here.
28 */
29
30 /*
31 * Define BCMSTDLIB_WIN32_APP if this is a Win32 Application compile
32 */
33 #if defined(_WIN32) && !defined(NDIS) && !defined(EFI)
34 #define BCMSTDLIB_WIN32_APP 1
35 #endif /* _WIN32 && !NDIS */
36
37 /*
38 * Define BCMSTDLIB_SNPRINTF_ONLY if we only want snprintf & vsnprintf implementations
39 */
40 #if defined(_WIN32) && !defined(EFI)
41 #define BCMSTDLIB_SNPRINTF_ONLY 1
42 #endif /* _WIN32 || !EFI */
43
44 #include <typedefs.h>
45 #ifdef BCMSTDLIB_WIN32_APP
46 /* for size_t definition */
47 #include <stddef.h>
48 #endif
49 #include <stdarg.h>
50 #ifndef BCMSTDLIB_WIN32_APP
51 #include <bcmutils.h>
52 #endif
53 #include <bcmstdlib.h>
54
55 /* Don't use compiler builtins for stdlib APIs within the implementation of the stdlib itself. */
56 #if defined(BCM_FORTIFY_SOURCE) || defined(BCM_STDLIB_USE_BUILTINS)
57 #undef memcpy
58 #undef memmove
59 #undef memset
60 #undef strncpy
61 #undef snprintf
62 #undef vsnprintf
63 #endif /* BCM_FORTIFY_SOURCE || BCM_STDLIB_USE_BUILTINS */
64
65 #ifdef HND_PRINTF_THREAD_SAFE
66 #include <osl.h>
67 #include <osl_ext.h>
68 #include <bcmstdlib_ext.h>
69
70 /* mutex macros for thread safe */
71 #define HND_PRINTF_MUTEX_DECL(mutex) static OSL_EXT_MUTEX_DECL(mutex)
72 #define HND_PRINTF_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex)
73 #define HND_PRINTF_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex)
74 #define HND_PRINTF_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec)
75 #define HND_PRINTF_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex)
76
77 HND_PRINTF_MUTEX_DECL(printf_mutex);
78 int in_isr_handler = 0, in_trap_handler = 0, in_fiq_handler = 0;
79
80 bool
printf_lock_init(void)81 printf_lock_init(void)
82 {
83 /* create mutex for critical section locking */
84 if (HND_PRINTF_MUTEX_CREATE("printf_mutex", &printf_mutex) != OSL_EXT_SUCCESS)
85 return FALSE;
86 return TRUE;
87 }
88
89 bool
printf_lock_cleanup(void)90 printf_lock_cleanup(void)
91 {
92 /* create mutex for critical section locking */
93 if (HND_PRINTF_MUTEX_DELETE(&printf_mutex) != OSL_EXT_SUCCESS)
94 return FALSE;
95 return TRUE;
96 }
97
98 /* returns TRUE if allowed to proceed, FALSE to discard.
99 * printf from isr hook or fiq hook is not allowed due to IRQ_MODE and FIQ_MODE stack size
100 * limitation.
101 */
102 static bool
printf_lock(void)103 printf_lock(void)
104 {
105
106 /* discard for irq or fiq context, we need to keep irq/fiq stack small. */
107 if (in_isr_handler || in_fiq_handler)
108 return FALSE;
109
110 /* allow printf in trap handler, proceed without mutex. */
111 if (in_trap_handler)
112 return TRUE;
113
114 /* if not in isr or trap, then go thread-protection with mutex. */
115 if (HND_PRINTF_MUTEX_ACQUIRE(&printf_mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS)
116 return FALSE;
117 else
118 return TRUE;
119 }
120
121 static void
printf_unlock(void)122 printf_unlock(void)
123 {
124 if (in_isr_handler || in_fiq_handler)
125 return;
126
127 if (in_trap_handler)
128 return;
129
130 if (HND_PRINTF_MUTEX_RELEASE(&printf_mutex) != OSL_EXT_SUCCESS)
131 return;
132 }
133
134 #else
135 #define printf_lock() (TRUE)
136 #define printf_unlock()
137 #endif /* HND_PRINTF_THREAD_SAFE */
138
139 #ifdef BCMSTDLIB_WIN32_APP
140
141 /* for a WIN32 application, use _vsnprintf as basis of vsnprintf/snprintf to
142 * support full set of format specifications.
143 */
144
145 int
BCMPOSTTRAPFN(vsnprintf)146 BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t bufsize, const char *fmt, va_list ap)
147 {
148 int r;
149
150 r = _vsnprintf(buf, bufsize, fmt, ap);
151
152 /* Microsoft _vsnprintf() will not null terminate on overflow,
153 * so null terminate at buffer end on error
154 */
155 if (r < 0 && bufsize > 0)
156 buf[bufsize - 1] = '\0';
157
158 return r;
159 }
160
161 int
BCMPOSTTRAPFN(snprintf)162 BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...)
163 {
164 va_list ap;
165 int r;
166
167 va_start(ap, fmt);
168 r = vsnprintf(buf, bufsize, fmt, ap);
169 va_end(ap);
170
171 return r;
172 }
173
174 #else /* BCMSTDLIB_WIN32_APP */
175
176 #if !defined(BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS)
177
178 static const char hex_upper[17] = "0123456789ABCDEF";
179 static const char hex_lower[17] = "0123456789abcdef";
180
181 static int
BCMPOSTTRAPFN(__atolx)182 BCMPOSTTRAPFN(__atolx)(char *buf, char * end, unsigned long num, unsigned long radix, int width,
183 const char *digits, int zero_pad)
184 {
185 char buffer[32];
186 char *op;
187 int retval;
188
189 op = &buffer[0];
190 retval = 0;
191
192 do {
193 *op++ = digits[num % radix];
194 retval++;
195 num /= radix;
196 } while (num != 0);
197
198 if (width && (width > retval) && zero_pad) {
199 width = width - retval;
200 while (width) {
201 *op++ = '0';
202 retval++;
203 width--;
204 }
205 }
206
207 while (op != buffer) {
208 op--;
209 if (buf <= end)
210 *buf = *op;
211 buf++;
212 }
213
214 return retval;
215 }
216
217 static int
BCMPOSTTRAPFN(__atox)218 BCMPOSTTRAPFN(__atox)(char *buf, char * end, unsigned int num, unsigned int radix, int width,
219 const char *digits, int zero_pad)
220 {
221 char buffer[16];
222 char *op;
223 int retval;
224
225 op = &buffer[0];
226 retval = 0;
227
228 do {
229 *op++ = digits[num % radix];
230 retval++;
231 num /= radix;
232 } while (num != 0);
233
234 if (width && (width > retval) && zero_pad) {
235 width = width - retval;
236 while (width) {
237 *op++ = '0';
238 retval++;
239 width--;
240 }
241 }
242
243 while (op != buffer) {
244 op--;
245 if (buf <= end)
246 *buf = *op;
247 buf++;
248 }
249
250 return retval;
251 }
252
253 int
BCMPOSTTRAPFN(vsnprintf)254 BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t size, const char *fmt, va_list ap)
255 {
256 char *optr;
257 char *end;
258 const char *iptr, *tmpptr;
259 unsigned int x;
260 int i;
261 int islong;
262 int width;
263 int width2 = 0;
264 int hashash = 0;
265 int zero_pad;
266 unsigned long ul = 0;
267 long int li = 0;
268
269 optr = buf;
270 end = buf + size - 1;
271 iptr = fmt;
272
273 if (FWSIGN_ENAB()) {
274 return 0;
275 }
276
277 if (end < buf - 1) {
278 end = ((void *) -1);
279 size = end - buf + 1;
280 }
281
282 while (*iptr) {
283 zero_pad = 0;
284 if (*iptr != '%') {
285 if (optr <= end)
286 *optr = *iptr;
287 ++optr;
288 ++iptr;
289 continue;
290 }
291
292 iptr++;
293
294 if (*iptr == '#') {
295 hashash = 1;
296 iptr++;
297 }
298 if (*iptr == '-') {
299 iptr++;
300 }
301
302 if (*iptr == '0') {
303 zero_pad = 1;
304 iptr++;
305 }
306
307 width = 0;
308 while (*iptr && bcm_isdigit(*iptr)) {
309 width += (*iptr - '0');
310 iptr++;
311 if (bcm_isdigit(*iptr))
312 width *= 10;
313 }
314 if (*iptr == '.') {
315 iptr++;
316 width2 = 0;
317 while (*iptr && bcm_isdigit(*iptr)) {
318 width2 += (*iptr - '0');
319 iptr++;
320 if (bcm_isdigit(*iptr)) width2 *= 10;
321 }
322 }
323
324 islong = 0;
325 if (*iptr == 'l') {
326 islong++;
327 iptr++;
328 if (*iptr == 'l') {
329 ++islong;
330 ++iptr;
331 }
332 }
333
334 switch (*iptr) {
335 case 's':
336 tmpptr = va_arg(ap, const char *);
337 if (!tmpptr)
338 tmpptr = "(null)";
339 if ((width == 0) & (width2 == 0)) {
340 while (*tmpptr) {
341 if (optr <= end)
342 *optr = *tmpptr;
343 ++optr;
344 ++tmpptr;
345 }
346 break;
347 }
348 while (width && *tmpptr) {
349 if (optr <= end)
350 *optr = *tmpptr;
351 ++optr;
352 ++tmpptr;
353 width--;
354 }
355 while (width) {
356 if (optr <= end)
357 *optr = ' ';
358 ++optr;
359 width--;
360 }
361 break;
362 case 'd':
363 case 'i':
364 if (!islong) {
365 i = va_arg(ap, int);
366 if (i < 0) {
367 if (optr <= end)
368 *optr = '-';
369 ++optr;
370 i = -i;
371 }
372 optr += __atox(optr, end, i, 10, width, hex_upper, zero_pad);
373 } else {
374 li = va_arg(ap, long int);
375 if (li < 0) {
376 if (optr <= end)
377 *optr = '-';
378 ++optr;
379 li = -li;
380 }
381 optr += __atolx(optr, end, li, 10, width, hex_upper, zero_pad);
382 }
383 break;
384 case 'u':
385 if (!islong) {
386 x = va_arg(ap, unsigned int);
387 optr += __atox(optr, end, x, 10, width, hex_upper, zero_pad);
388 } else {
389 ul = va_arg(ap, unsigned long);
390 optr += __atolx(optr, end, ul, 10, width, hex_upper, zero_pad);
391 }
392 break;
393 case 'X':
394 case 'x':
395 if (hashash) {
396 *optr++ = '0';
397 *optr++ = *iptr;
398 }
399 if (!islong) {
400 x = va_arg(ap, unsigned int);
401 optr += __atox(optr, end, x, 16, width,
402 (*iptr == 'X') ? hex_upper : hex_lower, zero_pad);
403 } else {
404 ul = va_arg(ap, unsigned long);
405 optr += __atolx(optr, end, ul, 16, width,
406 (*iptr == 'X') ? hex_upper : hex_lower, zero_pad);
407 }
408 break;
409 case 'p':
410 case 'P':
411 x = va_arg(ap, unsigned int);
412 optr += __atox(optr, end, x, 16, 8,
413 (*iptr == 'P') ? hex_upper : hex_lower, zero_pad);
414 break;
415 case 'c':
416 x = va_arg(ap, int);
417 if (optr <= end)
418 *optr = x & 0xff;
419 optr++;
420 break;
421
422 default:
423 if (optr <= end)
424 *optr = *iptr;
425 optr++;
426 break;
427 }
428 iptr++;
429 }
430
431 if (optr <= end) {
432 *optr = '\0';
433 return (int)(optr - buf);
434 } else {
435 *end = '\0';
436 return (int)(end - buf);
437 }
438 }
439
440 int
BCMPOSTTRAPFN(snprintf)441 BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...)
442 {
443 va_list ap;
444 int r;
445
446 if (FWSIGN_ENAB()) {
447 return 0;
448 }
449
450 va_start(ap, fmt);
451 r = vsnprintf(buf, bufsize, fmt, ap);
452 va_end(ap);
453
454 return r;
455 }
456 #endif /* !BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS */
457
458 #endif /* BCMSTDLIB_WIN32_APP */
459
460 #ifndef BCMSTDLIB_SNPRINTF_ONLY
461 int
BCMPOSTTRAPFN(vsprintf)462 BCMPOSTTRAPFN(vsprintf)(char *buf, const char *fmt, va_list ap)
463 {
464 if (FWSIGN_ENAB()) {
465 return 0;
466 }
467 return (vsnprintf(buf, INT_MAX, fmt, ap));
468 }
469
470 int
BCMPOSTTRAPFN(sprintf)471 BCMPOSTTRAPFN(sprintf)(char *buf, const char *fmt, ...)
472 {
473 va_list ap;
474 int count;
475
476 if (FWSIGN_ENAB()) {
477 return 0;
478 }
479
480 va_start(ap, fmt);
481 count = vsprintf(buf, fmt, ap);
482 va_end(ap);
483
484 return count;
485 }
486
487 #if !defined(EFI) || !defined(COMPILER_INTRINSICS_LIB)
488 void *
memmove(void * dest,const void * src,size_t n)489 memmove(void *dest, const void *src, size_t n)
490 {
491 /* only use memcpy if there is no overlap. otherwise copy each byte in a safe sequence */
492 if (((const char *)src >= (char *)dest + n) || ((const char *)src + n <= (char *)dest)) {
493 return memcpy(dest, src, n);
494 }
495
496 /* Overlapping copy forward or backward */
497 if (src < dest) {
498 unsigned char *d = (unsigned char *)dest + (n - 1);
499 const unsigned char *s = (const unsigned char *)src + (n - 1);
500 while (n) {
501 *d-- = *s--;
502 n--;
503 }
504 } else if (src > dest) {
505 unsigned char *d = (unsigned char *)dest;
506 const unsigned char *s = (const unsigned char *)src;
507 while (n) {
508 *d++ = *s++;
509 n--;
510 }
511 }
512
513 return dest;
514 }
515 #endif /* !EFI || !COMPILER_INTRINSICS_LIB */
516
517 #ifndef EFI
518 int
memcmp(const void * s1,const void * s2,size_t n)519 memcmp(const void *s1, const void *s2, size_t n)
520 {
521 const unsigned char *ss1;
522 const unsigned char *ss2;
523
524 ss1 = (const unsigned char *)s1;
525 ss2 = (const unsigned char *)s2;
526
527 while (n) {
528 if (*ss1 < *ss2)
529 return -1;
530 if (*ss1 > *ss2)
531 return 1;
532 ss1++;
533 ss2++;
534 n--;
535 }
536
537 return 0;
538 }
539
540 /* Skip over functions that are being used from DriverLibrary to save space */
541 char *
strncpy(char * dest,const char * src,size_t n)542 strncpy(char *dest, const char *src, size_t n)
543 {
544 char *endp;
545 char *p;
546
547 p = dest;
548 endp = p + n;
549
550 while (p != endp && (*p++ = *src++) != '\0')
551 ;
552
553 /* zero fill remainder */
554 bzero(p, (endp - p));
555
556 return dest;
557 }
558
559 size_t
BCMPOSTTRAPFN(strlen)560 BCMPOSTTRAPFN(strlen)(const char *s)
561 {
562 size_t n = 0;
563
564 while (*s) {
565 s++;
566 n++;
567 }
568
569 return n;
570 }
571
572 int
BCMPOSTTRAPFN(strcmp)573 BCMPOSTTRAPFN(strcmp)(const char *s1, const char *s2)
574 {
575 while (*s2 && *s1) {
576 if (*s1 < *s2)
577 return -1;
578 if (*s1 > *s2)
579 return 1;
580 s1++;
581 s2++;
582 }
583
584 if (*s1 && !*s2)
585 return 1;
586 if (!*s1 && *s2)
587 return -1;
588 return 0;
589 }
590 #endif /* EFI */
591
592 int
strncmp(const char * s1,const char * s2,size_t n)593 strncmp(const char *s1, const char *s2, size_t n)
594 {
595 while (*s2 && *s1 && n) {
596 if (*s1 < *s2)
597 return -1;
598 if (*s1 > *s2)
599 return 1;
600 s1++;
601 s2++;
602 n--;
603 }
604
605 if (!n)
606 return 0;
607 if (*s1 && !*s2)
608 return 1;
609 if (!*s1 && *s2)
610 return -1;
611 return 0;
612 }
613
614 char *
strchr(const char * str,int c)615 strchr(const char *str, int c)
616 {
617 const char *x = str;
618
619 while (*x != (char)c) {
620 if (*x++ == '\0')
621 return (NULL);
622 }
623
624 return DISCARD_QUAL(x, char);
625 }
626
627 char *
strrchr(const char * str,int c)628 strrchr(const char *str, int c)
629 {
630 const char *save = NULL;
631
632 do {
633 if (*str == (char)c)
634 save = str;
635 } while (*str++ != '\0');
636
637 return DISCARD_QUAL(save, char);
638 }
639
640 /* Skip over functions that are being used from DriverLibrary to save space */
641 #ifndef EFI
642 char *
strstr(const char * s,const char * substr)643 strstr(const char *s, const char *substr)
644 {
645 int substr_len = strlen(substr);
646
647 for (; *s; s++)
648 if (strncmp(s, substr, substr_len) == 0)
649 return DISCARD_QUAL(s, char);
650
651 return NULL;
652 }
653 #endif /* EFI */
654
655 size_t
strspn(const char * s,const char * accept)656 strspn(const char *s, const char *accept)
657 {
658 uint count = 0;
659
660 while (s[count] && strchr(accept, s[count]))
661 count++;
662
663 return count;
664 }
665
666 size_t
strcspn(const char * s,const char * reject)667 strcspn(const char *s, const char *reject)
668 {
669 uint count = 0;
670
671 while (s[count] && !strchr(reject, s[count]))
672 count++;
673
674 return count;
675 }
676
677 void *
memchr(const void * s,int c,size_t n)678 memchr(const void *s, int c, size_t n)
679 {
680 if (n != 0) {
681 const unsigned char *ptr = s;
682
683 do {
684 if (*ptr == (unsigned char)c)
685 return DISCARD_QUAL(ptr, void);
686 ptr++;
687 n--;
688 } while (n != 0);
689 }
690 return NULL;
691 }
692
693 unsigned long
strtoul(const char * cp,char ** endp,int base)694 strtoul(const char *cp, char **endp, int base)
695 {
696 ulong result, value;
697 bool minus;
698
699 minus = FALSE;
700
701 while (bcm_isspace(*cp))
702 cp++;
703
704 if (cp[0] == '+')
705 cp++;
706 else if (cp[0] == '-') {
707 minus = TRUE;
708 cp++;
709 }
710
711 if (base == 0) {
712 if (cp[0] == '0') {
713 if ((cp[1] == 'x') || (cp[1] == 'X')) {
714 base = 16;
715 cp = &cp[2];
716 } else {
717 base = 8;
718 cp = &cp[1];
719 }
720 } else
721 base = 10;
722 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
723 cp = &cp[2];
724 }
725
726 result = 0;
727
728 while (bcm_isxdigit(*cp) &&
729 (value = bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) <
730 (ulong) base) {
731 result = result * base + value;
732 cp++;
733 }
734
735 if (minus)
736 result = (ulong)(result * -1);
737
738 if (endp)
739 *endp = DISCARD_QUAL(cp, char);
740
741 return (result);
742 }
743
744 #ifdef EFI
745 int
putchar(int c)746 putchar(int c)
747 {
748 return putc(c, stdout);
749 }
750
751 int
puts(const char * s)752 puts(const char *s)
753 {
754 char c;
755
756 while ((c = *s++))
757 putchar(c);
758
759 putchar('\n');
760
761 return 0;
762 }
763
764 #else /* !EFI */
765
766 /* memset is not in ROM offload because it is used directly by the compiler in
767 * structure assignments/character array initialization with "".
768 */
769 void *
BCMPOSTTRAPFN(memset)770 BCMPOSTTRAPFN(memset)(void *dest, int c, size_t n)
771 {
772 uint32 w, *dw;
773 unsigned char *d;
774
775 dw = (uint32 *)dest;
776
777 /* 8 min because we have to create w */
778 if ((n >= 8) && (((uintptr)dest & 3) == 0)) {
779 if (c == 0)
780 w = 0;
781 else {
782 unsigned char ch;
783
784 ch = (unsigned char)(c & 0xff);
785 w = (ch << 8) | ch;
786 w |= w << 16;
787 }
788 while (n >= 4) {
789 *dw++ = w;
790 n -= 4;
791 }
792 }
793 d = (unsigned char *)dw;
794
795 while (n) {
796 *d++ = (unsigned char)c;
797 n--;
798 }
799
800 return dest;
801 }
802
803 /* memcpy is not in ROM offload because it is used directly by the compiler in
804 * structure assignments.
805 */
806 #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__)
807 void *
BCMPOSTTRAPFN(memcpy)808 BCMPOSTTRAPFN(memcpy)(void *dest, const void *src, size_t n)
809 {
810 uint32 *dw;
811 const uint32 *sw;
812 unsigned char *d;
813 const unsigned char *s;
814
815 sw = (const uint32 *)src;
816 dw = (uint32 *)dest;
817
818 if (n >= 4 && ((uintptr)src & 3) == ((uintptr)dest & 3)) {
819 uint32 t1, t2, t3, t4, t5, t6, t7, t8;
820 int i = (4 - ((uintptr)src & 3)) % 4;
821
822 n -= i;
823
824 d = (unsigned char *)dw;
825 s = (const unsigned char *)sw;
826 while (i--) {
827 *d++ = *s++;
828 }
829 sw = (const uint32 *)s;
830 dw = (uint32 *)d;
831
832 if (n >= 32) {
833 const uint32 *sfinal = (const uint32 *)((const uint8 *)sw + (n & ~31));
834
835 asm volatile("\n1:\t"
836 "ldmia.w\t%0!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t"
837 "stmia.w\t%1!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t"
838 "cmp\t%2, %0\n\t"
839 "bhi.n\t1b\n\t"
840 : "=r" (sw), "=r" (dw), "=r" (sfinal), "=r" (t1), "=r" (t2),
841 "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6), "=r" (t7),
842 "=r" (t8)
843 : "0" (sw), "1" (dw), "2" (sfinal));
844
845 n %= 32;
846 }
847
848 /* Copy the remaining words */
849 switch (n / 4) {
850 case 0:
851 break;
852 case 1:
853 asm volatile("ldr\t%2, [%0]\n\t"
854 "str\t%2, [%1]\n\t"
855 "adds\t%0, #4\n\t"
856 "adds\t%1, #4\n\t"
857 : "=r" (sw), "=r" (dw), "=r" (t1)
858 : "0" (sw), "1" (dw));
859 break;
860 case 2:
861 asm volatile("ldmia.w\t%0!, {%2, %3}\n\t"
862 "stmia.w\t%1!, {%2, %3}\n\t"
863 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2)
864 : "0" (sw), "1" (dw));
865 break;
866 case 3:
867 asm volatile("ldmia.w\t%0!, {%2, %3, %4}\n\t"
868 "stmia.w\t%1!, {%2, %3, %4}\n\t"
869 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2),
870 "=r" (t3)
871 : "0" (sw), "1" (dw));
872 break;
873 case 4:
874 asm volatile("ldmia.w\t%0!, {%2, %3, %4, %5}\n\t"
875 "stmia.w\t%1!, {%2, %3, %4, %5}\n\t"
876 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2),
877 "=r" (t3), "=r" (t4)
878 : "0" (sw), "1" (dw));
879 break;
880 case 5:
881 asm volatile(
882 "ldmia.w\t%0!, {%2, %3, %4, %5, %6}\n\t"
883 "stmia.w\t%1!, {%2, %3, %4, %5, %6}\n\t"
884 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2),
885 "=r" (t3), "=r" (t4), "=r" (t5)
886 : "0" (sw), "1" (dw));
887 break;
888 case 6:
889 asm volatile(
890 "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %7}\n\t"
891 "stmia.w\t%1!, {%2, %3, %4, %5, %6, %7}\n\t"
892 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2),
893 "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6)
894 : "0" (sw), "1" (dw));
895 break;
896 case 7:
897 asm volatile(
898 "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %8, %7}\n\t"
899 "stmia.w\t%1!, {%2, %3, %4, %5, %6, %8, %7}\n\t"
900 : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2),
901 "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6),
902 "=r" (t7)
903 : "0" (sw), "1" (dw));
904 break;
905 default:
906 ASSERT(0);
907 break;
908 }
909 n = n % 4;
910 }
911
912 /* Copy the remaining bytes */
913 d = (unsigned char *)dw;
914 s = (const unsigned char *)sw;
915 while (n--) {
916 *d++ = *s++;
917 }
918
919 return dest;
920 }
921
922 #ifdef __clang__
923 /* TODO: remove once toolchain builtin libraries are available */
924 /* simulate compiler builtins */
925
926 /* not aligned */
927 void *__aeabi_memcpy(void *dest, const void *src, size_t n);
928 void *
__aeabi_memcpy(void * dest,const void * src,size_t n)929 __aeabi_memcpy(void *dest, const void *src, size_t n)
930 {
931 return memcpy(dest, src, n);
932 }
933
934 /* 4 byte aligned */
935 void *__aeabi_memcpy4(void *dest, const void *src, size_t n);
936 void *
__aeabi_memcpy4(void * dest,const void * src,size_t n)937 __aeabi_memcpy4(void *dest, const void *src, size_t n)
938 {
939 return memcpy(dest, src, n);
940 }
941
942 /* 8 byte aligned */
943 void *__aeabi_memcpy8(void *dest, const void *src, size_t n);
944 void *
__aeabi_memcpy8(void * dest,const void * src,size_t n)945 __aeabi_memcpy8(void *dest, const void *src, size_t n)
946 {
947 return memcpy(dest, src, n);
948 }
949
950 /* 8 byte aligned */
951 void *__aeabi_memclr8(void *dest, size_t n);
952 void *
__aeabi_memclr8(void * dest,size_t n)953 __aeabi_memclr8(void *dest, size_t n)
954 {
955 return memset(dest, 0, n);
956 }
957 #endif /* __clang__ */
958 #else
959 void *
memcpy(void * dest,const void * src,size_t n)960 memcpy(void *dest, const void *src, size_t n)
961 {
962 uint32 *dw;
963 const uint32 *sw;
964 unsigned char *d;
965 const unsigned char *s;
966
967 sw = (const uint32 *)src;
968 dw = (uint32 *)dest;
969
970 if ((n >= 4) && (((uintptr)src & 3) == ((uintptr)dest & 3))) {
971 int i = (4 - ((uintptr)src & 3)) % 4;
972 n -= i;
973 d = (unsigned char *)dw;
974 s = (const unsigned char *)sw;
975 while (i--) {
976 *d++ = *s++;
977 }
978
979 sw = (const uint32 *)s;
980 dw = (uint32 *)d;
981 while (n >= 4) {
982 *dw++ = *sw++;
983 n -= 4;
984 }
985 }
986 d = (unsigned char *)dw;
987 s = (const unsigned char *)sw;
988 while (n--) {
989 *d++ = *s++;
990 }
991
992 return dest;
993 }
994 #endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) */
995 #endif /* EFI */
996
997 /* a hook to send printf output to the host */
998 static printf_sendup_output_fn_t g_printf_sendup_output_fn = NULL;
999 static void *g_printf_sendup_output_ctx = NULL;
1000
1001 #ifdef DONGLEBUILD
1002 static bool _rodata_overwritten = FALSE;
1003
1004 /* Ensure this string is not const. */
1005 CONST char BCMPOST_TRAP_RODATA(warn_str)[] = "RO overwritten %p\n";
1006 CONST char BCMPOST_TRAP_RODATA(time_str)[] = "%06u.%03u ";
1007 #endif /* DONGLEBUILD */
1008
1009 void
printf_set_sendup_output_fn(printf_sendup_output_fn_t fn,void * ctx)1010 printf_set_sendup_output_fn(printf_sendup_output_fn_t fn, void *ctx)
1011 {
1012 g_printf_sendup_output_fn = fn;
1013 g_printf_sendup_output_ctx = ctx;
1014 }
1015
1016 #ifdef DONGLEBUILD
1017 void
BCMPOSTTRAPFN(printf_set_rodata_invalid)1018 BCMPOSTTRAPFN(printf_set_rodata_invalid)(void)
1019 {
1020 _rodata_overwritten = TRUE;
1021 }
1022
1023 bool
printf_get_rodata_invalid(void)1024 printf_get_rodata_invalid(void)
1025 {
1026 return (_rodata_overwritten);
1027 }
1028 #endif /* DONGLEBUILD */
1029
1030 /* Include printf if it has already not been defined as NULL */
1031 #ifndef printf
1032 static bool last_nl = FALSE;
1033 int
BCMPOSTTRAPFN(printf)1034 BCMPOSTTRAPFN(printf)(const char *fmt, ...)
1035 {
1036 va_list ap;
1037 int count = 0, i;
1038 char buffer[PRINTF_BUFLEN + 1];
1039
1040 if (FWSIGN_ENAB()) {
1041 return 0;
1042 }
1043
1044 if (!printf_lock())
1045 return 0;
1046
1047 #ifdef DONGLEBUILD
1048 if (_rodata_overwritten == TRUE) {
1049 /* Regular printf will be garbage if ROdata is overwritten. In that case,
1050 * print the caller address.
1051 */
1052 _rodata_overwritten = FALSE;
1053 count = printf(warn_str, CALL_SITE);
1054 _rodata_overwritten = TRUE;
1055 return count;
1056 }
1057
1058 if (last_nl) {
1059 /* add the dongle ref time */
1060 uint32 dongle_time_ms = hnd_get_reftime_ms();
1061 count = sprintf(buffer, time_str, dongle_time_ms / 1000, dongle_time_ms % 1000);
1062 }
1063 #endif /* DONGLEBUILD */
1064
1065 va_start(ap, fmt);
1066 count += vsnprintf(buffer + count, sizeof(buffer) - count, fmt, ap);
1067 va_end(ap);
1068
1069 for (i = 0; i < count; i++) {
1070 putchar(buffer[i]);
1071
1072 /* EFI environment requires CR\LF in a printf, etc.
1073 * so unless the string has \r\n, it will not execute CR
1074 * So force it!
1075 */
1076 #ifdef EFI
1077 if (buffer[i] == '\n')
1078 putchar('\r');
1079 #endif
1080 }
1081
1082 /* send the output up to the host */
1083 if (g_printf_sendup_output_fn != NULL) {
1084 g_printf_sendup_output_fn(g_printf_sendup_output_ctx, buffer, count);
1085 }
1086
1087 if (buffer[count - 1] == '\n')
1088 last_nl = TRUE;
1089 else
1090 last_nl = FALSE;
1091
1092 printf_unlock();
1093
1094 return count;
1095 }
1096 #endif /* printf */
1097
1098 #if !defined(_WIN32) && !defined(EFI)
1099 int
fputs(const char * s,FILE * stream)1100 fputs(const char *s, FILE *stream /* UNUSED */)
1101 {
1102 char c;
1103
1104 UNUSED_PARAMETER(stream);
1105 while ((c = *s++))
1106 putchar(c);
1107 return 0;
1108 }
1109
1110 int
puts(const char * s)1111 puts(const char *s)
1112 {
1113 fputs(s, stdout);
1114 putchar('\n');
1115 return 0;
1116 }
1117
1118 int
fputc(int c,FILE * stream)1119 fputc(int c, FILE *stream)
1120 {
1121 return putc(c, stream);
1122 }
1123
1124 unsigned long
rand(void)1125 rand(void)
1126 {
1127 static unsigned long seed = 1;
1128 long x, hi, lo, t;
1129
1130 x = seed;
1131 hi = x / 127773;
1132 lo = x % 127773;
1133 t = 16807 * lo - 2836 * hi;
1134 if (t <= 0) t += 0x7fffffff;
1135 seed = t;
1136 return t;
1137 }
1138 #endif /* !_WIN32 && !EFI */
1139
1140 #endif /* BCMSTDLIB_SNPRINTF_ONLY */
1141
1142 #if !defined(_WIN32) || defined(EFI)
1143 size_t
strnlen(const char * s,size_t maxlen)1144 strnlen(const char *s, size_t maxlen)
1145 {
1146 const char *b = s;
1147 const char *e = s + maxlen;
1148
1149 while (s < e && *s) {
1150 s++;
1151 }
1152
1153 return s - b;
1154 }
1155 #endif /* !_WIN32 || EFI */
1156
1157 /* FORTIFY_SOURCE: Implementation of compiler built-in functions for C standard library functions
1158 * that provide run-time buffer overflow detection.
1159 */
1160 #if defined(BCM_FORTIFY_SOURCE)
1161
1162 void*
__memcpy_chk(void * dest,const void * src,size_t n,size_t destsz)1163 __memcpy_chk(void *dest, const void *src, size_t n, size_t destsz)
1164 {
1165 if (memcpy_s(dest, destsz, src, n) != 0) {
1166 OSL_SYS_HALT();
1167 }
1168
1169 return (dest);
1170 }
1171
1172 void *
__memmove_chk(void * dest,const void * src,size_t n,size_t destsz)1173 __memmove_chk(void *dest, const void *src, size_t n, size_t destsz)
1174 {
1175 if (memmove_s(dest, destsz, src, n) != 0) {
1176 OSL_SYS_HALT();
1177 }
1178
1179 return (dest);
1180 }
1181
1182 void *
__memset_chk(void * dest,int c,size_t n,size_t destsz)1183 __memset_chk(void *dest, int c, size_t n, size_t destsz)
1184 {
1185 if (memset_s(dest, destsz, c, n) != 0) {
1186 OSL_SYS_HALT();
1187 }
1188
1189 return (dest);
1190 }
1191
1192 int
__snprintf_chk(char * str,size_t n,int flag,size_t destsz,const char * fmt,...)1193 __snprintf_chk(char *str, size_t n, int flag, size_t destsz, const char *fmt, ...)
1194 {
1195 va_list arg;
1196 int rc;
1197
1198 if (n > destsz) {
1199 OSL_SYS_HALT();
1200 }
1201
1202 va_start(arg, fmt);
1203 rc = vsnprintf(str, n, fmt, arg);
1204 va_end(arg);
1205
1206 return (rc);
1207 }
1208
1209 int
__vsnprintf_chk(char * str,size_t n,int flags,size_t destsz,const char * fmt,va_list ap)1210 __vsnprintf_chk(char *str, size_t n, int flags, size_t destsz, const char *fmt, va_list ap)
1211 {
1212 if (n > destsz) {
1213 OSL_SYS_HALT();
1214 }
1215
1216 return (vsnprintf(str, n, fmt, ap));
1217 }
1218
1219 char *
__strncpy_chk(char * dest,const char * src,size_t n,size_t destsz)1220 __strncpy_chk(char *dest, const char *src, size_t n, size_t destsz)
1221 {
1222 if (n > destsz) {
1223 OSL_SYS_HALT();
1224 }
1225
1226 return (strncpy(dest, src, n));
1227 }
1228 #endif /* BCM_FORTIFY_SOURCE */
1229
1230 /* Provide stub implementations for xxx_s() APIs that are remapped to compiler builtins.
1231 * This allows the target to link.
1232 *
1233 * This is only intended as a compile-time test, and should be used by compile-only targets.
1234 */
1235 #if defined(BCM_STDLIB_S_BUILTINS_TEST)
1236 #undef strcpy
1237 char* strcpy(char *dest, const char *src);
1238 char*
strcpy(char * dest,const char * src)1239 strcpy(char *dest, const char *src)
1240 {
1241 return (NULL);
1242 }
1243
1244 #undef strcat
1245 char* strcat(char *dest, const char *src);
1246 char*
strcat(char * dest,const char * src)1247 strcat(char *dest, const char *src)
1248 {
1249 return (NULL);
1250 }
1251 #endif /* BCM_STDLIB_S_BUILTINS_TEST */
1252