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 movw %ax, %ss
lout: 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. */ /* Restore the BIST result. */
movl %ebp, %eax movl %ebp, %eax

View file

@ -433,7 +433,13 @@ clear_fixed_var_mtrr_out:
movw %ax, %ss movw %ax, %ss
lout: 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 */ /* Restore the BIST result */
movl %ebp, %eax movl %ebp, %eax
/* We need to set ebp ? No need */ /* We need to set ebp ? No need */

View file

@ -26,6 +26,7 @@
#include <tables.h> #include <tables.h>
#include <lib.h> #include <lib.h>
#include <mc146818rtc.h> #include <mc146818rtc.h>
#include <cpu.h>
/* ah, well, what a mess! This is a hard code. FIX ME but how? /* ah, well, what a mess! This is a hard code. FIX ME but how?
* By getting rid of ELF ... * 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) void dump_mem_range(int msg_level, unsigned char *buf, int size)
{ {
int i; 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. // 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(); hardware_stage1();
// //
@ -173,10 +185,14 @@ void __attribute__((stdcall)) stage1_main(u32 bist)
printk(BIOS_DEBUG, "Done RAM init code\n"); printk(BIOS_DEBUG, "Done RAM init code\n");
/* Turn off Cache-As-Ram */ /* Turn off Cache-As-Ram */
disable_car(); 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"); entry = load_file_segments(&archive, "normal/stage2");
if (entry == (void *)-1) if (entry == (void *)-1)
die("FATAL: Failed loading stage2."); die("FATAL: Failed loading stage2.");

View file

@ -24,6 +24,7 @@
#include <types.h> #include <types.h>
#include <device/device.h> #include <device/device.h>
#include <shared.h>
#define X86_VENDOR_INTEL 0 #define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1 #define X86_VENDOR_CYRIX 1
@ -196,4 +197,13 @@ static inline __attribute__((always_inline)) void hlt(void)
__asm__ __volatile__("hlt" : : : "memory"); __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 */ #endif /* ARCH_X86_CPU_H */

View file

@ -37,6 +37,10 @@ void console_tx_flush(void);
unsigned char console_rx_byte(void); unsigned char console_rx_byte(void);
int console_tst_byte(void); int console_tst_byte(void);
void die(const char *msg); 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 { struct console_driver {
void (*init)(void); void (*init)(void);
@ -46,6 +50,15 @@ struct console_driver {
int (*tst_byte)(void); 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))), SHARED_WITH_ATTRIBUTES(printk, int, __attribute__((format (printf, 2, 3))),
int msg_level, const char *fmt, ...); int msg_level, const char *fmt, ...);
SHARED(banner, void, int msg_level, const char *msg); 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 When you enable this option, coreboot will prefix each line of
console output with '(LB)'. 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 endmenu

View file

@ -3,6 +3,7 @@
#include <console.h> #include <console.h>
#include <uart8250.h> #include <uart8250.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
int vtxprintf(void (*)(unsigned char, void *arg), int vtxprintf(void (*)(unsigned char, void *arg),
void *arg, const char *, va_list); void *arg, const char *, va_list);
@ -12,8 +13,80 @@ static int console_loglevel(void)
return CONFIG_DEFAULT_CONSOLE_LOGLEVEL; 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) 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') { if (byte == '\n') {
uart8250_tx_byte(TTYSx_BASE, '\r'); uart8250_tx_byte(TTYSx_BASE, '\r');
#if defined(CONFIG_CONSOLE_PREFIX) && (CONFIG_CONSOLE_PREFIX == 1) #if defined(CONFIG_CONSOLE_PREFIX) && (CONFIG_CONSOLE_PREFIX == 1)
@ -26,8 +99,8 @@ void console_tx_byte(unsigned char byte, void *arg)
return; return;
#endif #endif
} }
uart8250_tx_byte(TTYSx_BASE, byte); uart8250_tx_byte(TTYSx_BASE, byte);
#endif
} }
int printk(int msg_level, const char *fmt, ...) int printk(int msg_level, const char *fmt, ...)