diff options
author | Robin Getz <robin.getz@analog.com> | 2009-07-06 10:53:19 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-09-16 21:31:43 -0400 |
commit | 3f871feaf3390c6d6e578818f867917c2e4738a2 (patch) | |
tree | 3b7ebc72793903361bb4b108bd829b21ede3fc01 /arch/blackfin/kernel/shadow_console.c | |
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>
Diffstat (limited to 'arch/blackfin/kernel/shadow_console.c')
-rw-r--r-- | arch/blackfin/kernel/shadow_console.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/arch/blackfin/kernel/shadow_console.c b/arch/blackfin/kernel/shadow_console.c new file mode 100644 index 000000000000..15819ff10573 --- /dev/null +++ b/arch/blackfin/kernel/shadow_console.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * manage a small early shadow of the log buffer which we can pass between the | ||
3 | * bootloader so early crash messages are communicated properly and easily | ||
4 | * | ||
5 | * Copyright 2009 Analog Devices Inc. | ||
6 | * | ||
7 | * Enter bugs at http://blackfin.uclinux.org/ | ||
8 | * | ||
9 | * Licensed under the GPL-2 or later. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/console.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <asm/blackfin.h> | ||
17 | #include <asm/irq_handler.h> | ||
18 | #include <asm/early_printk.h> | ||
19 | |||
20 | #define SHADOW_CONSOLE_START (0x500) | ||
21 | #define SHADOW_CONSOLE_END (0x1000) | ||
22 | #define SHADOW_CONSOLE_MAGIC_LOC (0x4F0) | ||
23 | #define SHADOW_CONSOLE_MAGIC (0xDEADBEEF) | ||
24 | |||
25 | static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START; | ||
26 | |||
27 | static __init void early_shadow_write(struct console *con, const char *s, | ||
28 | unsigned int n) | ||
29 | { | ||
30 | /* | ||
31 | * save 2 bytes for the double null at the end | ||
32 | * once we fail on a long line, make sure we don't write a short line afterwards | ||
33 | */ | ||
34 | if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) { | ||
35 | memcpy(shadow_console_buffer, s, n); | ||
36 | shadow_console_buffer += n; | ||
37 | shadow_console_buffer[0] = 0; | ||
38 | shadow_console_buffer[1] = 0; | ||
39 | } else | ||
40 | shadow_console_buffer = (char *)SHADOW_CONSOLE_END; | ||
41 | } | ||
42 | |||
43 | static __initdata struct console early_shadow_console = { | ||
44 | .name = "early_shadow", | ||
45 | .write = early_shadow_write, | ||
46 | .flags = CON_BOOT | CON_PRINTBUFFER, | ||
47 | .index = -1, | ||
48 | .device = 0, | ||
49 | }; | ||
50 | |||
51 | __init void enable_shadow_console(void) | ||
52 | { | ||
53 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | ||
54 | |||
55 | if (!(early_shadow_console.flags & CON_ENABLED)) { | ||
56 | register_console(&early_shadow_console); | ||
57 | /* for now, assume things are going to fail */ | ||
58 | *loc = SHADOW_CONSOLE_MAGIC; | ||
59 | loc++; | ||
60 | *loc = SHADOW_CONSOLE_START; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | static __init int disable_shadow_console(void) | ||
65 | { | ||
66 | /* | ||
67 | * by the time pure_initcall runs, the standard console is enabled, | ||
68 | * and the early_console is off, so unset the magic numbers | ||
69 | * unregistering the console is taken care of in common code (See | ||
70 | * ./kernel/printk:disable_boot_consoles() ) | ||
71 | */ | ||
72 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | ||
73 | |||
74 | *loc = 0; | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | pure_initcall(disable_shadow_console); | ||