mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
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:
parent
fd7c529003
commit
5d11489d74
7 changed files with 135 additions and 3 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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, ...)
|
||||||
|
|
Loading…
Add table
Reference in a new issue