From 870ce3ddd3b33c59418a7dba703e8a66ec75f98f Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Wed, 15 Aug 2018 17:02:28 +0100 Subject: libc: Move tf_printf and tf_snprintf to libc Change their names to printf and snprintf. They are much smaller than the previous versions we had, which makes them better suited for the Trusted Firmware. Change-Id: Ia872af91b7b967c47fce012eccecede7873a3daf Signed-off-by: Antonio Nino Diaz --- Makefile | 2 - common/tf_log.c | 8 +- common/tf_printf.c | 193 ------------------------------------ common/tf_snprintf.c | 125 ----------------------- docs/psci-lib-integration-guide.rst | 10 +- include/common/debug.h | 10 +- include/lib/libc/stdio.h | 10 +- lib/libc/libc.mk | 4 +- lib/libc/printf.c | 190 +++++++++++++++++++++++++++++++++++ lib/libc/snprintf.c | 125 +++++++++++++++++++++++ 10 files changed, 329 insertions(+), 348 deletions(-) delete mode 100644 common/tf_printf.c delete mode 100644 common/tf_snprintf.c create mode 100644 lib/libc/printf.c create mode 100644 lib/libc/snprintf.c diff --git a/Makefile b/Makefile index cb7eb08c..e7ca14a5 100644 --- a/Makefile +++ b/Makefile @@ -202,8 +202,6 @@ include lib/libc/libc.mk BL_COMMON_SOURCES += common/bl_common.c \ common/tf_log.c \ - common/tf_printf.c \ - common/tf_snprintf.c \ common/${ARCH}/debug.S \ lib/${ARCH}/cache_helpers.S \ lib/${ARCH}/misc_helpers.S \ diff --git a/common/tf_log.c b/common/tf_log.c index 54c0a436..6da1e85b 100644 --- a/common/tf_log.c +++ b/common/tf_log.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -36,11 +36,11 @@ void tf_log(const char *fmt, ...) prefix_str = plat_log_get_prefix(log_level); - if (prefix_str != NULL) - tf_string_print(prefix_str); + while (*prefix_str) + putchar(*prefix_str++); va_start(args, fmt); - tf_vprintf(fmt+1, args); + vprintf(fmt + 1, args); va_end(args); } diff --git a/common/tf_printf.c b/common/tf_printf.c deleted file mode 100644 index ecf058ca..00000000 --- a/common/tf_printf.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -#include -#include -#include -#include -#include -#include -#include - -/*********************************************************** - * The tf_printf implementation for all BL stages - ***********************************************************/ - -#define get_num_va_args(_args, _lcount) \ - (((_lcount) > 1) ? va_arg(_args, long long int) : \ - ((_lcount) ? 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) ? va_arg(_args, unsigned long int) : va_arg(_args, unsigned int))) - -int tf_string_print(const char *str) -{ - int count = 0; - - assert(str); - - while (*str) { - putchar(*str++); - count++; - } - - return count; -} - -static int unsigned_num_print(unsigned long long int unum, unsigned int radix, - char padc, int padn) -{ - /* Just need enough space to store 64 bit decimal integer */ - unsigned char num_buf[20]; - int i = 0, rem, count = 0; - - do { - rem = unum % radix; - if (rem < 0xa) - num_buf[i++] = '0' + rem; - else - num_buf[i++] = 'a' + (rem - 0xa); - } while (unum /= radix); - - if (padn > 0) { - while (i < padn--) { - putchar(padc); - count++; - } - } - - while (--i >= 0) { - putchar(num_buf[i]); - count++; - } - - return count; -} - -/******************************************************************* - * Reduced format print for Trusted firmware. - * The following type specifiers are supported by this print - * %x - hexadecimal format - * %s - string format - * %d or %i - signed decimal format - * %u - unsigned decimal format - * %p - pointer format - * - * The following length specifiers are supported by this print - * %l - long int (64-bit on AArch64) - * %ll - long long int (64-bit on AArch64) - * %z - size_t sized integer formats (64 bit on AArch64) - * - * The following padding specifiers are supported by this print - * %0NN - Left-pad the number with 0s (NN is a decimal number) - * - * The print exits on all other formats specifiers other than valid - * combinations of the above specifiers. - *******************************************************************/ -int tf_vprintf(const char *fmt, va_list args) -{ - int l_count; - long long int num; - unsigned long long int unum; - char *str; - char padc = 0; /* Padding character */ - int padn; /* Number of characters to pad */ - int count = 0; /* Number of printed characters */ - - while (*fmt) { - l_count = 0; - padn = 0; - - if (*fmt == '%') { - fmt++; - /* Check the format specifier */ -loop: - switch (*fmt) { - case 'i': /* Fall through to next one */ - case 'd': - num = get_num_va_args(args, l_count); - if (num < 0) { - putchar('-'); - unum = (unsigned long long int)-num; - padn--; - } else - unum = (unsigned long long int)num; - - count += unsigned_num_print(unum, 10, - padc, padn); - break; - case 's': - str = va_arg(args, char *); - count += tf_string_print(str); - break; - case 'p': - unum = (uintptr_t)va_arg(args, void *); - if (unum) { - count += tf_string_print("0x"); - padn -= 2; - } - - count += unsigned_num_print(unum, 16, - padc, padn); - break; - case 'x': - unum = get_unum_va_args(args, l_count); - count += unsigned_num_print(unum, 16, - padc, padn); - break; - case 'z': - if (sizeof(size_t) == 8) - l_count = 2; - - fmt++; - goto loop; - case 'l': - l_count++; - fmt++; - goto loop; - case 'u': - unum = get_unum_va_args(args, l_count); - count += unsigned_num_print(unum, 10, - padc, padn); - break; - case '0': - padc = '0'; - padn = 0; - fmt++; - - while (1) { - char ch = *fmt; - if (ch < '0' || ch > '9') { - goto loop; - } - padn = (padn * 10) + (ch - '0'); - fmt++; - } - default: - /* Exit on any other format specifier */ - return -1; - } - fmt++; - continue; - } - putchar(*fmt++); - count++; - } - - return count; -} - -int tf_printf(const char *fmt, ...) -{ - int count; - va_list va; - - va_start(va, fmt); - count = tf_vprintf(fmt, va); - va_end(va); - - return count; -} diff --git a/common/tf_snprintf.c b/common/tf_snprintf.c deleted file mode 100644 index 6df13772..00000000 --- a/common/tf_snprintf.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include - -static void string_print(char **s, size_t n, size_t *chars_printed, - const char *str) -{ - while (*str) { - if (*chars_printed < n) - *(*s)++ = *str; - (*chars_printed)++; - str++; - } -} - -static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, - unsigned int unum) -{ - /* Enough for a 32-bit unsigned decimal integer (4294967295). */ - unsigned char num_buf[10]; - int i = 0, rem; - - do { - rem = unum % 10; - num_buf[i++] = '0' + rem; - } while (unum /= 10); - - while (--i >= 0) { - if (*chars_printed < n) - *(*s)++ = num_buf[i]; - (*chars_printed)++; - } -} - -/******************************************************************* - * 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 tf_snprintf(char *s, size_t n, const char *fmt, ...) -{ - va_list args; - int num; - unsigned int unum; - char *str; - size_t chars_printed = 0; - - if (n == 1) { - /* Buffer is too small to actually write anything else. */ - *s = '\0'; - n = 0; - } else if (n >= 2) { - /* Reserve space for the terminator character. */ - n--; - } - - va_start(args, fmt); - while (*fmt) { - - if (*fmt == '%') { - fmt++; - /* Check the format specifier. */ - switch (*fmt) { - case 'i': - case 'd': - num = va_arg(args, int); - - if (num < 0) { - if (chars_printed < n) - *s++ = '-'; - chars_printed++; - - unum = (unsigned int)-num; - } else { - unum = (unsigned int)num; - } - - unsigned_dec_print(&s, n, &chars_printed, unum); - break; - case 's': - str = va_arg(args, char *); - string_print(&s, n, &chars_printed, str); - break; - case 'u': - unum = va_arg(args, unsigned int); - unsigned_dec_print(&s, n, &chars_printed, unum); - break; - default: - /* Panic on any other format specifier. */ - ERROR("tf_snprintf: specifier with ASCII code '%d' not supported.", - *fmt); - plat_panic_handler(); - } - fmt++; - continue; - } - - if (chars_printed < n) - *s++ = *fmt; - fmt++; - chars_printed++; - } - - va_end(args); - - if (n > 0) - *s = '\0'; - - return chars_printed; -} diff --git a/docs/psci-lib-integration-guide.rst b/docs/psci-lib-integration-guide.rst index 47cbfcc8..d86fc29e 100644 --- a/docs/psci-lib-integration-guide.rst +++ b/docs/psci-lib-integration-guide.rst @@ -319,7 +319,7 @@ and some helper utilities for assert, print and memory operations as listed below. The TF-A source tree provides implementations for all these functions but the EL3 Runtime Software may use its own implementation. -**Functions : assert(), memcpy(), memset** +**Functions : assert(), memcpy(), memset(), printf()** These must be implemented as described in ISO C Standard. @@ -353,14 +353,6 @@ This function invalidates (flushes) the data cache for memory at address This function will be called by the PSCI library on encountering a critical failure that cannot be recovered from. This function **must not** return. -**Function : tf\_printf()** - -This is printf-compatible function, but unlike printf, it does not return any -value. The TF-A source tree provides an implementation which -is optimized for stack usage and supports only a subset of format specifiers. -The details of the format specifiers supported can be found in the -``tf_printf.c`` file in the TF-A source tree. - CPU Context management API ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/common/debug.h b/include/common/debug.h index 3c99ce50..4c5560f5 100644 --- a/include/common/debug.h +++ b/include/common/debug.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef __DEBUG_H__ -#define __DEBUG_H__ +#ifndef DEBUG_H +#define DEBUG_H /* * The log output macros print output to the console. These macros produce @@ -90,11 +90,7 @@ void __dead2 do_panic(void); void __dead2 __stack_chk_fail(void); void tf_log(const char *fmt, ...) __printflike(1, 2); -int tf_printf(const char *fmt, ...) __printflike(1, 2); -int tf_snprintf(char *s, size_t n, const char *fmt, ...) __printflike(3, 4); -int tf_vprintf(const char *fmt, va_list args); -int tf_string_print(const char *str); void tf_log_set_max_level(unsigned int log_level); #endif /* __ASSEMBLY__ */ -#endif /* __DEBUG_H__ */ +#endif /* DEBUG_H */ diff --git a/include/lib/libc/stdio.h b/include/lib/libc/stdio.h index 83fd18c5..3d9323ef 100644 --- a/include/lib/libc/stdio.h +++ b/include/lib/libc/stdio.h @@ -11,6 +11,7 @@ #ifndef STDIO_H #define STDIO_H +#include #include #ifndef NULL @@ -19,14 +20,11 @@ #define EOF -1 -int printf(const char *fmt, ...); -int snprintf(char *s, size_t n, const char *fmt, ...); -int sprintf(char *s, const char *fmt, ...); -int sscanf(const char *s, const char *fmt, ...); +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 vsnprintf(char *s, size_t n, const char *fmt, va_list arg); -int vsprintf(char *s, const char *fmt, va_list arg); +int vprintf(const char *fmt, va_list args); #endif int putchar(int c); diff --git a/lib/libc/libc.mk b/lib/libc/libc.mk index 0dee4f55..554f36bb 100644 --- a/lib/libc/libc.mk +++ b/lib/libc/libc.mk @@ -16,12 +16,12 @@ LIBC_SRCS := $(addprefix lib/libc/, \ printf.c \ putchar.c \ puts.c \ + snprintf.c \ strchr.c \ strcmp.c \ strlen.c \ strncmp.c \ - strnlen.c \ - subr_prf.c) + strnlen.c) INCLUDES += -Iinclude/lib/libc \ -Iinclude/lib/libc/$(ARCH) \ diff --git a/lib/libc/printf.c b/lib/libc/printf.c new file mode 100644 index 00000000..a1a80248 --- /dev/null +++ b/lib/libc/printf.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include + +/*********************************************************** + * The tf_printf implementation for all BL stages + ***********************************************************/ + +#define get_num_va_args(_args, _lcount) \ + (((_lcount) > 1) ? va_arg(_args, long long int) : \ + ((_lcount) ? 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) ? va_arg(_args, unsigned long int) : va_arg(_args, unsigned int))) + +static int string_print(const char *str) +{ + int count = 0; + + assert(str); + + while (*str) { + putchar(*str++); + count++; + } + + return count; +} + +static int unsigned_num_print(unsigned long long int unum, unsigned int radix, + char padc, int padn) +{ + /* Just need enough space to store 64 bit decimal integer */ + unsigned char num_buf[20]; + int i = 0, rem, count = 0; + + do { + rem = unum % radix; + if (rem < 0xa) + num_buf[i++] = '0' + rem; + else + num_buf[i++] = 'a' + (rem - 0xa); + } while (unum /= radix); + + if (padn > 0) { + while (i < padn--) { + putchar(padc); + count++; + } + } + + while (--i >= 0) { + putchar(num_buf[i]); + count++; + } + + return count; +} + +/******************************************************************* + * Reduced format print for Trusted firmware. + * The following type specifiers are supported by this print + * %x - hexadecimal format + * %s - string format + * %d or %i - signed decimal format + * %u - unsigned decimal format + * %p - pointer format + * + * The following length specifiers are supported by this print + * %l - long int (64-bit on AArch64) + * %ll - long long int (64-bit on AArch64) + * %z - size_t sized integer formats (64 bit on AArch64) + * + * The following padding specifiers are supported by this print + * %0NN - Left-pad the number with 0s (NN is a decimal number) + * + * The print exits on all other formats specifiers other than valid + * combinations of the above specifiers. + *******************************************************************/ +int vprintf(const char *fmt, va_list args) +{ + int l_count; + long long int num; + unsigned long long int unum; + char *str; + char padc = 0; /* Padding character */ + int padn; /* Number of characters to pad */ + int count = 0; /* Number of printed characters */ + + while (*fmt) { + l_count = 0; + padn = 0; + + if (*fmt == '%') { + fmt++; + /* Check the format specifier */ +loop: + switch (*fmt) { + case 'i': /* Fall through to next one */ + case 'd': + num = get_num_va_args(args, l_count); + if (num < 0) { + putchar('-'); + unum = (unsigned long long int)-num; + padn--; + } else + unum = (unsigned long long int)num; + + count += unsigned_num_print(unum, 10, + padc, padn); + break; + case 's': + str = va_arg(args, char *); + count += string_print(str); + break; + case 'p': + unum = (uintptr_t)va_arg(args, void *); + if (unum) { + count += string_print("0x"); + padn -= 2; + } + + count += unsigned_num_print(unum, 16, + padc, padn); + break; + case 'x': + unum = get_unum_va_args(args, l_count); + count += unsigned_num_print(unum, 16, + padc, padn); + break; + case 'z': + if (sizeof(size_t) == 8) + l_count = 2; + + fmt++; + goto loop; + case 'l': + l_count++; + fmt++; + goto loop; + case 'u': + unum = get_unum_va_args(args, l_count); + count += unsigned_num_print(unum, 10, + padc, padn); + break; + case '0': + padc = '0'; + padn = 0; + fmt++; + + while (1) { + char ch = *fmt; + if (ch < '0' || ch > '9') { + goto loop; + } + padn = (padn * 10) + (ch - '0'); + fmt++; + } + default: + /* Exit on any other format specifier */ + return -1; + } + fmt++; + continue; + } + putchar(*fmt++); + count++; + } + + return count; +} + +int printf(const char *fmt, ...) +{ + int count; + va_list va; + + va_start(va, fmt); + count = vprintf(fmt, va); + va_end(va); + + return count; +} diff --git a/lib/libc/snprintf.c b/lib/libc/snprintf.c new file mode 100644 index 00000000..0738a869 --- /dev/null +++ b/lib/libc/snprintf.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +static void string_print(char **s, size_t n, size_t *chars_printed, + const char *str) +{ + while (*str) { + if (*chars_printed < n) + *(*s)++ = *str; + (*chars_printed)++; + str++; + } +} + +static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, + unsigned int unum) +{ + /* Enough for a 32-bit unsigned decimal integer (4294967295). */ + unsigned char num_buf[10]; + int i = 0, rem; + + do { + rem = unum % 10; + num_buf[i++] = '0' + rem; + } while (unum /= 10); + + while (--i >= 0) { + if (*chars_printed < n) + *(*s)++ = num_buf[i]; + (*chars_printed)++; + } +} + +/******************************************************************* + * 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 num; + unsigned int unum; + char *str; + size_t chars_printed = 0; + + if (n == 1) { + /* Buffer is too small to actually write anything else. */ + *s = '\0'; + n = 0; + } else if (n >= 2) { + /* Reserve space for the terminator character. */ + n--; + } + + va_start(args, fmt); + while (*fmt) { + + if (*fmt == '%') { + fmt++; + /* Check the format specifier. */ + switch (*fmt) { + case 'i': + case 'd': + num = va_arg(args, int); + + if (num < 0) { + if (chars_printed < n) + *s++ = '-'; + chars_printed++; + + unum = (unsigned int)-num; + } else { + unum = (unsigned int)num; + } + + unsigned_dec_print(&s, n, &chars_printed, unum); + break; + case 's': + str = va_arg(args, char *); + string_print(&s, n, &chars_printed, str); + break; + case 'u': + unum = va_arg(args, unsigned int); + unsigned_dec_print(&s, n, &chars_printed, unum); + break; + default: + /* Panic on any other format specifier. */ + ERROR("snprintf: specifier with ASCII code '%d' not supported.", + *fmt); + plat_panic_handler(); + } + fmt++; + continue; + } + + if (chars_printed < n) + *s++ = *fmt; + fmt++; + chars_printed++; + } + + va_end(args); + + if (n > 0) + *s = '\0'; + + return chars_printed; +} -- cgit v1.2.3