/* * stdlib support routines for self-contained images. * * Copyright (C) 2020, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * * <> */ /* * bcmstdlib.c file should be used only to construct an OSL or alone without any OSL * It should not be used with any orbitarary OSL's as there could be a conflict * with some of the routines defined here. */ /* * Define BCMSTDLIB_WIN32_APP if this is a Win32 Application compile */ #if defined(_WIN32) && !defined(NDIS) && !defined(EFI) #define BCMSTDLIB_WIN32_APP 1 #endif /* _WIN32 && !NDIS */ /* * Define BCMSTDLIB_SNPRINTF_ONLY if we only want snprintf & vsnprintf implementations */ #if defined(_WIN32) && !defined(EFI) #define BCMSTDLIB_SNPRINTF_ONLY 1 #endif /* _WIN32 || !EFI */ #include #ifdef BCMSTDLIB_WIN32_APP /* for size_t definition */ #include #endif #include #ifndef BCMSTDLIB_WIN32_APP #include #endif #include /* Don't use compiler builtins for stdlib APIs within the implementation of the stdlib itself. */ #if defined(BCM_FORTIFY_SOURCE) || defined(BCM_STDLIB_USE_BUILTINS) #undef memcpy #undef memmove #undef memset #undef strncpy #undef snprintf #undef vsnprintf #endif /* BCM_FORTIFY_SOURCE || BCM_STDLIB_USE_BUILTINS */ #ifdef HND_PRINTF_THREAD_SAFE #include #include #include /* mutex macros for thread safe */ #define HND_PRINTF_MUTEX_DECL(mutex) static OSL_EXT_MUTEX_DECL(mutex) #define HND_PRINTF_MUTEX_CREATE(name, mutex) osl_ext_mutex_create(name, mutex) #define HND_PRINTF_MUTEX_DELETE(mutex) osl_ext_mutex_delete(mutex) #define HND_PRINTF_MUTEX_ACQUIRE(mutex, msec) osl_ext_mutex_acquire(mutex, msec) #define HND_PRINTF_MUTEX_RELEASE(mutex) osl_ext_mutex_release(mutex) HND_PRINTF_MUTEX_DECL(printf_mutex); int in_isr_handler = 0, in_trap_handler = 0, in_fiq_handler = 0; bool printf_lock_init(void) { /* create mutex for critical section locking */ if (HND_PRINTF_MUTEX_CREATE("printf_mutex", &printf_mutex) != OSL_EXT_SUCCESS) return FALSE; return TRUE; } bool printf_lock_cleanup(void) { /* create mutex for critical section locking */ if (HND_PRINTF_MUTEX_DELETE(&printf_mutex) != OSL_EXT_SUCCESS) return FALSE; return TRUE; } /* returns TRUE if allowed to proceed, FALSE to discard. * printf from isr hook or fiq hook is not allowed due to IRQ_MODE and FIQ_MODE stack size * limitation. */ static bool printf_lock(void) { /* discard for irq or fiq context, we need to keep irq/fiq stack small. */ if (in_isr_handler || in_fiq_handler) return FALSE; /* allow printf in trap handler, proceed without mutex. */ if (in_trap_handler) return TRUE; /* if not in isr or trap, then go thread-protection with mutex. */ if (HND_PRINTF_MUTEX_ACQUIRE(&printf_mutex, OSL_EXT_TIME_FOREVER) != OSL_EXT_SUCCESS) return FALSE; else return TRUE; } static void printf_unlock(void) { if (in_isr_handler || in_fiq_handler) return; if (in_trap_handler) return; if (HND_PRINTF_MUTEX_RELEASE(&printf_mutex) != OSL_EXT_SUCCESS) return; } #else #define printf_lock() (TRUE) #define printf_unlock() #endif /* HND_PRINTF_THREAD_SAFE */ #ifdef BCMSTDLIB_WIN32_APP /* for a WIN32 application, use _vsnprintf as basis of vsnprintf/snprintf to * support full set of format specifications. */ int BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t bufsize, const char *fmt, va_list ap) { int r; r = _vsnprintf(buf, bufsize, fmt, ap); /* Microsoft _vsnprintf() will not null terminate on overflow, * so null terminate at buffer end on error */ if (r < 0 && bufsize > 0) buf[bufsize - 1] = '\0'; return r; } int BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...) { va_list ap; int r; va_start(ap, fmt); r = vsnprintf(buf, bufsize, fmt, ap); va_end(ap); return r; } #else /* BCMSTDLIB_WIN32_APP */ #if !defined(BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS) static const char hex_upper[17] = "0123456789ABCDEF"; static const char hex_lower[17] = "0123456789abcdef"; static int BCMPOSTTRAPFN(__atolx)(char *buf, char * end, unsigned long num, unsigned long radix, int width, const char *digits, int zero_pad) { char buffer[32]; char *op; int retval; op = &buffer[0]; retval = 0; do { *op++ = digits[num % radix]; retval++; num /= radix; } while (num != 0); if (width && (width > retval) && zero_pad) { width = width - retval; while (width) { *op++ = '0'; retval++; width--; } } while (op != buffer) { op--; if (buf <= end) *buf = *op; buf++; } return retval; } static int BCMPOSTTRAPFN(__atox)(char *buf, char * end, unsigned int num, unsigned int radix, int width, const char *digits, int zero_pad) { char buffer[16]; char *op; int retval; op = &buffer[0]; retval = 0; do { *op++ = digits[num % radix]; retval++; num /= radix; } while (num != 0); if (width && (width > retval) && zero_pad) { width = width - retval; while (width) { *op++ = '0'; retval++; width--; } } while (op != buffer) { op--; if (buf <= end) *buf = *op; buf++; } return retval; } int BCMPOSTTRAPFN(vsnprintf)(char *buf, size_t size, const char *fmt, va_list ap) { char *optr; char *end; const char *iptr, *tmpptr; unsigned int x; int i; int islong; int width; int width2 = 0; int hashash = 0; int zero_pad; unsigned long ul = 0; long int li = 0; optr = buf; end = buf + size - 1; iptr = fmt; if (FWSIGN_ENAB()) { return 0; } if (end < buf - 1) { end = ((void *) -1); size = end - buf + 1; } while (*iptr) { zero_pad = 0; if (*iptr != '%') { if (optr <= end) *optr = *iptr; ++optr; ++iptr; continue; } iptr++; if (*iptr == '#') { hashash = 1; iptr++; } if (*iptr == '-') { iptr++; } if (*iptr == '0') { zero_pad = 1; iptr++; } width = 0; while (*iptr && bcm_isdigit(*iptr)) { width += (*iptr - '0'); iptr++; if (bcm_isdigit(*iptr)) width *= 10; } if (*iptr == '.') { iptr++; width2 = 0; while (*iptr && bcm_isdigit(*iptr)) { width2 += (*iptr - '0'); iptr++; if (bcm_isdigit(*iptr)) width2 *= 10; } } islong = 0; if (*iptr == 'l') { islong++; iptr++; if (*iptr == 'l') { ++islong; ++iptr; } } switch (*iptr) { case 's': tmpptr = va_arg(ap, const char *); if (!tmpptr) tmpptr = "(null)"; if ((width == 0) & (width2 == 0)) { while (*tmpptr) { if (optr <= end) *optr = *tmpptr; ++optr; ++tmpptr; } break; } while (width && *tmpptr) { if (optr <= end) *optr = *tmpptr; ++optr; ++tmpptr; width--; } while (width) { if (optr <= end) *optr = ' '; ++optr; width--; } break; case 'd': case 'i': if (!islong) { i = va_arg(ap, int); if (i < 0) { if (optr <= end) *optr = '-'; ++optr; i = -i; } optr += __atox(optr, end, i, 10, width, hex_upper, zero_pad); } else { li = va_arg(ap, long int); if (li < 0) { if (optr <= end) *optr = '-'; ++optr; li = -li; } optr += __atolx(optr, end, li, 10, width, hex_upper, zero_pad); } break; case 'u': if (!islong) { x = va_arg(ap, unsigned int); optr += __atox(optr, end, x, 10, width, hex_upper, zero_pad); } else { ul = va_arg(ap, unsigned long); optr += __atolx(optr, end, ul, 10, width, hex_upper, zero_pad); } break; case 'X': case 'x': if (hashash) { *optr++ = '0'; *optr++ = *iptr; } if (!islong) { x = va_arg(ap, unsigned int); optr += __atox(optr, end, x, 16, width, (*iptr == 'X') ? hex_upper : hex_lower, zero_pad); } else { ul = va_arg(ap, unsigned long); optr += __atolx(optr, end, ul, 16, width, (*iptr == 'X') ? hex_upper : hex_lower, zero_pad); } break; case 'p': case 'P': x = va_arg(ap, unsigned int); optr += __atox(optr, end, x, 16, 8, (*iptr == 'P') ? hex_upper : hex_lower, zero_pad); break; case 'c': x = va_arg(ap, int); if (optr <= end) *optr = x & 0xff; optr++; break; default: if (optr <= end) *optr = *iptr; optr++; break; } iptr++; } if (optr <= end) { *optr = '\0'; return (int)(optr - buf); } else { *end = '\0'; return (int)(end - buf); } } int BCMPOSTTRAPFN(snprintf)(char *buf, size_t bufsize, const char *fmt, ...) { va_list ap; int r; if (FWSIGN_ENAB()) { return 0; } va_start(ap, fmt); r = vsnprintf(buf, bufsize, fmt, ap); va_end(ap); return r; } #endif /* !BCMROMOFFLOAD_EXCLUDE_STDLIB_FUNCS */ #endif /* BCMSTDLIB_WIN32_APP */ #ifndef BCMSTDLIB_SNPRINTF_ONLY int BCMPOSTTRAPFN(vsprintf)(char *buf, const char *fmt, va_list ap) { if (FWSIGN_ENAB()) { return 0; } return (vsnprintf(buf, INT_MAX, fmt, ap)); } int BCMPOSTTRAPFN(sprintf)(char *buf, const char *fmt, ...) { va_list ap; int count; if (FWSIGN_ENAB()) { return 0; } va_start(ap, fmt); count = vsprintf(buf, fmt, ap); va_end(ap); return count; } #if !defined(EFI) || !defined(COMPILER_INTRINSICS_LIB) void * memmove(void *dest, const void *src, size_t n) { /* only use memcpy if there is no overlap. otherwise copy each byte in a safe sequence */ if (((const char *)src >= (char *)dest + n) || ((const char *)src + n <= (char *)dest)) { return memcpy(dest, src, n); } /* Overlapping copy forward or backward */ if (src < dest) { unsigned char *d = (unsigned char *)dest + (n - 1); const unsigned char *s = (const unsigned char *)src + (n - 1); while (n) { *d-- = *s--; n--; } } else if (src > dest) { unsigned char *d = (unsigned char *)dest; const unsigned char *s = (const unsigned char *)src; while (n) { *d++ = *s++; n--; } } return dest; } #endif /* !EFI || !COMPILER_INTRINSICS_LIB */ #ifndef EFI int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *ss1; const unsigned char *ss2; ss1 = (const unsigned char *)s1; ss2 = (const unsigned char *)s2; while (n) { if (*ss1 < *ss2) return -1; if (*ss1 > *ss2) return 1; ss1++; ss2++; n--; } return 0; } /* Skip over functions that are being used from DriverLibrary to save space */ char * strncpy(char *dest, const char *src, size_t n) { char *endp; char *p; p = dest; endp = p + n; while (p != endp && (*p++ = *src++) != '\0') ; /* zero fill remainder */ bzero(p, (endp - p)); return dest; } size_t BCMPOSTTRAPFN(strlen)(const char *s) { size_t n = 0; while (*s) { s++; n++; } return n; } int BCMPOSTTRAPFN(strcmp)(const char *s1, const char *s2) { while (*s2 && *s1) { if (*s1 < *s2) return -1; if (*s1 > *s2) return 1; s1++; s2++; } if (*s1 && !*s2) return 1; if (!*s1 && *s2) return -1; return 0; } #endif /* EFI */ int strncmp(const char *s1, const char *s2, size_t n) { while (*s2 && *s1 && n) { if (*s1 < *s2) return -1; if (*s1 > *s2) return 1; s1++; s2++; n--; } if (!n) return 0; if (*s1 && !*s2) return 1; if (!*s1 && *s2) return -1; return 0; } char * strchr(const char *str, int c) { const char *x = str; while (*x != (char)c) { if (*x++ == '\0') return (NULL); } return DISCARD_QUAL(x, char); } char * strrchr(const char *str, int c) { const char *save = NULL; do { if (*str == (char)c) save = str; } while (*str++ != '\0'); return DISCARD_QUAL(save, char); } /* Skip over functions that are being used from DriverLibrary to save space */ #ifndef EFI char * strstr(const char *s, const char *substr) { int substr_len = strlen(substr); for (; *s; s++) if (strncmp(s, substr, substr_len) == 0) return DISCARD_QUAL(s, char); return NULL; } #endif /* EFI */ size_t strspn(const char *s, const char *accept) { uint count = 0; while (s[count] && strchr(accept, s[count])) count++; return count; } size_t strcspn(const char *s, const char *reject) { uint count = 0; while (s[count] && !strchr(reject, s[count])) count++; return count; } void * memchr(const void *s, int c, size_t n) { if (n != 0) { const unsigned char *ptr = s; do { if (*ptr == (unsigned char)c) return DISCARD_QUAL(ptr, void); ptr++; n--; } while (n != 0); } return NULL; } unsigned long strtoul(const char *cp, char **endp, int base) { ulong result, value; bool minus; minus = FALSE; while (bcm_isspace(*cp)) cp++; if (cp[0] == '+') cp++; else if (cp[0] == '-') { minus = TRUE; cp++; } if (base == 0) { if (cp[0] == '0') { if ((cp[1] == 'x') || (cp[1] == 'X')) { base = 16; cp = &cp[2]; } else { base = 8; cp = &cp[1]; } } else base = 10; } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { cp = &cp[2]; } result = 0; while (bcm_isxdigit(*cp) && (value = bcm_isdigit(*cp) ? *cp - '0' : bcm_toupper(*cp) - 'A' + 10) < (ulong) base) { result = result * base + value; cp++; } if (minus) result = (ulong)(result * -1); if (endp) *endp = DISCARD_QUAL(cp, char); return (result); } #ifdef EFI int putchar(int c) { return putc(c, stdout); } int puts(const char *s) { char c; while ((c = *s++)) putchar(c); putchar('\n'); return 0; } #else /* !EFI */ /* memset is not in ROM offload because it is used directly by the compiler in * structure assignments/character array initialization with "". */ void * BCMPOSTTRAPFN(memset)(void *dest, int c, size_t n) { uint32 w, *dw; unsigned char *d; dw = (uint32 *)dest; /* 8 min because we have to create w */ if ((n >= 8) && (((uintptr)dest & 3) == 0)) { if (c == 0) w = 0; else { unsigned char ch; ch = (unsigned char)(c & 0xff); w = (ch << 8) | ch; w |= w << 16; } while (n >= 4) { *dw++ = w; n -= 4; } } d = (unsigned char *)dw; while (n) { *d++ = (unsigned char)c; n--; } return dest; } /* memcpy is not in ROM offload because it is used directly by the compiler in * structure assignments. */ #if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) void * BCMPOSTTRAPFN(memcpy)(void *dest, const void *src, size_t n) { uint32 *dw; const uint32 *sw; unsigned char *d; const unsigned char *s; sw = (const uint32 *)src; dw = (uint32 *)dest; if (n >= 4 && ((uintptr)src & 3) == ((uintptr)dest & 3)) { uint32 t1, t2, t3, t4, t5, t6, t7, t8; int i = (4 - ((uintptr)src & 3)) % 4; n -= i; d = (unsigned char *)dw; s = (const unsigned char *)sw; while (i--) { *d++ = *s++; } sw = (const uint32 *)s; dw = (uint32 *)d; if (n >= 32) { const uint32 *sfinal = (const uint32 *)((const uint8 *)sw + (n & ~31)); asm volatile("\n1:\t" "ldmia.w\t%0!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t" "stmia.w\t%1!, {%3, %4, %5, %6, %7, %8, %9, %10}\n\t" "cmp\t%2, %0\n\t" "bhi.n\t1b\n\t" : "=r" (sw), "=r" (dw), "=r" (sfinal), "=r" (t1), "=r" (t2), "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6), "=r" (t7), "=r" (t8) : "0" (sw), "1" (dw), "2" (sfinal)); n %= 32; } /* Copy the remaining words */ switch (n / 4) { case 0: break; case 1: asm volatile("ldr\t%2, [%0]\n\t" "str\t%2, [%1]\n\t" "adds\t%0, #4\n\t" "adds\t%1, #4\n\t" : "=r" (sw), "=r" (dw), "=r" (t1) : "0" (sw), "1" (dw)); break; case 2: asm volatile("ldmia.w\t%0!, {%2, %3}\n\t" "stmia.w\t%1!, {%2, %3}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2) : "0" (sw), "1" (dw)); break; case 3: asm volatile("ldmia.w\t%0!, {%2, %3, %4}\n\t" "stmia.w\t%1!, {%2, %3, %4}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), "=r" (t3) : "0" (sw), "1" (dw)); break; case 4: asm volatile("ldmia.w\t%0!, {%2, %3, %4, %5}\n\t" "stmia.w\t%1!, {%2, %3, %4, %5}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), "=r" (t3), "=r" (t4) : "0" (sw), "1" (dw)); break; case 5: asm volatile( "ldmia.w\t%0!, {%2, %3, %4, %5, %6}\n\t" "stmia.w\t%1!, {%2, %3, %4, %5, %6}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), "=r" (t3), "=r" (t4), "=r" (t5) : "0" (sw), "1" (dw)); break; case 6: asm volatile( "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %7}\n\t" "stmia.w\t%1!, {%2, %3, %4, %5, %6, %7}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6) : "0" (sw), "1" (dw)); break; case 7: asm volatile( "ldmia.w\t%0!, {%2, %3, %4, %5, %6, %8, %7}\n\t" "stmia.w\t%1!, {%2, %3, %4, %5, %6, %8, %7}\n\t" : "=r" (sw), "=r" (dw), "=r" (t1), "=r" (t2), "=r" (t3), "=r" (t4), "=r" (t5), "=r" (t6), "=r" (t7) : "0" (sw), "1" (dw)); break; default: ASSERT(0); break; } n = n % 4; } /* Copy the remaining bytes */ d = (unsigned char *)dw; s = (const unsigned char *)sw; while (n--) { *d++ = *s++; } return dest; } #ifdef __clang__ /* TODO: remove once toolchain builtin libraries are available */ /* simulate compiler builtins */ /* not aligned */ void *__aeabi_memcpy(void *dest, const void *src, size_t n); void * __aeabi_memcpy(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } /* 4 byte aligned */ void *__aeabi_memcpy4(void *dest, const void *src, size_t n); void * __aeabi_memcpy4(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } /* 8 byte aligned */ void *__aeabi_memcpy8(void *dest, const void *src, size_t n); void * __aeabi_memcpy8(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } /* 8 byte aligned */ void *__aeabi_memclr8(void *dest, size_t n); void * __aeabi_memclr8(void *dest, size_t n) { return memset(dest, 0, n); } #endif /* __clang__ */ #else void * memcpy(void *dest, const void *src, size_t n) { uint32 *dw; const uint32 *sw; unsigned char *d; const unsigned char *s; sw = (const uint32 *)src; dw = (uint32 *)dest; if ((n >= 4) && (((uintptr)src & 3) == ((uintptr)dest & 3))) { int i = (4 - ((uintptr)src & 3)) % 4; n -= i; d = (unsigned char *)dw; s = (const unsigned char *)sw; while (i--) { *d++ = *s++; } sw = (const uint32 *)s; dw = (uint32 *)d; while (n >= 4) { *dw++ = *sw++; n -= 4; } } d = (unsigned char *)dw; s = (const unsigned char *)sw; while (n--) { *d++ = *s++; } return dest; } #endif /* defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) */ #endif /* EFI */ /* a hook to send printf output to the host */ static printf_sendup_output_fn_t g_printf_sendup_output_fn = NULL; static void *g_printf_sendup_output_ctx = NULL; #ifdef DONGLEBUILD static bool _rodata_overwritten = FALSE; /* Ensure this string is not const. */ CONST char BCMPOST_TRAP_RODATA(warn_str)[] = "RO overwritten %p\n"; CONST char BCMPOST_TRAP_RODATA(time_str)[] = "%06u.%03u "; #endif /* DONGLEBUILD */ void printf_set_sendup_output_fn(printf_sendup_output_fn_t fn, void *ctx) { g_printf_sendup_output_fn = fn; g_printf_sendup_output_ctx = ctx; } #ifdef DONGLEBUILD void BCMPOSTTRAPFN(printf_set_rodata_invalid)(void) { _rodata_overwritten = TRUE; } bool printf_get_rodata_invalid(void) { return (_rodata_overwritten); } #endif /* DONGLEBUILD */ /* Include printf if it has already not been defined as NULL */ #ifndef printf static bool last_nl = FALSE; int BCMPOSTTRAPFN(printf)(const char *fmt, ...) { va_list ap; int count = 0, i; char buffer[PRINTF_BUFLEN + 1]; if (FWSIGN_ENAB()) { return 0; } if (!printf_lock()) return 0; #ifdef DONGLEBUILD if (_rodata_overwritten == TRUE) { /* Regular printf will be garbage if ROdata is overwritten. In that case, * print the caller address. */ _rodata_overwritten = FALSE; count = printf(warn_str, CALL_SITE); _rodata_overwritten = TRUE; return count; } if (last_nl) { /* add the dongle ref time */ uint32 dongle_time_ms = hnd_get_reftime_ms(); count = sprintf(buffer, time_str, dongle_time_ms / 1000, dongle_time_ms % 1000); } #endif /* DONGLEBUILD */ va_start(ap, fmt); count += vsnprintf(buffer + count, sizeof(buffer) - count, fmt, ap); va_end(ap); for (i = 0; i < count; i++) { putchar(buffer[i]); /* EFI environment requires CR\LF in a printf, etc. * so unless the string has \r\n, it will not execute CR * So force it! */ #ifdef EFI if (buffer[i] == '\n') putchar('\r'); #endif } /* send the output up to the host */ if (g_printf_sendup_output_fn != NULL) { g_printf_sendup_output_fn(g_printf_sendup_output_ctx, buffer, count); } if (buffer[count - 1] == '\n') last_nl = TRUE; else last_nl = FALSE; printf_unlock(); return count; } #endif /* printf */ #if !defined(_WIN32) && !defined(EFI) int fputs(const char *s, FILE *stream /* UNUSED */) { char c; UNUSED_PARAMETER(stream); while ((c = *s++)) putchar(c); return 0; } int puts(const char *s) { fputs(s, stdout); putchar('\n'); return 0; } int fputc(int c, FILE *stream) { return putc(c, stream); } unsigned long rand(void) { static unsigned long seed = 1; long x, hi, lo, t; x = seed; hi = x / 127773; lo = x % 127773; t = 16807 * lo - 2836 * hi; if (t <= 0) t += 0x7fffffff; seed = t; return t; } #endif /* !_WIN32 && !EFI */ #endif /* BCMSTDLIB_SNPRINTF_ONLY */ #if !defined(_WIN32) || defined(EFI) size_t strnlen(const char *s, size_t maxlen) { const char *b = s; const char *e = s + maxlen; while (s < e && *s) { s++; } return s - b; } #endif /* !_WIN32 || EFI */ /* FORTIFY_SOURCE: Implementation of compiler built-in functions for C standard library functions * that provide run-time buffer overflow detection. */ #if defined(BCM_FORTIFY_SOURCE) void* __memcpy_chk(void *dest, const void *src, size_t n, size_t destsz) { if (memcpy_s(dest, destsz, src, n) != 0) { OSL_SYS_HALT(); } return (dest); } void * __memmove_chk(void *dest, const void *src, size_t n, size_t destsz) { if (memmove_s(dest, destsz, src, n) != 0) { OSL_SYS_HALT(); } return (dest); } void * __memset_chk(void *dest, int c, size_t n, size_t destsz) { if (memset_s(dest, destsz, c, n) != 0) { OSL_SYS_HALT(); } return (dest); } int __snprintf_chk(char *str, size_t n, int flag, size_t destsz, const char *fmt, ...) { va_list arg; int rc; if (n > destsz) { OSL_SYS_HALT(); } va_start(arg, fmt); rc = vsnprintf(str, n, fmt, arg); va_end(arg); return (rc); } int __vsnprintf_chk(char *str, size_t n, int flags, size_t destsz, const char *fmt, va_list ap) { if (n > destsz) { OSL_SYS_HALT(); } return (vsnprintf(str, n, fmt, ap)); } char * __strncpy_chk(char *dest, const char *src, size_t n, size_t destsz) { if (n > destsz) { OSL_SYS_HALT(); } return (strncpy(dest, src, n)); } #endif /* BCM_FORTIFY_SOURCE */ /* Provide stub implementations for xxx_s() APIs that are remapped to compiler builtins. * This allows the target to link. * * This is only intended as a compile-time test, and should be used by compile-only targets. */ #if defined(BCM_STDLIB_S_BUILTINS_TEST) #undef strcpy char* strcpy(char *dest, const char *src); char* strcpy(char *dest, const char *src) { return (NULL); } #undef strcat char* strcat(char *dest, const char *src); char* strcat(char *dest, const char *src) { return (NULL); } #endif /* BCM_STDLIB_S_BUILTINS_TEST */