From e5d30b78b7720ba3e511819b7fc51c11d642153b Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Thu, 25 Mar 2010 22:15:19 +0000 Subject: [PATCH] libpayload update * rework Config.in * add string_to_args function to actually make getopt usable. * add strchr * add strlcat * some malloc fixes (exposed by the USB stack) * add malloc debugging (thanks to Matthias Krause from Secunet!) * make LAR support optional, it's not really used anymore * (define htoX macros for ppc) Signed-off-by: Stefan Reinauer Acked-by: Joseph Smith git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5298 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- payloads/libpayload/Config.in | 80 +++++++++++++++-- payloads/libpayload/include/getopt.h | 5 ++ payloads/libpayload/include/libpayload.h | 80 ++++++++++++++++- .../libpayload/include/powerpc/arch/endian.h | 4 + payloads/libpayload/libc/Makefile.inc | 7 +- payloads/libpayload/libc/args.c | 88 +++++++++++++++++++ payloads/libpayload/libc/malloc.c | 64 ++++++++++++-- payloads/libpayload/libc/string.c | 49 ++++++++++- 8 files changed, 361 insertions(+), 16 deletions(-) create mode 100644 payloads/libpayload/libc/args.c diff --git a/payloads/libpayload/Config.in b/payloads/libpayload/Config.in index ae071456bf..f3606ae575 100644 --- a/payloads/libpayload/Config.in +++ b/payloads/libpayload/Config.in @@ -30,6 +30,31 @@ mainmenu "Libpayload Configuration" +menu "Generic Options" + +config EXPERIMENTAL + bool "Experimental Options" + default n + help + Prompt for experimental functionality. Attention: This is not likely + to work without problems + +config OBSOLETE + bool "Obsolete Options" + default n + help + Prompt for obsolete options. These options are for old, unsupported + features and are likely to go away in the future. + +config DEVELOPER + bool "Developer Options" + default n + help + Prompt for developer options. These options are only interesting for + libpayload developers. + +endmenu + menu "Architecture Options" choice @@ -65,6 +90,18 @@ config TINYCURSES bool "Enable tinycurses support" default y +config LAR + bool "LAR support" + default n + depends on OBSOLETE + help + LAR is the archive format of (obsolete) coreboot v3 + +config CBFS + bool "CBFS support" + default y + help + CBFS is the archive format of (obsolete) coreboot v3 endmenu menu "Console Options" @@ -197,19 +234,52 @@ config USB_EHCI NOTE: This option is not (fully) implemented yet config USB_HID - bool "Support for USB keyboards (broken)" + bool "Support for USB keyboards" depends on USB - default n + default y + help + Select this option if you want to use devices complying to the + USB HID (Human Interface Device) standard. Such devices are for + example keyboards and mice. Currently only keyboards are supported. + Say Y here unless you know exactly what you are doing. config USB_HUB - bool "Support for USB hubs (broken)" + bool "Support for USB hubs" depends on USB - default n + default y + help + Select this option if you want to compile in support for USB hubs. + Say Y here unless you know exactly what you are doing. config USB_MSC bool "Support for USB storage" depends on USB - + default y + help + Select this option if you want to compile in support for USB mass + storage devices (USB memory sticks, hard drives, CDROM/DVD drives) + Say Y here unless you know exactly what you are doing. + +endmenu + +menu "Debugging" + depends on DEVELOPER + +config DEBUG_MALLOC + bool "Debug memory allocator" + depends on USB + default n + help + Select this option if you want to debug the memory allocator. This + option logs all uses of the following functions: + + void free(void *ptr); + void *malloc(size_t size); + void *calloc(size_t nmemb, size_t size); + void *realloc(void *ptr, size_t size); + void *memalign(size_t align, size_t size); + + Say N here unless you are debugging memory allocator problems. endmenu diff --git a/payloads/libpayload/include/getopt.h b/payloads/libpayload/include/getopt.h index d5038c8e0f..d4d8135aff 100644 --- a/payloads/libpayload/include/getopt.h +++ b/payloads/libpayload/include/getopt.h @@ -75,4 +75,9 @@ extern char *suboptarg; /* getsubopt(3) external variable */ #endif //__END_DECLS +#define MAX_ARGS 16 +extern char *string_argv[MAX_ARGS]; +extern int string_argc; +int string_to_args(char *caller, char *string); + #endif /* !_GETOPT_H_ */ diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h index 4e96c6690a..12897872c9 100644 --- a/payloads/libpayload/include/libpayload.h +++ b/payloads/libpayload/include/libpayload.h @@ -43,14 +43,17 @@ #ifndef _LIBPAYLOAD_H #define _LIBPAYLOAD_H +#include #include #include #include #include #include #include -#include #include +#ifdef CONFIG_LAR +#include +#endif #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -253,11 +256,82 @@ unsigned short ipchksum(const void *ptr, unsigned long nbytes); * @defgroup malloc Memory allocation functions * @{ */ +#if defined(CONFIG_DEBUG_MALLOC) && !defined(IN_MALLOC_C) +#define free(p) \ + ({ \ + extern void print_malloc_map(void); \ + extern void free(void *); \ + printf("free(%p) called from %s:%s:%d...\n", p, __FILE__, __func__, \ + __LINE__);\ + printf("PRE free()\n"); \ + print_malloc_map(); \ + free(p); \ + printf("POST free()\n"); \ + print_malloc_map(); \ + }) +#define malloc(s) \ + ({ \ + extern void print_malloc_map(void); \ + extern void *malloc(size_t); \ + void *ptr; \ + printf("malloc(%u) called from %s:%s:%d...\n", s, __FILE__, __func__, \ + __LINE__);\ + printf("PRE malloc\n"); \ + print_malloc_map(); \ + ptr = malloc(s); \ + printf("POST malloc (ptr = %p)\n", ptr); \ + print_malloc_map(); \ + ptr; \ + }) +#define calloc(n,s) \ + ({ \ + extern void print_malloc_map(void); \ + extern void *calloc(size_t,size_t); \ + void *ptr; \ + printf("calloc(%u, %u) called from %s:%s:%d...\n", n, s, __FILE__, \ + __func__, __LINE__);\ + printf("PRE calloc\n"); \ + print_malloc_map(); \ + ptr = calloc(n,s); \ + printf("POST calloc (ptr = %p)\n", ptr); \ + print_malloc_map(); \ + ptr; \ + }) +#define realloc(p,s) \ + ({ \ + extern void print_malloc_map(void); \ + extern void *realloc(void*,size_t); \ + void *ptr; \ + printf("realloc(%p, %u) called from %s:%s:%d...\n", p, s, __FILE__, \ + __func__, __LINE__);\ + printf("PRE realloc\n"); \ + print_malloc_map(); \ + ptr = realloc(p,s); \ + printf("POST realloc (ptr = %p)\n", ptr); \ + print_malloc_map(); \ + ptr; \ + }) +#define memalign(a,s) \ + ({ \ + extern void print_malloc_map(void); \ + extern void *memalign(size_t, size_t); \ + void *ptr; \ + printf("memalign(%u, %u) called from %s:%s:%d...\n", a, s, __FILE__, \ + __func__, __LINE__);\ + printf("PRE memalign\n"); \ + print_malloc_map(); \ + ptr = memalign(a,s); \ + printf("POST realloc (ptr = %p)\n", ptr); \ + print_malloc_map(); \ + ptr; \ + }) +#else void free(void *ptr); void *malloc(size_t size); void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size); void *memalign(size_t align, size_t size); +#endif /** @} */ /** @@ -341,7 +415,9 @@ int strncmp(const char *s1, const char *s2, size_t maxlen); char *strncpy(char *d, const char *s, size_t n); char *strcpy(char *d, const char *s); char *strncat(char *d, const char *s, size_t n); +size_t strlcat(char *d, const char *s, size_t n); char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); char *strdup(const char *s); char *strstr(const char *h, const char *n); char *strsep(char **stringp, const char *delim); @@ -363,6 +439,7 @@ struct timeval { int gettimeofday(struct timeval *tv, void *tz); /** @} */ +#ifdef CONFIG_LAR /** * @defgroup lar LAR functions * @{ @@ -421,6 +498,7 @@ int lfread(void *ptr, size_t size, size_t nmemb, struct LFILE *stream); int lfseek(struct LFILE *stream, long offset, int whence); int lfclose(struct LFILE *file); /** @} */ +#endif /** * @defgroup info System information functions diff --git a/payloads/libpayload/include/powerpc/arch/endian.h b/payloads/libpayload/include/powerpc/arch/endian.h index 8ffad70f0b..1b8ff8a808 100644 --- a/payloads/libpayload/include/powerpc/arch/endian.h +++ b/payloads/libpayload/include/powerpc/arch/endian.h @@ -38,4 +38,8 @@ #define ntohll(in) (in) +#define htonw(in) ntohw(in) +#define htonl(in) ntohw(in) +#define htonll(in) ntohll(in) + #endif diff --git a/payloads/libpayload/libc/Makefile.inc b/payloads/libpayload/libc/Makefile.inc index 82906c7132..3cd98c9b98 100644 --- a/payloads/libpayload/libc/Makefile.inc +++ b/payloads/libpayload/libc/Makefile.inc @@ -30,5 +30,10 @@ TARGETS-$(CONFIG_LIBC) += libc/malloc.o libc/printf.o libc/console.o libc/string.o TARGETS-$(CONFIG_LIBC) += libc/memory.o libc/ctype.o libc/ipchecksum.o libc/lib.o -TARGETS-$(CONFIG_LIBC) += libc/rand.o libc/time.o libc/lar.o libc/exec.o +TARGETS-$(CONFIG_LIBC) += libc/rand.o libc/time.o libc/exec.o TARGETS-$(CONFIG_LIBC) += libc/readline.o libc/getopt_long.o libc/sysinfo.o +TARGETS-$(CONFIG_LIBC) += libc/args.o + +# should be moved to coreboot directory +TARGETS-$(CONFIG_LAR) += libc/lar.o +#TARGETS-$(CONFIG_CBFS) += libc/cbfs.o diff --git a/payloads/libpayload/libc/args.c b/payloads/libpayload/libc/args.c new file mode 100644 index 0000000000..8242d60bba --- /dev/null +++ b/payloads/libpayload/libc/args.c @@ -0,0 +1,88 @@ +/* + * This file is part of the libpayload project. + * + * Copyright (C) 2008 coresystems GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * @file libc/readline.c + * Simple readline implementation + */ + +#include +#include + +/* We don't want to waste malloc on this, so we live with a small + * fixed size array + */ +char *string_argv[MAX_ARGS]; +int string_argc; + +/** + * Take a string and make char *argv[] and int argc from it. + * + * This function allows the user to use getopt on an arbitrary string. + * + * global variables valid after a successful run of string_to_args(): + * string_argc pointer to number of arguments + * string_argv pointer to argument list. + * + * @param caller to be used as argv[0] (may be NULL to ignore) + * @param string to process + * @return 0 if no error occured. + */ +int string_to_args(char *caller, char *string) +{ + int i = 0; + + if (caller) + string_argv[i++] = caller; + + if (*string) + string_argv[i++] = string; + + /* Terminate if the string ends */ + while (string && *string) { + /* whitespace occured? */ + if ((*string == ' ') || (*string == '\t')) { + /* skip all whitespace (and null it) */ + while (*string == ' ' || *string == '\t') + *string++ = 0; + /* if our ugly static array is big enough, store + * argument to string_argv[] + */ + if (i < MAX_ARGS) + string_argv[i++] = string; + } + string++; + } + + /* prevent array from overflowing */ + string_argc = (i <= MAX_ARGS) ? i : MAX_ARGS; + + /* and return whether there was an overflow */ + return (i <= MAX_ARGS) ? 0 : 1; +} diff --git a/payloads/libpayload/libc/malloc.c b/payloads/libpayload/libc/malloc.c index 28b0974752..9e1dd2e575 100644 --- a/payloads/libpayload/libc/malloc.c +++ b/payloads/libpayload/libc/malloc.c @@ -2,6 +2,7 @@ * This file is part of the libpayload project. * * Copyright (C) 2008 Advanced Micro Devices, Inc. + * Copyright (C) 2008-2010 coresystems GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,6 +39,7 @@ * your buffers, kids!). */ +#define IN_MALLOC_C #include extern char _heap, _eheap; /* Defined in the ldscript. */ @@ -66,11 +68,21 @@ typedef unsigned int hdrtype_t; static int free_aligned(void* addr); void print_malloc_map(void); +#ifdef CONFIG_DEBUG_MALLOC +static int heap_initialized = 0; +static int minimal_free = 0; +#endif + static void setup(void) { int size = (unsigned int)(&_eheap - &_heap) - HDRSIZE; *((hdrtype_t *) hstart) = FREE_BLOCK(size); + +#ifdef CONFIG_DEBUG_MALLOC + heap_initialized = 1; + minimal_free = size; +#endif } static void *alloc(int len) @@ -94,7 +106,9 @@ static void *alloc(int len) int size = SIZE(header); if (!HAS_MAGIC(header) || size == 0) { - printf("memory allocator panic.\n"); + printf("memory allocator panic. (%s%s)\n", + !HAS_MAGIC(header) ? " no magic " : "", + size == 0 ? " size=0 " : ""); halt(); } @@ -268,9 +282,16 @@ struct align_region_t static struct align_region_t* align_regions = 0; -static struct align_region_t *allocate_region(struct align_region_t *old_first, int alignment, int num_elements) +static struct align_region_t *allocate_region(int alignment, int num_elements) { - struct align_region_t *new_region = malloc(sizeof(struct align_region_t)); + struct align_region_t *new_region; +#ifdef CONFIG_DEBUG_MALLOC + printf("%s(old align_regions=%p, alignment=%u, num_elements=%u)\n", + __func__, align_regions, alignment, num_elements); +#endif + + new_region = malloc(sizeof(struct align_region_t)); + if (!new_region) return NULL; new_region->alignment = alignment; @@ -282,8 +303,9 @@ static struct align_region_t *allocate_region(struct align_region_t *old_first, new_region->start_data = (void*)((u32)(new_region->start + num_elements + alignment - 1) & (~(alignment-1))); new_region->size = num_elements * alignment; new_region->free = num_elements; - new_region->next = old_first; + new_region->next = align_regions; memset(new_region->start, 0, num_elements); + align_regions = new_region; return new_region; } @@ -325,15 +347,29 @@ look_further: { if ((reg->alignment == align) && (reg->free >= (size + align - 1)/align)) { +#ifdef CONFIG_DEBUG_MALLOC + printf(" found memalign region. %x free, %x required\n", reg->free, (size + align - 1)/align); +#endif break; } reg = reg->next; } if (reg == 0) { - align_regions = allocate_region(align_regions, align, (size/align<99)?100:((size/align)+1)); - reg = align_regions; +#ifdef CONFIG_DEBUG_MALLOC + printf(" need to allocate a new memalign region\n"); +#endif + /* get align regions */ + reg = allocate_region(align, (size<1024)?(1024/align):(((size-1)/align)+1)); +#ifdef CONFIG_DEBUG_MALLOC + printf(" ... returned %p\n", align_regions); +#endif } + if (reg == 0) { + /* Nothing available. */ + return (void *)NULL; + } + int i, count = 0, target = (size+align-1)/align; for (i = 0; i < (reg->size/align); i++) { @@ -358,16 +394,20 @@ look_further: } /* This is for debugging purposes. */ -#ifdef TEST +#ifdef CONFIG_DEBUG_MALLOC void print_malloc_map(void) { void *ptr = hstart; + int free_memory = 0; while (ptr < hend) { hdrtype_t hdr = *((hdrtype_t *) ptr); if (!HAS_MAGIC(hdr)) { - printf("Poisoned magic - we're toast\n"); + if (heap_initialized) + printf("Poisoned magic - we're toast\n"); + else + printf("No magic yet - going to initialize\n"); break; } @@ -377,7 +417,15 @@ void print_malloc_map(void) (unsigned int)(ptr - hstart), hdr & FLAG_FREE ? "FREE" : "USED", SIZE(hdr)); + if (hdr & FLAG_FREE) + free_memory += SIZE(hdr); + ptr += HDRSIZE + SIZE(hdr); } + + if (free_memory && (minimal_free > free_memory)) + minimal_free = free_memory; + printf("Maximum memory consumption: %d bytes", + (unsigned int)(&_eheap - &_heap) - HDRSIZE - minimal_free); } #endif diff --git a/payloads/libpayload/libc/string.c b/payloads/libpayload/libc/string.c index 81cce26a61..b69fab6815 100644 --- a/payloads/libpayload/libc/string.c +++ b/payloads/libpayload/libc/string.c @@ -171,7 +171,9 @@ char *strcpy(char *d, const char *s) char *strncat(char *d, const char *s, size_t n) { char *p = d + strlen(d); - int max = n > strlen(s) ? strlen(s) : n; + int sl = strlen(s); + int max = n > sl ? sl : n; + // int max = n > strlen(s) ? strlen(s) : n; int i; for (i = 0; i < max; i++) @@ -181,6 +183,30 @@ char *strncat(char *d, const char *s, size_t n) return d; } +/** + * Concatenates two strings with a maximum length. + * + * @param d The destination string. + * @param s The source string. + * @param n Not more than n characters from s will be appended to d. + * @return A pointer to the destination string. + */ +size_t strlcat(char *d, const char *s, size_t n) +{ + int sl = strlen(s); + int dl = strlen(d); + + char *p = d + dl; + int max = n > (sl + dl) ? sl : (n - dl - 1); + int i; + + for (i = 0; i < max; i++) + p[i] = s[i]; + + p[i] = '\0'; + return max; +} + /** * Find a character in a string. * @@ -201,6 +227,27 @@ char *strchr(const char *s, int c) return NULL; } +/** + * Find a character in a string. + * + * @param s The string. + * @param c The character. + * @return A pointer to the last occurence of the character in the + * string, or NULL if the character was not encountered within the string. + */ + +char *strrchr(const char *s, int c) +{ + char *p = (char *)s + strlen(s); + + for (; p >= s; p--) { + if (*p == c) + return p; + } + + return NULL; +} + /** * Duplicate a string. *