Make printk() log to a buffer.

Tested on Qemu and Geode LX.
Benefits of this patch:
- printk() now works directly after printk_buffer_init(), even before
the serial port is set up.
- If all you want is a log, you don't have to bother with serial output.
- A payload can read and analyze the log.
- You can build on this and buffer log until serial is available, then
flush the messages buffered so far.

The printk buffer is configurable with a default-on Kconfig variable.

If you want to dump the buffer from the Qemu monitor after CAR has been
disabled, use this command:
memsave 0x90000 65536 memdump.bin

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Acked-by: Peter Stuge <peter@stuge.se>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Marc Jones <marc.jones@amd.com>


git-svn-id: svn://coreboot.org/repository/coreboot-v3@590 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
Carl-Daniel Hailfinger 2008-02-13 15:48:37 +00:00
parent fd7c529003
commit 5d11489d74
7 changed files with 135 additions and 3 deletions

View file

@ -361,6 +361,13 @@ DCacheSetupGood:
movw %ax, %ss
lout:
#ifdef CONFIG_CONSOLE_BUFFER
/* Store pointer to start of printk buffer, should really use
* PRINTK_BUF_ADDR_CAR instead.
*/
movl $CONFIG_CARBASE, %eax
pushl %eax /* printk buffer */
#endif
/* Restore the BIST result. */
movl %ebp, %eax

View file

@ -433,7 +433,13 @@ clear_fixed_var_mtrr_out:
movw %ax, %ss
lout:
#ifdef CONFIG_CONSOLE_BUFFER
/* Store pointer to start of printk buffer, should really use
* PRINTK_BUF_ADDR_CAR instead.
*/
movl $CONFIG_CARBASE, %eax
pushl %eax /* printk buffer */
#endif
/* Restore the BIST result */
movl %ebp, %eax
/* We need to set ebp ? No need */

View file

@ -26,6 +26,7 @@
#include <tables.h>
#include <lib.h>
#include <mc146818rtc.h>
#include <cpu.h>
/* ah, well, what a mess! This is a hard code. FIX ME but how?
* By getting rid of ELF ...
@ -67,6 +68,12 @@ void init_archive(struct mem_file *archive)
}
void *bottom_of_stack(void)
{
/* -4-4 because CONFIG_CARBASE + CONFIG_CARSIZE - 4 is initial %esp */
return (void *)(CONFIG_CARBASE + CONFIG_CARSIZE - 4 - 4);
}
void dump_mem_range(int msg_level, unsigned char *buf, int size)
{
int i;
@ -129,6 +136,11 @@ void __attribute__((stdcall)) stage1_main(u32 bist)
// We have cache as ram running and can start executing code in C.
#ifdef CONFIG_CONSOLE_BUFFER
/* Initialize the printk buffer. */
printk_buffer_init();
#endif
hardware_stage1();
//
@ -173,10 +185,14 @@ void __attribute__((stdcall)) stage1_main(u32 bist)
printk(BIOS_DEBUG, "Done RAM init code\n");
/* Turn off Cache-As-Ram */
disable_car();
#ifdef CONFIG_CONSOLE_BUFFER
/* Move the printk buffer to PRINTK_BUF_ADDR_RAM */
printk_buffer_move((void *)PRINTK_BUF_ADDR_RAM, PRINTK_BUF_SIZE_RAM);
#endif
entry = load_file_segments(&archive, "normal/stage2");
if (entry == (void *)-1)
die("FATAL: Failed loading stage2.");

View file

@ -24,6 +24,7 @@
#include <types.h>
#include <device/device.h>
#include <shared.h>
#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
@ -196,4 +197,13 @@ static inline __attribute__((always_inline)) void hlt(void)
__asm__ __volatile__("hlt" : : : "memory");
}
SHARED(bottom_of_stack, void *, void);
#ifdef CONFIG_CONSOLE_BUFFER
#define PRINTK_BUF_SIZE_CAR (CONFIG_CARSIZE / 2)
#define PRINTK_BUF_ADDR_CAR CONFIG_CARBASE
#define PRINTK_BUF_SIZE_RAM 65536
#define PRINTK_BUF_ADDR_RAM 0x90000
#endif
#endif /* ARCH_X86_CPU_H */

View file

@ -37,6 +37,10 @@ void console_tx_flush(void);
unsigned char console_rx_byte(void);
int console_tst_byte(void);
void die(const char *msg);
#ifdef CONFIG_CONSOLE_BUFFER
void printk_buffer_init(void);
void printk_buffer_move(void *newaddr, int newsize);
#endif
struct console_driver {
void (*init)(void);
@ -46,6 +50,15 @@ struct console_driver {
int (*tst_byte)(void);
};
#ifdef CONFIG_CONSOLE_BUFFER
struct printk_buffer {
int len;
int readoffset;
int writeoffset;
char buffer[];
};
#endif
SHARED_WITH_ATTRIBUTES(printk, int, __attribute__((format (printf, 2, 3))),
int msg_level, const char *fmt, ...);
SHARED(banner, void, int msg_level, const char *msg);

View file

@ -223,5 +223,12 @@ config CONSOLE_PREFIX
When you enable this option, coreboot will prefix each line of
console output with '(LB)'.
config CONSOLE_BUFFER
boolean "Console memory buffer support"
default y
depends CONSOLE
help
Save coreboot output in a memory buffer.
endmenu

View file

@ -3,6 +3,7 @@
#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);
@ -12,8 +13,80 @@ static int console_loglevel(void)
return CONFIG_DEFAULT_CONSOLE_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');
#if defined(CONFIG_CONSOLE_PREFIX) && (CONFIG_CONSOLE_PREFIX == 1)
@ -26,8 +99,8 @@ void console_tx_byte(unsigned char byte, void *arg)
return;
#endif
}
uart8250_tx_byte(TTYSx_BASE, byte);
#endif
}
int printk(int msg_level, const char *fmt, ...)