Author: hailfinger Date: 2008-02-13 16:48:37 +0100 (Wed, 13 Feb 2008) New Revision: 590
Modified: coreboot-v3/arch/x86/geodelx/stage0.S coreboot-v3/arch/x86/stage0_i586.S coreboot-v3/arch/x86/stage1.c coreboot-v3/include/arch/x86/cpu.h coreboot-v3/include/console.h coreboot-v3/lib/Kconfig coreboot-v3/lib/console.c Log: 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
Modified: coreboot-v3/arch/x86/geodelx/stage0.S =================================================================== --- coreboot-v3/arch/x86/geodelx/stage0.S 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/arch/x86/geodelx/stage0.S 2008-02-13 15:48:37 UTC (rev 590) @@ -361,6 +361,13 @@ 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
Modified: coreboot-v3/arch/x86/stage0_i586.S =================================================================== --- coreboot-v3/arch/x86/stage0_i586.S 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/arch/x86/stage0_i586.S 2008-02-13 15:48:37 UTC (rev 590) @@ -433,7 +433,13 @@ 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 */
Modified: coreboot-v3/arch/x86/stage1.c =================================================================== --- coreboot-v3/arch/x86/stage1.c 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/arch/x86/stage1.c 2008-02-13 15:48:37 UTC (rev 590) @@ -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 *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 @@
// 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 @@
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.");
Modified: coreboot-v3/include/arch/x86/cpu.h =================================================================== --- coreboot-v3/include/arch/x86/cpu.h 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/include/arch/x86/cpu.h 2008-02-13 15:48:37 UTC (rev 590) @@ -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 @@ __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 */
Modified: coreboot-v3/include/console.h =================================================================== --- coreboot-v3/include/console.h 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/include/console.h 2008-02-13 15:48:37 UTC (rev 590) @@ -37,6 +37,10 @@ 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 @@ 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);
Modified: coreboot-v3/lib/Kconfig =================================================================== --- coreboot-v3/lib/Kconfig 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/lib/Kconfig 2008-02-13 15:48:37 UTC (rev 590) @@ -223,5 +223,12 @@ 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
Modified: coreboot-v3/lib/console.c =================================================================== --- coreboot-v3/lib/console.c 2008-02-13 15:35:30 UTC (rev 589) +++ coreboot-v3/lib/console.c 2008-02-13 15:48:37 UTC (rev 590) @@ -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 @@ 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 @@ return; #endif } - uart8250_tx_byte(TTYSx_BASE, byte); +#endif }
int printk(int msg_level, const char *fmt, ...)