diff options
author | Robin Getz <robin.getz@analog.com> | 2009-07-06 14:53:19 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-09-16 21:31:43 -0400 |
commit | 3f871feaf3390c6d6e578818f867917c2e4738a2 (patch) | |
tree | 3b7ebc72793903361bb4b108bd829b21ede3fc01 | |
parent | 53e18df745b6f833df07ead62ded09ebae3b0303 (diff) |
Blackfin: add an early shadow console
Add a memory based shadow console to keep a copy of the printk buffer in a
location which can be found externally. This allows bootloaders to locate
and utilize the log buffer in case of silent (early/resume/etc...) crashes.
Signed-off-by: Robin Getz <robin.getz@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r-- | arch/blackfin/include/asm/early_printk.h | 2 | ||||
-rw-r--r-- | arch/blackfin/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/blackfin/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/blackfin/kernel/shadow_console.c | 78 |
4 files changed, 83 insertions, 0 deletions
diff --git a/arch/blackfin/include/asm/early_printk.h b/arch/blackfin/include/asm/early_printk.h index 110f1c1f845..f5b6b7d972e 100644 --- a/arch/blackfin/include/asm/early_printk.h +++ b/arch/blackfin/include/asm/early_printk.h @@ -23,6 +23,8 @@ #ifdef CONFIG_EARLY_PRINTK extern int setup_early_printk(char *); +extern void enable_shadow_console(void); #else #define setup_early_printk(fmt) do { } while (0) +#define enable_shadow_console(fmt) do { } while (0) #endif /* CONFIG_EARLY_PRINTK */ diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 141d9281e4b..a8ddbc8ed5a 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB_TESTS) += kgdb_test.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_EARLY_PRINTK) += shadow_console.o obj-$(CONFIG_STACKTRACE) += stacktrace.o # the kgdb test puts code into L2 and without linker diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 6dbf21930a9..3974764acd2 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -810,6 +810,8 @@ void __init setup_arch(char **cmdline_p) { unsigned long sclk, cclk; + enable_shadow_console(); + /* Check to make sure we are running on the right processor */ if (unlikely(CPUID != bfin_cpuid())) printk(KERN_ERR "ERROR: Not running on ADSP-%s: unknown CPUID 0x%04x Rev 0.%d\n", diff --git a/arch/blackfin/kernel/shadow_console.c b/arch/blackfin/kernel/shadow_console.c new file mode 100644 index 00000000000..15819ff1057 --- /dev/null +++ b/arch/blackfin/kernel/shadow_console.c @@ -0,0 +1,78 @@ +/* + * manage a small early shadow of the log buffer which we can pass between the + * bootloader so early crash messages are communicated properly and easily + * + * Copyright 2009 Analog Devices Inc. + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/string.h> +#include <asm/blackfin.h> +#include <asm/irq_handler.h> +#include <asm/early_printk.h> + +#define SHADOW_CONSOLE_START (0x500) +#define SHADOW_CONSOLE_END (0x1000) +#define SHADOW_CONSOLE_MAGIC_LOC (0x4F0) +#define SHADOW_CONSOLE_MAGIC (0xDEADBEEF) + +static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START; + +static __init void early_shadow_write(struct console *con, const char *s, + unsigned int n) +{ + /* + * save 2 bytes for the double null at the end + * once we fail on a long line, make sure we don't write a short line afterwards + */ + if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) { + memcpy(shadow_console_buffer, s, n); + shadow_console_buffer += n; + shadow_console_buffer[0] = 0; + shadow_console_buffer[1] = 0; + } else + shadow_console_buffer = (char *)SHADOW_CONSOLE_END; +} + +static __initdata struct console early_shadow_console = { + .name = "early_shadow", + .write = early_shadow_write, + .flags = CON_BOOT | CON_PRINTBUFFER, + .index = -1, + .device = 0, +}; + +__init void enable_shadow_console(void) +{ + int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; + + if (!(early_shadow_console.flags & CON_ENABLED)) { + register_console(&early_shadow_console); + /* for now, assume things are going to fail */ + *loc = SHADOW_CONSOLE_MAGIC; + loc++; + *loc = SHADOW_CONSOLE_START; + } +} + +static __init int disable_shadow_console(void) +{ + /* + * by the time pure_initcall runs, the standard console is enabled, + * and the early_console is off, so unset the magic numbers + * unregistering the console is taken care of in common code (See + * ./kernel/printk:disable_boot_consoles() ) + */ + int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; + + *loc = 0; + + return 0; +} +pure_initcall(disable_shadow_console); |