diff options
-rw-r--r-- | include/lib/libc/assert.h | 20 | ||||
-rw-r--r-- | include/lib/libc/cdefs.h | 10 | ||||
-rw-r--r-- | include/lib/libc/stdio.h | 3 | ||||
-rw-r--r-- | include/lib/libc/stdlib.h | 5 | ||||
-rw-r--r-- | include/lib/libc/string.h | 1 | ||||
-rw-r--r-- | include/lib/libc/uuid.h | 4 | ||||
-rw-r--r-- | lib/libc/assert.c | 28 | ||||
-rw-r--r-- | lib/libc/libc.mk | 2 | ||||
-rw-r--r-- | lib/libc/printf.c | 70 | ||||
-rw-r--r-- | lib/libc/snprintf.c | 201 |
10 files changed, 233 insertions, 111 deletions
diff --git a/include/lib/libc/assert.h b/include/lib/libc/assert.h index d04f9dc04..ce631e3e4 100644 --- a/include/lib/libc/assert.h +++ b/include/lib/libc/assert.h @@ -9,33 +9,15 @@ #include <cdefs.h> -#include <platform_def.h> - #include <common/debug.h> -#ifndef PLAT_LOG_LEVEL_ASSERT -#define PLAT_LOG_LEVEL_ASSERT LOG_LEVEL -#endif - #if ENABLE_ASSERTIONS -# if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE -# define assert(e) ((e) ? (void)0 : __assert(__FILE__, __LINE__, #e)) -# elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO -# define assert(e) ((e) ? (void)0 : __assert(__FILE__, __LINE__)) -# else -# define assert(e) ((e) ? (void)0 : __assert()) -# endif +#define assert(e) ((e) ? (void)0 : __assert(__FILE__, __LINE__, #e)) #else #define assert(e) ((void)0) #endif /* ENABLE_ASSERTIONS */ -#if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE __dead2 void __assert(const char *file, unsigned int line, const char *assertion); -#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO -__dead2 void __assert(const char *file, unsigned int line); -#else -__dead2 void __assert(void); -#endif #endif /* ASSERT_H */ diff --git a/include/lib/libc/cdefs.h b/include/lib/libc/cdefs.h index 0d0072254..c3dd6f1f5 100644 --- a/include/lib/libc/cdefs.h +++ b/include/lib/libc/cdefs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -14,15 +14,11 @@ #define __unused __attribute__((__unused__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) -#if RECLAIM_INIT_CODE /* - * Add each function to a section that is unique so the functions can still - * be garbage collected + * For compatibility with TF-A codebase. */ -#define __init __section(".text.init." __FILE__ "." __XSTRING(__LINE__)) -#else #define __init -#endif + #define __printflike(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) diff --git a/include/lib/libc/stdio.h b/include/lib/libc/stdio.h index 3d9323efa..feb036ee2 100644 --- a/include/lib/libc/stdio.h +++ b/include/lib/libc/stdio.h @@ -24,7 +24,8 @@ int printf(const char *fmt, ...) __printflike(1, 2); int snprintf(char *s, size_t n, const char *fmt, ...) __printflike(3, 4); #ifdef STDARG_H -int vprintf(const char *fmt, va_list args); +int vprintf(const char *fmt, va_list args) __printflike(1, 0); +int vsnprintf(char *str, size_t size, const char *format, va_list ap) __printflike(3, 0); #endif int putchar(int c); diff --git a/include/lib/libc/stdlib.h b/include/lib/libc/stdlib.h index edd6265f5..0ef077ffd 100644 --- a/include/lib/libc/stdlib.h +++ b/include/lib/libc/stdlib.h @@ -19,8 +19,13 @@ #define _ATEXIT_MAX 1 +#define RAND_MAX 0x7ffffffd + extern void abort(void); extern int atexit(void (*func)(void)); extern void exit(int status); +int rand(void); +void srand(unsigned int seed); + #endif /* STDLIB_H */ diff --git a/include/lib/libc/string.h b/include/lib/libc/string.h index ee6eeacef..21fd08436 100644 --- a/include/lib/libc/string.h +++ b/include/lib/libc/string.h @@ -29,5 +29,6 @@ size_t strlen(const char *s); size_t strnlen(const char *s, size_t maxlen); char *strrchr(const char *p, int ch); size_t strlcpy(char * dst, const char * src, size_t dsize); +char *strncpy(char *dst, const char *src, size_t n); #endif /* STRING_H */ diff --git a/include/lib/libc/uuid.h b/include/lib/libc/uuid.h index 934fb4fdf..bdefb9172 100644 --- a/include/lib/libc/uuid.h +++ b/include/lib/libc/uuid.h @@ -34,8 +34,8 @@ #ifndef _SYS_UUID_H_ #define _SYS_UUID_H_ -#include <sys/cdefs.h> -#include <sys/_stdint.h> +#include <cdefs.h> +#include <stdint.h> /* Length of a node address (an IEEE 802 address). */ #define _UUID_NODE_LEN 6 diff --git a/lib/libc/assert.c b/lib/libc/assert.c index 60f1a8660..dbf8507d0 100644 --- a/lib/libc/assert.c +++ b/lib/libc/assert.c @@ -9,35 +9,9 @@ #include <stdio.h> #include <common/debug.h> -#include <drivers/console.h> -#include <plat/common/platform.h> -/* - * Only print the output if PLAT_LOG_LEVEL_ASSERT is higher or equal to - * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1. - */ - -#if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE void __assert(const char *file, unsigned int line, const char *assertion) { printf("ASSERT: %s:%d:%s\n", file, line, assertion); - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); -} -#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO -void __assert(const char *file, unsigned int line) -{ - printf("ASSERT: %s:%d\n", file, line); - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); -} -#else -void __assert(void) -{ - backtrace("assert"); - (void)console_flush(); - plat_panic_handler(); + panic(); } -#endif diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk index e1b5560f8..729b91c06 100644 --- a/lib/libc/libc.mk +++ b/lib/libc/libc.mk @@ -16,12 +16,14 @@ LIBC_SRCS := $(addprefix lib/libc/, \ printf.c \ putchar.c \ puts.c \ + rand.c \ snprintf.c \ strchr.c \ strcmp.c \ strlcpy.c \ strlen.c \ strncmp.c \ + strncpy.c \ strnlen.c \ strrchr.c) diff --git a/lib/libc/printf.c b/lib/libc/printf.c index 2715a72d4..60203fb32 100644 --- a/lib/libc/printf.c +++ b/lib/libc/printf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -21,17 +21,36 @@ (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \ va_arg(_args, unsigned int))) -static int string_print(const char *str) +static int string_print(const char *str, char padc, int padn) { - int count = 0; + int i = 0, count = 0; assert(str != NULL); + while (str[i] != '\0') + i++; + + if (padn > 0) { + while (i < padn) { + (void)putchar(padc); + count++; + padn--; + } + } + for ( ; *str != '\0'; str++) { (void)putchar(*str); count++; } + if (padn < 0) { + while (i < -padn) { + (void)putchar(padc); + count++; + padn++; + } + } + return count; } @@ -41,6 +60,7 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, /* Just need enough space to store 64 bit decimal integer */ char num_buf[20]; int i = 0, count = 0; + int width; unsigned int rem; do { @@ -53,8 +73,10 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, unum /= radix; } while (unum > 0U); + width = i; + if (padn > 0) { - while (i < padn) { + while (width < padn) { (void)putchar(padc); count++; padn--; @@ -66,11 +88,19 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, count++; } + if (padn < 0) { + while (width < -padn) { + (void)putchar(padc); + count++; + padn++; + } + } + return count; } /******************************************************************* - * Reduced format print for Trusted firmware. + * Simplified version of printf() with smaller memory footprint. * The following type specifiers are supported by this print * %x - hexadecimal format * %s - string format @@ -85,6 +115,8 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, * * The following padding specifiers are supported by this print * %0NN - Left-pad the number with 0s (NN is a decimal number) + * %NN - Left-pad the number or string with spaces (NN is a decimal number) + * %-NN - Right-pad the number or string with spaces (NN is a decimal number) * * The print exits on all other formats specifiers other than valid * combinations of the above specifiers. @@ -92,15 +124,18 @@ static int unsigned_num_print(unsigned long long int unum, unsigned int radix, int vprintf(const char *fmt, va_list args) { int l_count; + int left; long long int num; unsigned long long int unum; char *str; - char padc = '\0'; /* Padding character */ + char padc; /* Padding character */ int padn; /* Number of characters to pad */ int count = 0; /* Number of printed characters */ while (*fmt != '\0') { l_count = 0; + left = 0; + padc = '\0'; padn = 0; if (*fmt == '%') { @@ -108,6 +143,25 @@ int vprintf(const char *fmt, va_list args) /* Check the format specifier */ loop: switch (*fmt) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + padc = ' '; + for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) + padn = (padn * 10) + (*fmt - '0'); + if (left) + padn = -padn; + goto loop; + case '-': + left = 1; + fmt++; + goto loop; case 'i': /* Fall through to next one */ case 'd': num = get_num_va_args(args, l_count); @@ -123,12 +177,12 @@ loop: break; case 's': str = va_arg(args, char *); - count += string_print(str); + count += string_print(str, padc, padn); break; case 'p': unum = (uintptr_t)va_arg(args, void *); if (unum > 0U) { - count += string_print("0x"); + count += string_print("0x", padc, 0); padn -= 2; } diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c index 38ad1c71a..29c50df4d 100644 --- a/lib/libc/snprintf.c +++ b/lib/libc/snprintf.c @@ -1,15 +1,26 @@ /* - * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include <assert.h> #include <stdarg.h> +#include <stdlib.h> #include <common/debug.h> #include <plat/common/platform.h> +#define get_num_va_args(_args, _lcount) \ + (((_lcount) > 1) ? va_arg(_args, long long int) : \ + (((_lcount) == 1) ? va_arg(_args, long int) : \ + va_arg(_args, int))) + +#define get_unum_va_args(_args, _lcount) \ + (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \ + (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \ + va_arg(_args, unsigned int))) + static void string_print(char **s, size_t n, size_t *chars_printed, const char *str) { @@ -24,51 +35,72 @@ static void string_print(char **s, size_t n, size_t *chars_printed, } } -static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, - unsigned int unum) +static void unsigned_num_print(char **s, size_t n, size_t *count, + unsigned long long int unum, unsigned int radix, + char padc, int padn) { - /* Enough for a 32-bit unsigned decimal integer (4294967295). */ - char num_buf[10]; + /* Just need enough space to store 64 bit decimal integer */ + char num_buf[20]; int i = 0; + int width; unsigned int rem; do { - rem = unum % 10U; - num_buf[i++] = '0' + rem; - unum /= 10U; + rem = unum % radix; + if (rem < 0xa) + num_buf[i] = '0' + rem; + else + num_buf[i] = 'a' + (rem - 0xa); + i++; + unum /= radix; } while (unum > 0U); + width = i; + + if (padn > 0) { + while (width < padn) { + if (*count < n) { + *(*s) = padc; + (*s)++; + } + (*count)++; + padn--; + } + } + while (--i >= 0) { - if (*chars_printed < n) { + if (*count < n) { *(*s) = num_buf[i]; (*s)++; } + (*count)++; + } - (*chars_printed)++; + if (padn < 0) { + while (width < -padn) { + if (*count < n) { + *(*s) = padc; + (*s)++; + } + (*count)++; + padn++; + } } } -/******************************************************************* - * Reduced snprintf to be used for Trusted firmware. - * The following type specifiers are supported: - * - * %d or %i - signed decimal format - * %s - string format - * %u - unsigned decimal format - * - * The function panics on all other formats specifiers. - * - * It returns the number of characters that would be written if the - * buffer was big enough. If it returns a value lower than n, the - * whole string has been written. - *******************************************************************/ -int snprintf(char *s, size_t n, const char *fmt, ...) +/* + * Scaled down version of vsnprintf(3). + */ +int vsnprintf(char *s, size_t n, const char *fmt, va_list args) { - va_list args; - int num; - unsigned int unum; + int l_count; + int left; char *str; - size_t chars_printed = 0U; + int num; + unsigned long long int unum; + char padc; /* Padding character */ + int padn; /* Number of characters to pad */ + size_t count = 0U; if (n == 0U) { /* There isn't space for anything. */ @@ -81,63 +113,138 @@ int snprintf(char *s, size_t n, const char *fmt, ...) n--; } - va_start(args, fmt); while (*fmt != '\0') { + l_count = 0; + left = 0; + padc = '\0'; + padn = 0; if (*fmt == '%') { fmt++; /* Check the format specifier. */ +loop: switch (*fmt) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + padc = ' '; + for (padn = 0; *fmt >= '0' && *fmt <= '9'; fmt++) + padn = (padn * 10) + (*fmt - '0'); + if (left) + padn = -padn; + goto loop; + case '-': + left = 1; + fmt++; + goto loop; case 'i': case 'd': - num = va_arg(args, int); + num = get_num_va_args(args, l_count); if (num < 0) { - if (chars_printed < n) { + if (count < n) { *s = '-'; s++; } - chars_printed++; + count++; unum = (unsigned int)-num; } else { unum = (unsigned int)num; } - unsigned_dec_print(&s, n, &chars_printed, unum); + unsigned_num_print(&s, n, &count, unum, 10, + padc, padn); break; + case 'l': + l_count++; + fmt++; + goto loop; case 's': str = va_arg(args, char *); - string_print(&s, n, &chars_printed, str); + string_print(&s, n, &count, str); break; case 'u': - unum = va_arg(args, unsigned int); - unsigned_dec_print(&s, n, &chars_printed, unum); + unum = get_unum_va_args(args, l_count); + unsigned_num_print(&s, n, &count, unum, 10, + padc, padn); break; - default: - /* Panic on any other format specifier. */ - ERROR("snprintf: specifier with ASCII code '%d' not supported.", - *fmt); - plat_panic_handler(); + case 'x': + unum = get_unum_va_args(args, l_count); + unsigned_num_print(&s, n, &count, unum, 16, + padc, padn); + break; + case '0': + padc = '0'; + padn = 0; + fmt++; + + for (;;) { + char ch = *fmt; + if ((ch < '0') || (ch > '9')) { + goto loop; + } + padn = (padn * 10) + (ch - '0'); + fmt++; + } assert(0); /* Unreachable */ + default: + /* + * Exit on any other format specifier and abort + * when in debug mode. + */ + WARN("snprintf: specifier with ASCII code '%d' not supported.\n", + *fmt); + assert(0); + return -1; } fmt++; continue; } - if (chars_printed < n) { + if (count < n) { *s = *fmt; s++; } fmt++; - chars_printed++; + count++; } - va_end(args); - if (n > 0U) *s = '\0'; - return (int)chars_printed; + return (int)count; +} + +/******************************************************************* + * Reduced snprintf to be used for Trusted firmware. + * The following type specifiers are supported: + * + * %d or %i - signed decimal format + * %s - string format + * %u - unsigned decimal format + * + * The function panics on all other formats specifiers. + * + * It returns the number of characters that would be written if the + * buffer was big enough. If it returns a value lower than n, the + * whole string has been written. + *******************************************************************/ +int snprintf(char *s, size_t n, const char *fmt, ...) +{ + va_list args; + int chars_printed; + + va_start(args, fmt); + chars_printed = vsnprintf(s, n, fmt, args); + va_end(args); + + return chars_printed; } |