Ron? Marc? Can anyone check this on real hardware? The printk buffer is located in Geode LX memory: - while CAR is enabled: starting at 0x80000 (CONFIG_CARBASE) size 16k (CONFIG_CARSIZE / 2) - after CAR is disabled: starting at 0x90000 size 64k
On 11.02.2008 16:19, Carl-Daniel Hailfinger wrote:
On 11.02.2008 04:19, Peter Stuge wrote:
On Mon, Feb 11, 2008 at 03:01:39AM +0100, Carl-Daniel Hailfinger wrote:
New version, without the recently merged stuff.
If you want to dump the buffer from the Qemu monitor after CAR has been disabled, use this command: memsave 0x90000 65536 memdump.bin
How do we fuse it with the kernel message buffer?
That problem still needs to be solved.
Still to be done, but not really the scope of the patch.
Tested on Qemu, should work on LX. Code needs to get in mergeable shape before commit, but I'd appreciate testers on LX with FS2.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Acked-by: Peter Stuge peter@stuge.se
But please wait for comments from others too. I also have no way of testing this.
You could test on Qemu. I'll write up a really short Howto.
Run qemu with "-monitor stdio", then press "C-a c" on the console and issue this command:
memsave 0x90000 65536 memdump.bin
memdump.bin now contains the printk message buffer (inlcuding header).
Index: LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S
--- LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S (Revision 587) +++ LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S (Arbeitskopie) @@ -361,6 +361,11 @@ movw %ax, %ss
lout:
- /* Store pointer to start of printk buffer, should really use
* PRINTK_BUF_ADDR_CAR instead.
*/
- movl $CONFIG_CARBASE, %eax
So why not do that?
We'd have to import PRINTK_BUF_ADDR_CAR from some header. We need to create such a platform-specific header which exists on all platforms. Maybe cpu.h?
To be solved. Not necessary for merge.
- /* -4-4 because CONFIG_CARBASE + CONFIG_CARSIZE - 4 is initial %esp */
- return (void *)(CONFIG_CARBASE + CONFIG_CARSIZE - 4 - 4);
+}
Is it really bottom of stack and not top? esp decreases, and the pointer is pushed before anything else?
Oh! It could be the bottom of the stack even though it has the highest memory address. That's a bit confusing though.
Yes, I'll add a better comment later.
Still to be done.
Regards, Carl-Daniel
New patch with printk buffer as default-on Kconfig variable. Stack checking removed, can be introduced in a separate patch. Lots of cleanup and correctness fixes. Tested on Qemu, should work on Geode as well.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: LinuxBIOSv3-printkbuffer/include/console.h =================================================================== --- LinuxBIOSv3-printkbuffer/include/console.h (Revision 587) +++ LinuxBIOSv3-printkbuffer/include/console.h (Arbeitskopie) @@ -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); Index: LinuxBIOSv3-printkbuffer/include/arch/x86/cpu.h =================================================================== --- LinuxBIOSv3-printkbuffer/include/arch/x86/cpu.h (Revision 587) +++ LinuxBIOSv3-printkbuffer/include/arch/x86/cpu.h (Arbeitskopie) @@ -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 */ Index: LinuxBIOSv3-printkbuffer/lib/Kconfig =================================================================== --- LinuxBIOSv3-printkbuffer/lib/Kconfig (Revision 587) +++ LinuxBIOSv3-printkbuffer/lib/Kconfig (Arbeitskopie) @@ -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
Index: LinuxBIOSv3-printkbuffer/lib/console.c =================================================================== --- LinuxBIOSv3-printkbuffer/lib/console.c (Revision 587) +++ LinuxBIOSv3-printkbuffer/lib/console.c (Arbeitskopie) @@ -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, ...) Index: LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S =================================================================== --- LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S (Revision 587) +++ LinuxBIOSv3-printkbuffer/arch/x86/geodelx/stage0.S (Arbeitskopie) @@ -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
Index: LinuxBIOSv3-printkbuffer/arch/x86/stage0_i586.S =================================================================== --- LinuxBIOSv3-printkbuffer/arch/x86/stage0_i586.S (Revision 587) +++ LinuxBIOSv3-printkbuffer/arch/x86/stage0_i586.S (Arbeitskopie) @@ -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 */ Index: LinuxBIOSv3-printkbuffer/arch/x86/stage1.c =================================================================== --- LinuxBIOSv3-printkbuffer/arch/x86/stage1.c (Revision 587) +++ LinuxBIOSv3-printkbuffer/arch/x86/stage1.c (Arbeitskopie) @@ -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.");