aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/lib/libc/assert.h20
-rw-r--r--include/lib/libc/cdefs.h10
-rw-r--r--include/lib/libc/stdio.h3
-rw-r--r--include/lib/libc/stdlib.h5
-rw-r--r--include/lib/libc/string.h1
-rw-r--r--include/lib/libc/uuid.h4
-rw-r--r--lib/libc/assert.c28
-rw-r--r--lib/libc/libc.mk2
-rw-r--r--lib/libc/printf.c70
-rw-r--r--lib/libc/snprintf.c201
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;
}