diff options
Diffstat (limited to 'arch/blackfin/kernel/shadow_console.c')
-rw-r--r-- | arch/blackfin/kernel/shadow_console.c | 113 |
1 files changed, 113 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..8b8c7107a162 --- /dev/null +++ b/arch/blackfin/kernel/shadow_console.c | |||
@@ -0,0 +1,113 @@ | |||
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 | __init void early_shadow_write(struct console *con, const char *s, | ||
28 | unsigned int n) | ||
29 | { | ||
30 | unsigned int i; | ||
31 | /* | ||
32 | * save 2 bytes for the double null at the end | ||
33 | * once we fail on a long line, make sure we don't write a short line afterwards | ||
34 | */ | ||
35 | if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) { | ||
36 | /* can't use memcpy - it may not be relocated yet */ | ||
37 | for (i = 0; i <= n; i++) | ||
38 | shadow_console_buffer[i] = s[i]; | ||
39 | shadow_console_buffer += n; | ||
40 | shadow_console_buffer[0] = 0; | ||
41 | shadow_console_buffer[1] = 0; | ||
42 | } else | ||
43 | shadow_console_buffer = (char *)SHADOW_CONSOLE_END; | ||
44 | } | ||
45 | |||
46 | static __initdata struct console early_shadow_console = { | ||
47 | .name = "early_shadow", | ||
48 | .write = early_shadow_write, | ||
49 | .flags = CON_BOOT | CON_PRINTBUFFER, | ||
50 | .index = -1, | ||
51 | .device = 0, | ||
52 | }; | ||
53 | |||
54 | __init int shadow_console_enabled(void) | ||
55 | { | ||
56 | return early_shadow_console.flags & CON_ENABLED; | ||
57 | } | ||
58 | |||
59 | __init void mark_shadow_error(void) | ||
60 | { | ||
61 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | ||
62 | loc[0] = SHADOW_CONSOLE_MAGIC; | ||
63 | loc[1] = SHADOW_CONSOLE_START; | ||
64 | } | ||
65 | |||
66 | __init void enable_shadow_console(void) | ||
67 | { | ||
68 | if (!shadow_console_enabled()) { | ||
69 | register_console(&early_shadow_console); | ||
70 | /* for now, assume things are going to fail */ | ||
71 | mark_shadow_error(); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static __init int disable_shadow_console(void) | ||
76 | { | ||
77 | /* | ||
78 | * by the time pure_initcall runs, the standard console is enabled, | ||
79 | * and the early_console is off, so unset the magic numbers | ||
80 | * unregistering the console is taken care of in common code (See | ||
81 | * ./kernel/printk:disable_boot_consoles() ) | ||
82 | */ | ||
83 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | ||
84 | |||
85 | loc[0] = 0; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | pure_initcall(disable_shadow_console); | ||
90 | |||
91 | /* | ||
92 | * since we can't use printk, dump numbers (as hex), n = # bits | ||
93 | */ | ||
94 | __init void early_shadow_reg(unsigned long reg, unsigned int n) | ||
95 | { | ||
96 | /* | ||
97 | * can't use any "normal" kernel features, since thay | ||
98 | * may not be relocated to their execute address yet | ||
99 | */ | ||
100 | int i; | ||
101 | char ascii[11] = " 0x"; | ||
102 | |||
103 | n = n / 4; | ||
104 | reg = reg << ((8 - n) * 4); | ||
105 | n += 3; | ||
106 | |||
107 | for (i = 3; i <= n ; i++) { | ||
108 | ascii[i] = hex_asc_lo(reg >> 28); | ||
109 | reg <<= 4; | ||
110 | } | ||
111 | early_shadow_write(NULL, ascii, n); | ||
112 | |||
113 | } | ||