[coreboot] libpayload
Jordan Crouse
jordan.crouse at amd.com
Thu Mar 20 00:41:13 CET 2008
On 18/03/08 21:57 +0100, Uwe Hermann wrote:
> On Tue, Mar 18, 2008 at 02:46:40PM -0600, Jordan Crouse wrote:
> > With Uwe's help, we have relicensed libpayload as BSD, and we are now
> > ready to commit it to the SVN. Last step is the customary list review.
> > Please review quickly so we can get this into the tree soon with enough
> > time to hack on it before the summit.
> >
> > What follows are two patches - the first is the bulk of the code that
> > is entirely from AMD, and the second is the code that I pulled in from
> > external places. There will be a third patch from Uwe for the code that he
> > pulled in from external places himself.
>
> And here it is.
>
> Signed-off-by: Uwe Hermann <uwe at hermann-uwe.de>
Acked-by: Jordan Crouse <jordan.crouse at amd.com> (with the HOTFIX too)
>
> Uwe.
> --
> http://www.hermann-uwe.de | http://www.holsham-traders.de
> http://www.crazy-hacks.org | http://www.unmaintained-free-software.org
> diff -urN libpayload-clean/LICENSES libpayload/LICENSES
> --- libpayload-clean/LICENSES 1969-12-31 17:00:00.000000000 -0700
> +++ libpayload/LICENSES 2008-03-18 06:04:30.275010750 -0700
> @@ -0,0 +1,87 @@
> +-------------------------------------------------------------------------------
> +Copyright and Licenses
> +-------------------------------------------------------------------------------
> +
> +The copyright on libpayload is owned by various individual developers
> +and/or companies. Please check the individual source files for details.
> +
> +The libpayload code is mostly licensed under the terms of the three-clause
> +BSD license:
> +
> + 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.
> +
> +For some parts, which were taken from external projects, other (compatible)
> +licenses may apply. Please check the individual source files for details,
> +or see the section below for an overview of third-party code in libpayload.
> +
> +
> +Third-party Code and License Overview
> +-------------------------------------
> +
> +This is an overview of (modified or unmodified) third-party code in
> +libpayload, and where it was originally taken from.
> +
> +Please check the individual source code files for the list of copyright
> +holders, and the exact license terms that apply.
> +
> +* util/kconfig/*: GPLv2
> + Source: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
> + Current version we use: TODO
> +
> +* include/curses.priv.h: BSD-like license
> + Source: ncurses, http://www.gnu.org/software/ncurses/
> + Original files: ncurses/curses.priv.h
> + Current version we use: 5.6
> +
> +* include/curses.h: BSD-like license
> + Source: ncurses, http://www.gnu.org/software/ncurses/
> + Original files: include/curses.h.in
> + Current version we use: 5.6
> +
> +* libc/ipchecksum.c: 2-clause BSD license
> + Source: FreeBSD's base system libraries, http://www.freebsd.org
> + http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libalias/Attic/alias_util.c?rev=1.15;content-type=text%2Fplain
> + Original files: lib/libalias/alias_util.c, function LibAliasInternetChecksum()
> + Current version we use: CVS revision 1.15 2004/07/06 12:13:28
> +
> +* libc/memory.c: 3-clause BSD license
> + Source: HelenOS, http://www.helenos.eu
> + svn checkout svn://svn.helenos.eu/HelenOS/trunk HelenOS
> + http://svn.helenos.eu/chora/browse.php?f=%2Ftrunk%2F
> + Original files: uspace/libc/generic/string.c
> + Current version we use: r2754
> +
> +* libc/printf.c: 3-clause BSD license
> + Source: HelenOS, http://www.helenos.eu
> + svn checkout svn://svn.helenos.eu/HelenOS/trunk HelenOS
> + http://svn.helenos.eu/chora/browse.php?f=%2Ftrunk%2F
> + Original files: kernel/generic/src/printf/printf_core.c
> + kernel/generic/src/printf/sprintf.c
> + kernel/generic/src/printf/vsnprintf.c
> + kernel/generic/src/printf/vsprintf.c
> + kernel/generic/src/printf/printf.c
> + kernel/generic/src/printf/vprintf.c
> + Current version we use: r2745
> +
> diff -urN libpayload-clean/libc/ipchecksum.c libpayload/libc/ipchecksum.c
> --- libpayload-clean/libc/ipchecksum.c 1969-12-31 17:00:00.000000000 -0700
> +++ libpayload/libc/ipchecksum.c 2008-03-18 06:01:49.648972250 -0700
> @@ -0,0 +1,49 @@
> +/*
> + * This file is part of the libpayload project
> + *
> + * Copyright (c) 2001 Charles Mott <cm at linktel.net>
> + * All rights reserved.
> + *
> + * 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.
> + *
> + * 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.
> + */
> +
> +#include <libpayload.h>
> +
> +unsigned short ipchksum(const unsigned short *ptr, unsigned long nbytes)
> +{
> + int sum, oddbyte;
> +
> + sum = 0;
> + while (nbytes > 1) {
> + sum += *ptr++;
> + nbytes -= 2;
> + }
> + if (nbytes == 1) {
> + oddbyte = 0;
> + ((u8 *) &oddbyte)[0] = *(u8 *)ptr;
> + ((u8 *) &oddbyte)[1] = 0;
> + sum += oddbyte;
> + }
> + sum = (sum >> 16) + (sum & 0xffff);
> + sum += (sum >> 16);
> + return (~sum);
> +}
> diff -urN libpayload-clean/libc/memory.c libpayload/libc/memory.c
> --- libpayload-clean/libc/memory.c 1969-12-31 17:00:00.000000000 -0700
> +++ libpayload/libc/memory.c 2008-03-18 06:01:49.648972250 -0700
> @@ -0,0 +1,115 @@
> +/*
> + * This file is part of the libpayload project.
> + *
> + * It has originally been taken from the HelenOS project
> + * (http://www.helenos.eu), and slightly modified for our purposes.
> + *
> + * Copyright (c) 2005 Martin Decky
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * - Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * - 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.
> + * - 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 ``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 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.
> + */
> +
> +#include <libpayload.h>
> +
> +void *memset(void *s, int c, size_t n)
> +{
> + char *os = s;
> +
> + while (n--)
> + *(os++) = c;
> +
> + return s;
> +}
> +
> +struct along {
> + unsigned long n;
> +} __attribute__ ((packed));
> +
> +static void *unaligned_memcpy(void *dst, const void *src, size_t n)
> +{
> + int i, j;
> + struct along *adst = dst;
> + const struct along *asrc = src;
> +
> + for (i = 0; i < n / sizeof(unsigned long); i++)
> + adst[i].n = asrc[i].n;
> +
> + for (j = 0; j < n % sizeof(unsigned long); j++)
> + ((unsigned char *)(((unsigned long *)dst) + i))[j] =
> + ((unsigned char *)(((unsigned long *)src) + i))[j];
> +
> + return (char *)src;
> +}
> +
> +void *memcpy(void *dst, const void *src, size_t n)
> +{
> + int i, j;
> +
> + if (((long)dst & (sizeof(long) - 1))
> + || ((long)src & (sizeof(long) - 1)))
> + return unaligned_memcpy(dst, src, n);
> +
> + for (i = 0; i < n / sizeof(unsigned long); i++)
> + ((unsigned long *)dst)[i] = ((unsigned long *)src)[i];
> +
> + for (j = 0; j < n % sizeof(unsigned long); j++)
> + ((unsigned char *)(((unsigned long *)dst) + i))[j] =
> + ((unsigned char *)(((unsigned long *)src) + i))[j];
> +
> + return (char *)src;
> +}
> +
> +void *memmove(void *dst, const void *src, size_t n)
> +{
> + int i, j;
> +
> + if (src > dst)
> + return memcpy(dst, src, n);
> +
> + for (j = (n % sizeof(unsigned long)) - 1; j >= 0; j--)
> + ((unsigned char *)((unsigned long *)dst))[j] =
> + ((unsigned char *)((unsigned long *)src))[j];
> +
> + for (i = n / sizeof(unsigned long) - 1; i >= 0; i--)
> + ((unsigned long *)dst)[i] = ((unsigned long *)src)[i];
> +
> + return (char *)src;
> +}
> +
> +/**
> + * Compare two memory areas.
> + *
> + * @param s1 Pointer to the first area to compare.
> + * @param s2 Pointer to the second area to compare.
> + * @param len Size of the first area in bytes. Both areas must have the same
> + * length.
> + * @return If len is 0, return zero. If the areas match, return zero.
> + * Otherwise return non-zero.
> + */
> +int memcmp(const char *s1, const char *s2, size_t len)
> +{
> + for (; len && *s1++ == *s2++; len--) ;
> + return len;
> +}
> diff -urN libpayload-clean/libc/printf.c libpayload/libc/printf.c
> --- libpayload-clean/libc/printf.c 1969-12-31 17:00:00.000000000 -0700
> +++ libpayload/libc/printf.c 2008-03-18 06:01:49.652972500 -0700
> @@ -0,0 +1,816 @@
> +/*
> + * This file is part of the libpayload project.
> + *
> + * It has originally been taken from the HelenOS project
> + * (http://www.helenos.eu), and slightly modified for our purposes.
> + *
> + * Copyright (C) 2001-2004 Jakub Jermar
> + * Copyright (C) 2006 Josef Cejka
> + * Copyright (C) 2008 Uwe Hermann <uwe at hermann-uwe.de>
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + * - Redistributions of source code must retain the above copyright
> + * notice, this list of conditions and the following disclaimer.
> + * - 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.
> + * - 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 ``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 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.
> + */
> +
> +#include <libpayload.h>
> +#include <stdarg.h>
> +
> +/** Structure for specifying output methods for different printf clones. */
> +struct printf_spec {
> + /* Output function, returns count of printed characters or EOF. */
> + int (*write) (void *, size_t, void *);
> + /* Support data - output stream specification, its state, locks, ... */
> + void *data;
> +};
> +
> +/** Show prefixes 0x or 0. */
> +#define __PRINTF_FLAG_PREFIX 0x00000001
> +/** Signed / unsigned number. */
> +#define __PRINTF_FLAG_SIGNED 0x00000002
> +/** Print leading zeroes. */
> +#define __PRINTF_FLAG_ZEROPADDED 0x00000004
> +/** Align to left. */
> +#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
> +/** Always show + sign. */
> +#define __PRINTF_FLAG_SHOWPLUS 0x00000020
> +/** Print space instead of plus. */
> +#define __PRINTF_FLAG_SPACESIGN 0x00000040
> +/** Show big characters. */
> +#define __PRINTF_FLAG_BIGCHARS 0x00000080
> +/** Number has - sign. */
> +#define __PRINTF_FLAG_NEGATIVE 0x00000100
> +
> +/**
> + * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
> + * to terminate string (last one is only for better testing end of buffer by
> + * zero-filling subroutine).
> + */
> +#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
> +
> +/** Enumeration of possible arguments types. */
> +typedef enum {
> + PrintfQualifierByte = 0,
> + PrintfQualifierShort,
> + PrintfQualifierInt,
> + PrintfQualifierLong,
> + PrintfQualifierLongLong,
> + PrintfQualifierPointer,
> +} qualifier_t;
> +
> +static char digits_small[] = "0123456789abcdef";
> +static char digits_big[] = "0123456789ABCDEF";
> +
> +/**
> + * Print one or more characters without adding newline.
> + *
> + * @param buf Buffer of >= count bytesi size. NULL pointer is not allowed!
> + * @param count Number of characters to print.
> + * @param ps Output method and its data.
> + * @return Number of characters printed.
> + */
> +static int printf_putnchars(const char *buf, size_t count,
> + struct printf_spec *ps)
> +{
> + return ps->write((void *)buf, count, ps->data);
> +}
> +
> +/**
> + * Print a string without adding a newline.
> + *
> + * @param str String to print.
> + * @param ps Write function specification and support data.
> + * @return Number of characters printed.
> + */
> +static int printf_putstr(const char *str, struct printf_spec *ps)
> +{
> + size_t count;
> +
> + if (str == NULL) {
> + char *nullstr = "(NULL)";
> + return printf_putnchars(nullstr, strlen(nullstr), ps);
> + }
> +
> + count = strlen(str);
> +
> + return ps->write((void *)str, count, ps->data);
> +}
> +
> +/**
> + * Print one character.
> + *
> + * @param c Character to be printed.
> + * @param ps Output method.
> + * @return Number of characters printed.
> + */
> +static int printf_putchar(int c, struct printf_spec *ps)
> +{
> + unsigned char ch = c;
> +
> + return ps->write((void *)&ch, 1, ps->data);
> +}
> +
> +/**
> + * Print one formatted character.
> + *
> + * @param c Character to print.
> + * @param width Width modifier.
> + * @param flags Flags that change the way the character is printed.
> + * @return Number of characters printed, negative value on failure.
> + */
> +static int print_char(char c, int width, uint64_t flags, struct printf_spec *ps)
> +{
> + int counter = 0;
> +
> + if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
> + while (--width > 0) {
> + if (printf_putchar(' ', ps) > 0)
> + ++counter;
> + }
> + }
> +
> + if (printf_putchar(c, ps) > 0)
> + counter++;
> +
> + while (--width > 0) {
> + if (printf_putchar(' ', ps) > 0)
> + ++counter;
> + }
> +
> + return ++counter;
> +}
> +
> +/**
> + * Print string.
> + *
> + * @param s String to be printed.
> + * @param width Width modifier.
> + * @param precision Precision modifier.
> + * @param flags Flags that modify the way the string is printed.
> + * @return Number of characters printed, negative value on failure.
> + */
> +static int print_string(char *s, int width, unsigned int precision,
> + uint64_t flags, struct printf_spec *ps)
> +{
> + int counter = 0, retval;
> + size_t size;
> +
> + if (s == NULL)
> + return printf_putstr("(NULL)", ps);
> + size = strlen(s);
> + /* Print leading spaces. */
> + if (precision == 0)
> + precision = size;
> + width -= precision;
> +
> + if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
> + while (width-- > 0) {
> + if (printf_putchar(' ', ps) == 1)
> + counter++;
> + }
> + }
> +
> + if ((retval = printf_putnchars(s, MIN(size, precision), ps)) < 0)
> + return -counter;
> + counter += retval;
> +
> + while (width-- > 0) {
> + if (printf_putchar(' ', ps) == 1)
> + ++counter;
> + }
> +
> + return counter;
> +}
> +
> +/**
> + * Print a number in a given base.
> + *
> + * Print significant digits of a number in given base.
> + *
> + * @param num Number to print.
> + * @param widt Width modifier.h
> + * @param precision Precision modifier.
> + * @param base Base to print the number in (must be between 2 and 16).
> + * @param flags Flags that modify the way the number is printed.
> + * @return Number of characters printed.
> + */
> +static int print_number(uint64_t num, int width, int precision, int base,
> + uint64_t flags, struct printf_spec *ps)
> +{
> + char *digits = digits_small;
> + char d[PRINT_NUMBER_BUFFER_SIZE];
> + char *ptr = &d[PRINT_NUMBER_BUFFER_SIZE - 1];
> + int size = 0; /* Size of number with all prefixes and signs. */
> + int number_size; /* Size of plain number. */
> + char sgn;
> + int retval;
> + int counter = 0;
> +
> + if (flags & __PRINTF_FLAG_BIGCHARS)
> + digits = digits_big;
> +
> + *ptr-- = 0; /* Put zero at end of string. */
> +
> + if (num == 0) {
> + *ptr-- = '0';
> + size++;
> + } else {
> + do {
> + *ptr-- = digits[num % base];
> + size++;
> + } while (num /= base);
> + }
> +
> + number_size = size;
> +
> + /*
> + * Collect the sum of all prefixes/signs/... to calculate padding and
> + * leading zeroes.
> + */
> + if (flags & __PRINTF_FLAG_PREFIX) {
> + switch (base) {
> + case 2: /* Binary formating is not standard, but useful. */
> + size += 2;
> + break;
> + case 8:
> + size++;
> + break;
> + case 16:
> + size += 2;
> + break;
> + }
> + }
> +
> + sgn = 0;
> + if (flags & __PRINTF_FLAG_SIGNED) {
> + if (flags & __PRINTF_FLAG_NEGATIVE) {
> + sgn = '-';
> + size++;
> + } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
> + sgn = '+';
> + size++;
> + } else if (flags & __PRINTF_FLAG_SPACESIGN) {
> + sgn = ' ';
> + size++;
> + }
> + }
> +
> + if (flags & __PRINTF_FLAG_LEFTALIGNED)
> + flags &= ~__PRINTF_FLAG_ZEROPADDED;
> +
> + /*
> + * If the number is leftaligned or precision is specified then
> + * zeropadding is ignored.
> + */
> + if (flags & __PRINTF_FLAG_ZEROPADDED) {
> + if ((precision == 0) && (width > size))
> + precision = width - size + number_size;
> + }
> +
> + /* Print leading spaces. */
> + if (number_size > precision) {
> + /* Print the whole number not only a part. */
> + precision = number_size;
> + }
> +
> + width -= precision + size - number_size;
> +
> + if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
> + while (width-- > 0) {
> + if (printf_putchar(' ', ps) == 1)
> + counter++;
> + }
> + }
> +
> + /* Print sign. */
> + if (sgn) {
> + if (printf_putchar(sgn, ps) == 1)
> + counter++;
> + }
> +
> + /* Print prefix. */
> + if (flags & __PRINTF_FLAG_PREFIX) {
> + switch (base) {
> + case 2: /* Binary formating is not standard, but useful. */
> + if (printf_putchar('0', ps) == 1)
> + counter++;
> + if (flags & __PRINTF_FLAG_BIGCHARS) {
> + if (printf_putchar('B', ps) == 1)
> + counter++;
> + } else {
> + if (printf_putchar('b', ps) == 1)
> + counter++;
> + }
> + break;
> + case 8:
> + if (printf_putchar('o', ps) == 1)
> + counter++;
> + break;
> + case 16:
> + if (printf_putchar('0', ps) == 1)
> + counter++;
> + if (flags & __PRINTF_FLAG_BIGCHARS) {
> + if (printf_putchar('X', ps) == 1)
> + counter++;
> + } else {
> + if (printf_putchar('x', ps) == 1)
> + counter++;
> + }
> + break;
> + }
> + }
> +
> + /* Print leading zeroes. */
> + precision -= number_size;
> + while (precision-- > 0) {
> + if (printf_putchar('0', ps) == 1)
> + counter++;
> + }
> +
> + /* Print number itself. */
> + if ((retval = printf_putstr(++ptr, ps)) > 0)
> + counter += retval;
> +
> + /* Print ending spaces. */
> + while (width-- > 0) {
> + if (printf_putchar(' ', ps) == 1)
> + counter++;
> + }
> +
> + return counter;
> +}
> +
> +/** Print formatted string.
> + *
> + * Print string formatted according to the fmt parameter and variadic arguments.
> + * Each formatting directive must have the following form:
> + *
> + * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
> + *
> + * FLAGS:@n
> + * - "#" Force to print prefix.For \%o conversion, the prefix is 0, for
> + * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
> + * prefix is 0b.
> + *
> + * - "-" Align to left.
> + *
> + * - "+" Print positive sign just as negative.
> + *
> + * - " " If the printed number is positive and "+" flag is not set,
> + * print space in place of sign.
> + *
> + * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
> + * sign and the rest of the number. This flag is ignored if "-"
> + * flag is specified.
> + *
> + * WIDTH:@n
> + * - Specify the minimal width of a printed argument. If it is bigger,
> + * width is ignored. If width is specified with a "*" character instead of
> + * number, width is taken from parameter list. And integer parameter is
> + * expected before parameter for processed conversion specification. If
> + * this value is negative its absolute value is taken and the "-" flag is
> + * set.
> + *
> + * PRECISION:@n
> + * - Value precision. For numbers it specifies minimum valid numbers.
> + * Smaller numbers are printed with leading zeroes. Bigger numbers are not
> + * affected. Strings with more than precision characters are cut off. Just
> + * as with width, an "*" can be used used instead of a number. An integer
> + * value is then expected in parameters. When both width and precision are
> + * specified using "*", the first parameter is used for width and the
> + * second one for precision.
> + *
> + * TYPE:@n
> + * - "hh" Signed or unsigned char. at n
> + * - "h" Signed or unsigned short. at n
> + * - "" Signed or unsigned int (default value). at n
> + * - "l" Signed or unsigned long int. at n
> + * - "ll" Signed or unsigned long long int. at n
> + *
> + *
> + * CONVERSION:@n
> + * - % Print percentile character itself.
> + *
> + * - c Print single character.
> + *
> + * - s Print zero terminated string. If a NULL value is passed as
> + * value, "(NULL)" is printed instead.
> + *
> + * - P, p Print value of a pointer. Void * value is expected and it is
> + * printed in hexadecimal notation with prefix (as with \%#X / \%#x
> + * for 32-bit or \%#X / \%#x for 64-bit long pointers).
> + *
> + * - b Print value as unsigned binary number. Prefix is not printed by
> + * default. (Nonstandard extension.)
> + *
> + * - o Print value as unsigned octal number. Prefix is not printed by
> + * default.
> + *
> + * - d, i Print signed decimal number. There is no difference between d
> + * and i conversion.
> + *
> + * - u Print unsigned decimal number.
> + *
> + * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
> + * not printed by default.
> + *
> + * All other characters from fmt except the formatting directives are printed in
> + * verbatim.
> + *
> + * @param fmt Formatting NULL terminated string.
> + * @param ps TODO.
> + * @param ap TODO.
> + * @return Number of characters printed, negative value on failure.
> + */
> +static int printf_core(const char *fmt, struct printf_spec *ps, va_list ap)
> +{
> + int i = 0; /* Index of the currently processed char from fmt */
> + int j = 0; /* Index to the first not printed nonformating character */
> + int end;
> + int counter; /* Counter of printed characters */
> + int retval; /* Used to store return values from called functions */
> + char c;
> + qualifier_t qualifier; /* Type of argument */
> + int base; /* Base in which a numeric parameter will be printed */
> + uint64_t number; /* Argument value */
> + size_t size; /* Byte size of integer parameter */
> + int width, precision;
> + uint64_t flags;
> +
> + counter = 0;
> +
> + while ((c = fmt[i])) {
> + /* Control character. */
> + if (c == '%') {
> + /* Print common characters if any processed. */
> + if (i > j) {
> + if ((retval = printf_putnchars(&fmt[j],
> + (size_t) (i - j), ps)) < 0) {
> + counter = -counter;
> + goto out; /* Error */
> + }
> + counter += retval;
> + }
> +
> + j = i;
> + /* Parse modifiers. */
> + flags = 0;
> + end = 0;
> +
> + do {
> + ++i;
> + switch (c = fmt[i]) {
> + case '#':
> + flags |= __PRINTF_FLAG_PREFIX;
> + break;
> + case '-':
> + flags |= __PRINTF_FLAG_LEFTALIGNED;
> + break;
> + case '+':
> + flags |= __PRINTF_FLAG_SHOWPLUS;
> + break;
> + case ' ':
> + flags |= __PRINTF_FLAG_SPACESIGN;
> + break;
> + case '0':
> + flags |= __PRINTF_FLAG_ZEROPADDED;
> + break;
> + default:
> + end = 1;
> + };
> +
> + } while (end == 0);
> +
> + /* Width & '*' operator. */
> + width = 0;
> + if (isdigit(fmt[i])) {
> + while (isdigit(fmt[i])) {
> + width *= 10;
> + width += fmt[i++] - '0';
> + }
> + } else if (fmt[i] == '*') {
> + /* Get width value from argument list. */
> + i++;
> + width = (int)va_arg(ap, int);
> + if (width < 0) {
> + /* Negative width sets '-' flag. */
> + width *= -1;
> + flags |= __PRINTF_FLAG_LEFTALIGNED;
> + }
> + }
> +
> + /* Precision and '*' operator. */
> + precision = 0;
> + if (fmt[i] == '.') {
> + ++i;
> + if (isdigit(fmt[i])) {
> + while (isdigit(fmt[i])) {
> + precision *= 10;
> + precision += fmt[i++] - '0';
> + }
> + } else if (fmt[i] == '*') {
> + /* Get precision from argument list. */
> + i++;
> + precision = (int)va_arg(ap, int);
> + /* Ignore negative precision. */
> + if (precision < 0)
> + precision = 0;
> + }
> + }
> +
> + switch (fmt[i++]) {
> + /** @todo unimplemented qualifiers:
> + * t ptrdiff_t - ISO C 99
> + */
> + case 'h': /* char or short */
> + qualifier = PrintfQualifierShort;
> + if (fmt[i] == 'h') {
> + i++;
> + qualifier = PrintfQualifierByte;
> + }
> + break;
> + case 'l': /* long or long long */
> + qualifier = PrintfQualifierLong;
> + if (fmt[i] == 'l') {
> + i++;
> + qualifier = PrintfQualifierLongLong;
> + }
> + break;
> + default:
> + /* default type */
> + qualifier = PrintfQualifierInt;
> + --i;
> + }
> +
> + base = 10;
> +
> + switch (c = fmt[i]) {
> + /* String and character conversions */
> + case 's':
> + if ((retval = print_string(va_arg(ap, char *),
> + width, precision, flags, ps)) < 0) {
> + counter = -counter;
> + goto out;
> + };
> + counter += retval;
> + j = i + 1;
> + goto next_char;
> + case 'c':
> + c = va_arg(ap, unsigned int);
> + retval = print_char(c, width, flags, ps);
> + if (retval < 0) {
> + counter = -counter;
> + goto out;
> + };
> + counter += retval;
> + j = i + 1;
> + goto next_char;
> +
> + /* Integer values */
> + case 'P': /* pointer */
> + flags |= __PRINTF_FLAG_BIGCHARS;
> + case 'p':
> + flags |= __PRINTF_FLAG_PREFIX;
> + base = 16;
> + qualifier = PrintfQualifierPointer;
> + break;
> + case 'b':
> + base = 2;
> + break;
> + case 'o':
> + base = 8;
> + break;
> + case 'd':
> + case 'i':
> + flags |= __PRINTF_FLAG_SIGNED;
> + case 'u':
> + break;
> + case 'X':
> + flags |= __PRINTF_FLAG_BIGCHARS;
> + case 'x':
> + base = 16;
> + break;
> + case '%': /* percentile itself */
> + j = i;
> + goto next_char;
> + default: /* Bad formatting */
> + /*
> + * Unknown format. Now, j is the index of '%'
> + * so we will print whole bad format sequence.
> + */
> + goto next_char;
> + }
> +
> + /* Print integers. */
> + /* Print number. */
> + switch (qualifier) {
> + case PrintfQualifierByte:
> + size = sizeof(unsigned char);
> + number = (uint64_t) va_arg(ap, unsigned int);
> + break;
> + case PrintfQualifierShort:
> + size = sizeof(unsigned short);
> + number = (uint64_t) va_arg(ap, unsigned int);
> + break;
> + case PrintfQualifierInt:
> + size = sizeof(unsigned int);
> + number = (uint64_t) va_arg(ap, unsigned int);
> + break;
> + case PrintfQualifierLong:
> + size = sizeof(unsigned long);
> + number = (uint64_t) va_arg(ap, unsigned long);
> + break;
> + case PrintfQualifierLongLong:
> + size = sizeof(unsigned long long);
> + number = (uint64_t) va_arg(ap, unsigned long long);
> + break;
> + case PrintfQualifierPointer:
> + size = sizeof(void *);
> + number = (uint64_t) (unsigned long)va_arg(ap, void *);
> + break;
> + default: /* Unknown qualifier */
> + counter = -counter;
> + goto out;
> + }
> +
> + if (flags & __PRINTF_FLAG_SIGNED) {
> + if (number & (0x1 << (size * 8 - 1))) {
> + flags |= __PRINTF_FLAG_NEGATIVE;
> +
> + if (size == sizeof(uint64_t)) {
> + number = -((int64_t) number);
> + } else {
> + number = ~number;
> + number &= ~(0xFFFFFFFFFFFFFFFFll << (size * 8));
> + number++;
> + }
> + }
> + }
> +
> + if ((retval = print_number(number, width, precision,
> + base, flags, ps)) < 0) {
> + counter = -counter;
> + goto out;
> + }
> +
> + counter += retval;
> + j = i + 1;
> + }
> +next_char:
> + ++i;
> + }
> +
> + if (i > j) {
> + if ((retval = printf_putnchars(&fmt[j],
> + (u64) (i - j), ps)) < 0) {
> + counter = -counter;
> + goto out; /* Error */
> +
> + }
> + counter += retval;
> + }
> +
> +out:
> + return counter;
> +}
> +
> +int sprintf(char *str, const char *fmt, ...)
> +{
> + int ret;
> + va_list args;
> +
> + va_start(args, fmt);
> + ret = vsprintf(str, fmt, args);
> + va_end(args);
> +
> + return ret;
> +}
> +
> +struct vsnprintf_data {
> + size_t size; /* Total space for string */
> + size_t len; /* Count of currently used characters */
> + char *string; /* Destination string */
> +};
> +
> +/**
> + * Write string to given buffer.
> + *
> + * Write at most data->size characters including trailing zero. According to
> + * C99, snprintf() has to return number of characters that would have been
> + * written if enough space had been available. Hence the return value is not
> + * number of really printed characters but size of the input string.
> + * Number of really used characters is stored in data->len.
> + *
> + * @param str Source string to print.
> + * @param count Size of source string.
> + * @param data Structure with destination string, counter of used space
> + * and total string size.
> + * @return Number of characters to print (not characters really printed!).
> + */
> +static int vsnprintf_write(const char *str, size_t count,
> + struct vsnprintf_data *data)
> +{
> + size_t i;
> +
> + i = data->size - data->len;
> + if (i == 0)
> + return count;
> +
> + /* We have only one free byte left in buffer => write trailing zero. */
> + if (i == 1) {
> + data->string[data->size - 1] = 0;
> + data->len = data->size;
> + return count;
> + }
> +
> + /*
> + * We have not enough space for whole string with the trailing
> + * zero => print only a part of string.
> + */
> + if (i <= count) {
> + memcpy((void *)(data->string + data->len), (void *)str, i - 1);
> + data->string[data->size - 1] = 0;
> + data->len = data->size;
> + return count;
> + }
> +
> + /* Buffer is big enough to print whole string. */
> + memcpy((void *)(data->string + data->len), (void *)str, count);
> + data->len += count;
> + /*
> + * Put trailing zero at end, but not count it into data->len so
> + * it could be rewritten next time.
> + */
> + data->string[data->len] = 0;
> +
> + return count;
> +}
> +
> +int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
> +{
> + struct vsnprintf_data data = { size, 0, str };
> + struct printf_spec ps =
> + { (int (*)(void *, size_t, void *))vsnprintf_write, &data };
> +
> + /* Print 0 at end of string - fix case that nothing will be printed. */
> + if (size > 0)
> + str[0] = 0;
> +
> + /* vsnprintf_write() ensures that str will be terminated by zero. */
> + return printf_core(fmt, &ps, ap);
> +}
> +
> +int vsprintf(char *str, const char *fmt, va_list ap)
> +{
> + return vsnprintf(str, (size_t) - 1, fmt, ap);
> +}
> +
> +int printf(const char *fmt, ...)
> +{
> + int ret;
> + va_list args;
> +
> + va_start(args, fmt);
> + ret = vprintf(fmt, args);
> + va_end(args);
> +
> + return ret;
> +}
> +
> +static int vprintf_write(const char *str, size_t count, void *unused)
> +{
> + size_t i;
> +
> + for (i = 0; i < count; i++)
> + putchar(str[i]);
> +
> + return i;
> +}
> +
> +int vprintf(const char *fmt, va_list ap)
> +{
> + struct printf_spec ps =
> + { (int (*)(void *, size_t, void *))vprintf_write, NULL };
> +
> + return printf_core(fmt, &ps, ap);
> +}
> --
> coreboot mailing list
> coreboot at coreboot.org
> http://www.coreboot.org/mailman/listinfo/coreboot
--
Jordan Crouse
Systems Software Development Engineer
Advanced Micro Devices, Inc.
More information about the coreboot
mailing list