mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
(1)we now compile in all printks, which is good: we can print any message provided we can change the console log level at any time. (2) The console log level is compiled in and unchangeable, which is bad, as it defeats the purpose of (1). Add a BIOS_ALWAYS log level. Make console log level a variable. Make functions that set it and get it visible everywhere. Always print out the version message; this is really *not* noise! PCI: Simplify pci functions so that they can be used in stage1 or anywhere for that matter. Add a find function which is needed for many stage1 functions. Note that we copy but also clean up the libpayload stuff just a bit. Get rid of config space type 2. If there was ever a platform that used it, I don't know what it was, and the presence is a needless distraction. tested and working on DBE62 (which means the console and the pci functions work :-). There is a remaining problem with dumplxmsrs which nobody understands. It prints out garbage if we use the %s for the msr names. Formatting is an issue; if somebody wants to fix formatting they can assume I will ack it. Sorry, my emacs has gone just nuts. Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Acked-by: Peter Stuge <peter@stuge.se> git-svn-id: svn://coreboot.org/repository/coreboot-v3@729 f3766cd6-281f-0410-b1cd-43a5c92072e9
213 lines
5.2 KiB
C
213 lines
5.2 KiB
C
#include <types.h>
|
|
#include <cpu.h>
|
|
#include <console.h>
|
|
#include <uart8250.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
int vtxprintf(void (*)(unsigned char, void *arg),
|
|
void *arg, const char *, va_list);
|
|
|
|
static unsigned int loglevel = CONFIG_DEFAULT_CONSOLE_LOGLEVEL;
|
|
|
|
/**
|
|
* set the console log level
|
|
* There are no invalid settings, although there are ones that
|
|
* do not make much sense.
|
|
*
|
|
* @param level The new level
|
|
*/
|
|
void set_loglevel(unsigned int level) {
|
|
if (level > BIOS_SPEW)
|
|
printk(BIOS_ALWAYS, "Warning: ridiculous log level setting: %d (max %d)\n",
|
|
level, BIOS_SPEW);
|
|
loglevel = level;
|
|
}
|
|
|
|
/**
|
|
* get the console log level
|
|
*
|
|
* @return The level
|
|
*/
|
|
static unsigned int console_loglevel(void)
|
|
{
|
|
return loglevel;
|
|
}
|
|
|
|
#ifdef CONFIG_CONSOLE_BUFFER
|
|
void printk_buffer_move(void *newaddr, int newsize)
|
|
{
|
|
struct printk_buffer **p;
|
|
struct printk_buffer *oldbuf, *newbuf;
|
|
int copylen;
|
|
p = bottom_of_stack();
|
|
oldbuf = *p;
|
|
newbuf = newaddr;
|
|
newbuf->len = newsize;
|
|
newbuf->readoffset = 0;
|
|
/* Check for wraparound */
|
|
if (oldbuf->writeoffset < oldbuf->readoffset) {
|
|
/* Copy from readoffset to end of buffer. */
|
|
copylen = oldbuf->len - oldbuf->readoffset;
|
|
} else {
|
|
/* Copy from readoffset to writeoffset (exclusive).*/
|
|
copylen = oldbuf->writeoffset - oldbuf->readoffset;
|
|
}
|
|
if (copylen > newsize)
|
|
copylen = newsize;
|
|
/* If memcpy() ever uses printk we will see pretty explosions. */
|
|
memcpy(&newbuf->buffer[0], &oldbuf->buffer[oldbuf->readoffset],
|
|
copylen);
|
|
newbuf->writeoffset = copylen;
|
|
/* Check for wraparound */
|
|
if (oldbuf->writeoffset < oldbuf->readoffset) {
|
|
/* Copy from start of buffer to writeoffset (exclusive). */
|
|
copylen = (copylen + oldbuf->writeoffset > newsize)
|
|
? newsize - copylen : oldbuf->writeoffset;
|
|
memcpy(&newbuf->buffer[newbuf->writeoffset],
|
|
&oldbuf->buffer[0], copylen);
|
|
newbuf->writeoffset += copylen;
|
|
}
|
|
*p = newbuf;
|
|
return;
|
|
}
|
|
|
|
struct printk_buffer *printk_buffer_addr(void)
|
|
{
|
|
struct printk_buffer **p;
|
|
p = bottom_of_stack();
|
|
return *p;
|
|
}
|
|
|
|
void printk_buffer_init(void)
|
|
{
|
|
struct printk_buffer *buf = printk_buffer_addr();
|
|
buf->len = PRINTK_BUF_SIZE_CAR - sizeof(struct printk_buffer);
|
|
buf->readoffset = 0;
|
|
buf->writeoffset = 0;
|
|
return;
|
|
}
|
|
|
|
void buffer_tx_byte(unsigned char byte, void *arg)
|
|
{
|
|
struct printk_buffer *buf = printk_buffer_addr();
|
|
buf->buffer[buf->writeoffset++] = byte;
|
|
buf->writeoffset %= buf->len;
|
|
/* Make sure writeoffset is always ahead of readoffset here. */
|
|
if (buf->writeoffset == buf->readoffset) {
|
|
buf->readoffset++;
|
|
buf->readoffset %= buf->len;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
void console_tx_byte(unsigned char byte, void *arg)
|
|
{
|
|
#ifdef CONFIG_CONSOLE_BUFFER
|
|
buffer_tx_byte(byte, arg);
|
|
#endif
|
|
#ifdef CONFIG_CONSOLE_SERIAL
|
|
if (byte == '\n') {
|
|
uart8250_tx_byte(TTYSx_BASE, '\r');
|
|
#ifdef CONFIG_CONSOLE_PREFIX
|
|
uart8250_tx_byte(TTYSx_BASE, '\n');
|
|
uart8250_tx_byte(TTYSx_BASE, '(');
|
|
uart8250_tx_byte(TTYSx_BASE, 'L');
|
|
uart8250_tx_byte(TTYSx_BASE, 'B');
|
|
uart8250_tx_byte(TTYSx_BASE, ')');
|
|
uart8250_tx_byte(TTYSx_BASE, ' ');
|
|
return;
|
|
#endif
|
|
}
|
|
uart8250_tx_byte(TTYSx_BASE, byte);
|
|
#endif
|
|
}
|
|
|
|
int printk(int msg_level, const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int i;
|
|
|
|
if (msg_level > console_loglevel()) {
|
|
return 0;
|
|
}
|
|
|
|
va_start(args, fmt);
|
|
i = vtxprintf(console_tx_byte, (void *)0, fmt, args);
|
|
va_end(args);
|
|
|
|
return i;
|
|
}
|
|
|
|
/**
|
|
* Print a nice banner so we know what step we died on.
|
|
*
|
|
* @param level The printk level (e.g. BIOS_EMERG)
|
|
* @param s String to put in the middle of the banner
|
|
*/
|
|
|
|
void banner(int level, const char *s)
|
|
{
|
|
int i;
|
|
/* 10 = signs and a space. */
|
|
printk(level, "========== ");
|
|
for(i = 11; *s; i++, s++)
|
|
printk(level, "%c", *s);
|
|
/* trailing space */
|
|
printk(level, " ");
|
|
i++;
|
|
/* fill it up to 80 columns */
|
|
for(; i < 80; i++)
|
|
printk(level, "=");
|
|
printk(level, "\n");
|
|
}
|
|
|
|
void console_init(void)
|
|
{
|
|
static const char console_test[] =
|
|
"\n\ncoreboot-"
|
|
COREBOOT_VERSION
|
|
COREBOOT_EXTRA_VERSION
|
|
" "
|
|
COREBOOT_BUILD
|
|
" starting... (console_loglevel=%d)\n";
|
|
|
|
printk(BIOS_ALWAYS, console_test, console_loglevel());
|
|
}
|
|
|
|
/**
|
|
* Halt and loop due to a fatal error.
|
|
* There have been several iterations of this function.
|
|
* The first simply did a hlt(). Doing a hlt() can make jtag debugging
|
|
* very difficult as one can not break into a hlt instruction on some CPUs.
|
|
* Second was to do a console_tx_byte of a NULL character.
|
|
* A number of concerns were raised about doing this idea.
|
|
* Third idea was to do an inb from port 0x80, the POST port. That design
|
|
* makes us very CPU-specific.
|
|
* The fourth idea was just POSTING the same
|
|
* code over and over. That would erase the most recent POST code,
|
|
* hindering diagnosis.
|
|
*
|
|
* For now, for lack of a better alternative,
|
|
* we will call console_tx_byte ten times and then halt.
|
|
* Some CPU JTAG debbuggers might have problems but it is the right thing
|
|
* to do. We call with a NULL since it will clear any FIFOs in the path and
|
|
* won't clutter up the output, since NULL doesn't print a visible character
|
|
* on most terminal emulators.
|
|
*
|
|
* @param str A string to print for the error
|
|
*
|
|
*/
|
|
void die(const char *str)
|
|
{
|
|
int i;
|
|
|
|
printk(BIOS_EMERG, str);
|
|
|
|
while (1) {
|
|
for (i = 0; i < 10; i++)
|
|
console_tx_byte(0, (void *)0);
|
|
hlt();
|
|
}
|
|
}
|