mirror of
https://github.com/drasko/codezero.git
synced 2026-01-11 18:33:16 +01:00
Mutex system call fixed for multiple contenders Userspace irq support extended to keyboard/mouse. Scheduler modified for real-time irq tasks
455 lines
10 KiB
C
455 lines
10 KiB
C
/*********************************************************************
|
|
*
|
|
* Copyright (C) 2002-2004 Karlsruhe University
|
|
*
|
|
* File path: generic/printk.cc
|
|
* Description: Implementation of printf
|
|
*
|
|
* 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 <stdarg.h> /* for va_list, ... comes with gcc */
|
|
#include <l4/lib/printk.h>
|
|
#include <l4/lib/mutex.h>
|
|
|
|
/* FIXME: LICENSE LICENCE */
|
|
typedef unsigned int word_t;
|
|
|
|
extern void putc(const char c);
|
|
extern int print_tid (word_t val, word_t width, word_t precision, int adjleft);
|
|
|
|
|
|
/* convert nibble to lowercase hex char */
|
|
#define hexchars(x) (((x) < 10) ? ('0' + (x)) : ('a' + ((x) - 10)))
|
|
|
|
/**
|
|
* Print hexadecimal value
|
|
*
|
|
* @param val value to print
|
|
* @param width width in caracters
|
|
* @param precision minimum number of digits to apprear
|
|
* @param adjleft left adjust the value
|
|
* @param nullpad pad with leading zeros (when right padding)
|
|
*
|
|
* Prints a hexadecimal value with leading zeroes of given width
|
|
* using putc(), or if adjleft argument is given, print
|
|
* hexadecimal value with space padding to the right.
|
|
*
|
|
* @returns the number of charaters printed (should be same as width).
|
|
*/
|
|
int print_hex64(u64 val, int width, int precision, int adjleft, int nullpad)
|
|
{
|
|
int i, n = 0;
|
|
int nwidth = 0;
|
|
u32 high, low;
|
|
|
|
high = val >> 32;
|
|
low = (u32)val;
|
|
|
|
// Find width of hexnumber
|
|
if (high) {
|
|
while ((high >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
|
|
nwidth++;
|
|
nwidth += 32;
|
|
} else {
|
|
while ((low >> (4 * nwidth)) && ((unsigned) nwidth < 2 * sizeof (u32)))
|
|
nwidth++;
|
|
}
|
|
|
|
if (nwidth == 0)
|
|
nwidth = 1;
|
|
|
|
// May need to increase number of printed digits
|
|
if (precision > nwidth)
|
|
nwidth = precision;
|
|
|
|
// May need to increase number of printed characters
|
|
if (width == 0 && width < nwidth)
|
|
width = nwidth;
|
|
|
|
// Print number with padding
|
|
if (high)
|
|
{
|
|
if (!adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (nullpad ? '0' : ' ');
|
|
for (i = 4 * (nwidth - 33); i >= 0; i -= 4, n++)
|
|
putc (hexchars ((high >> i) & 0xF));
|
|
if (adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (' ');
|
|
width -= 32;
|
|
nwidth -= 32;
|
|
nullpad = 1;
|
|
}
|
|
if (! adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (nullpad ? '0' : ' ');
|
|
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
|
putc (hexchars ((low >> i) & 0xF));
|
|
if (adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (' ');
|
|
|
|
return n;
|
|
}
|
|
|
|
int print_hex_3arg(const word_t val, int width, int precision)
|
|
{
|
|
long i, n = 0;
|
|
long nwidth = 0;
|
|
int adjleft = 0;
|
|
int nullpad = 0;
|
|
|
|
// Find width of hexnumber
|
|
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
|
|
nwidth++;
|
|
|
|
if (nwidth == 0)
|
|
nwidth = 1;
|
|
|
|
// May need to increase number of printed digits
|
|
if (precision > nwidth)
|
|
nwidth = precision;
|
|
|
|
// May need to increase number of printed characters
|
|
if (width == 0 && width < nwidth)
|
|
width = nwidth;
|
|
|
|
// Print number with padding
|
|
if (! adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (nullpad ? '0' : ' ');
|
|
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
|
putc (hexchars ((val >> i) & 0xF));
|
|
if (adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (' ');
|
|
|
|
return n;
|
|
}
|
|
|
|
int print_hex_5arg(const word_t val, int width,
|
|
int precision, int adjleft, int nullpad)
|
|
{
|
|
long i, n = 0;
|
|
long nwidth = 0;
|
|
|
|
// Find width of hexnumber
|
|
while ((val >> (4 * nwidth)) && (word_t) nwidth < 2 * sizeof (word_t))
|
|
nwidth++;
|
|
|
|
if (nwidth == 0)
|
|
nwidth = 1;
|
|
|
|
// May need to increase number of printed digits
|
|
if (precision > nwidth)
|
|
nwidth = precision;
|
|
|
|
// May need to increase number of printed characters
|
|
if (width == 0 && width < nwidth)
|
|
width = nwidth;
|
|
|
|
// Print number with padding
|
|
if (! adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (nullpad ? '0' : ' ');
|
|
for (i = 4 * (nwidth - 1); i >= 0; i -= 4, n++)
|
|
putc (hexchars ((val >> i) & 0xF));
|
|
if (adjleft)
|
|
for (i = width - nwidth; i > 0; i--, n++)
|
|
putc (' ');
|
|
|
|
return n;
|
|
}
|
|
/**
|
|
* Print a string
|
|
*
|
|
* @param s zero-terminated string to print
|
|
* @param width minimum width of printed string
|
|
*
|
|
* Prints the zero-terminated string using putc(). The printed
|
|
* string will be right padded with space to so that it will be
|
|
* at least WIDTH characters wide.
|
|
*
|
|
* @returns the number of charaters printed.
|
|
*/
|
|
int print_string_3arg(const char * s, const int width, const int precision)
|
|
{
|
|
int n = 0;
|
|
|
|
for (;;)
|
|
{
|
|
if (*s == 0)
|
|
break;
|
|
|
|
putc(*s++);
|
|
n++;
|
|
if (precision && n >= precision)
|
|
break;
|
|
}
|
|
|
|
while (n < width) { putc(' '); n++; }
|
|
|
|
return n;
|
|
}
|
|
|
|
int print_string_1arg(const char * s)
|
|
{
|
|
int n = 0;
|
|
int width = 0;
|
|
int precision = 0;
|
|
|
|
for (;;) {
|
|
if (*s == 0)
|
|
break;
|
|
|
|
putc(*s++);
|
|
n++;
|
|
if (precision && n >= precision)
|
|
break;
|
|
}
|
|
|
|
while (n < width) {
|
|
putc(' ');
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
/**
|
|
* Print hexadecimal value with a separator
|
|
*
|
|
* @param val value to print
|
|
* @param bits number of lower-most bits before which to
|
|
* place the separator
|
|
* @param sep the separator to print
|
|
*
|
|
* @returns the number of charaters printed.
|
|
*/
|
|
int print_hex_sep(const word_t val, const int bits, const char *sep)
|
|
{
|
|
int n = 0;
|
|
|
|
n = print_hex_3arg(val >> bits, 0, 0);
|
|
n += print_string_1arg(sep);
|
|
n += print_hex_3arg(val & ((1 << bits) - 1), 0, 0);
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
/**
|
|
* Print decimal value
|
|
*
|
|
* @param val value to print
|
|
* @param width width of field
|
|
* @param pad character used for padding value up to width
|
|
*
|
|
* Prints a value as a decimal in the given WIDTH with leading
|
|
* whitespaces.
|
|
*
|
|
* @returns the number of characters printed (may be more than WIDTH)
|
|
*/
|
|
int print_dec(const word_t val, int width)
|
|
{
|
|
word_t divisor;
|
|
int digits;
|
|
/* estimate number of spaces and digits */
|
|
for (divisor = 1, digits = 1; val/divisor >= 10; divisor *= 10, digits++);
|
|
|
|
/* print spaces */
|
|
for ( ; digits < width; digits++ )
|
|
putc(' ');
|
|
|
|
/* print digits */
|
|
do {
|
|
putc(((val/divisor) % 10) + '0');
|
|
} while (divisor /= 10);
|
|
|
|
/* report number of digits printed */
|
|
return digits;
|
|
}
|
|
|
|
/**
|
|
* Does the real printk work
|
|
*
|
|
* @param format_p pointer to format string
|
|
* @param args list of arguments, variable length
|
|
*
|
|
* Prints the given arguments as specified by the format string.
|
|
* Implements a subset of the well-known printf plus some L4-specifics.
|
|
*
|
|
* @returns the number of characters printed
|
|
*/
|
|
int do_printk(char* format_p, va_list args)
|
|
{
|
|
const char* format = format_p;
|
|
int n = 0;
|
|
int i = 0;
|
|
int width = 8;
|
|
int precision = 0;
|
|
int adjleft = 0, nullpad = 0;
|
|
|
|
#define arg(x) va_arg(args, x)
|
|
|
|
/* sanity check */
|
|
if (format == '\0')
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
while (*format)
|
|
{
|
|
switch (*(format))
|
|
{
|
|
case '%':
|
|
width = precision = 0;
|
|
adjleft = nullpad = 0;
|
|
reentry:
|
|
switch (*(++format))
|
|
{
|
|
/* modifiers */
|
|
case '.':
|
|
for (format++; *format >= '0' && *format <= '9'; format++)
|
|
precision = precision * 10 + (*format) - '0';
|
|
if (*format == 'w')
|
|
{
|
|
// Set precision to printsize of a hex word
|
|
precision = sizeof (word_t) * 2;
|
|
format++;
|
|
}
|
|
format--;
|
|
goto reentry;
|
|
case '0':
|
|
nullpad = (width == 0);
|
|
case '1'...'9':
|
|
width = width*10 + (*format)-'0';
|
|
goto reentry;
|
|
case 'w':
|
|
// Set width to printsize of a hex word
|
|
width = sizeof (word_t) * 2;
|
|
goto reentry;
|
|
case '-':
|
|
adjleft = 0;
|
|
goto reentry;
|
|
case 'l':
|
|
goto reentry;
|
|
break;
|
|
case 'c':
|
|
putc(arg(int));
|
|
n++;
|
|
break;
|
|
case 'm': /* microseconds */
|
|
{
|
|
n += print_hex64(arg(u64), width, precision,
|
|
adjleft, nullpad);
|
|
break;
|
|
}
|
|
case 'd':
|
|
{
|
|
long val = arg(long);
|
|
if (val < 0)
|
|
{
|
|
putc('-');
|
|
val = -val;
|
|
}
|
|
n += print_dec(val, width);
|
|
break;
|
|
}
|
|
case 'u':
|
|
n += print_dec(arg(long), width);
|
|
break;
|
|
case 'p':
|
|
precision = sizeof (word_t) * 2;
|
|
case 'x':
|
|
n += print_hex_5arg(arg(long), width, precision, adjleft, nullpad);
|
|
break;
|
|
case 's':
|
|
{
|
|
char* s = arg(char*);
|
|
if (s)
|
|
n += print_string_3arg(s, width, precision);
|
|
else
|
|
n += print_string_3arg("(null)", width, precision);
|
|
}
|
|
break;
|
|
|
|
case 't':
|
|
case 'T':
|
|
// Do nothing for now.
|
|
//n += print_tid (arg (word_t), width, precision, adjleft);
|
|
break;
|
|
|
|
case '%':
|
|
putc('%');
|
|
n++;
|
|
format++;
|
|
continue;
|
|
default:
|
|
n += print_string_1arg("?");
|
|
break;
|
|
};
|
|
i++;
|
|
break;
|
|
default:
|
|
putc(*format);
|
|
n++;
|
|
break;
|
|
}
|
|
format++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
DECLARE_SPINLOCK(printk_lock);
|
|
|
|
/**
|
|
* Flexible print function
|
|
*
|
|
* @param format string containing formatting and parameter type
|
|
* information
|
|
* @param ... variable list of parameters
|
|
*
|
|
* @returns the number of characters printed
|
|
*/
|
|
int printk(char *format, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
unsigned long irqstate;
|
|
|
|
va_start(args, format);
|
|
|
|
spin_lock_irq(&printk_lock, &irqstate);
|
|
i = do_printk(format, args);
|
|
spin_unlock_irq(&printk_lock, irqstate);
|
|
|
|
va_end(args);
|
|
return i;
|
|
}
|
|
|
|
|