| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 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 | * | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 7 | * Licensed under the GPL-2 or later. | 
|  | 8 | */ | 
|  | 9 |  | 
|  | 10 | #include <linux/kernel.h> | 
|  | 11 | #include <linux/init.h> | 
|  | 12 | #include <linux/console.h> | 
|  | 13 | #include <linux/string.h> | 
|  | 14 | #include <asm/blackfin.h> | 
|  | 15 | #include <asm/irq_handler.h> | 
|  | 16 | #include <asm/early_printk.h> | 
|  | 17 |  | 
|  | 18 | #define SHADOW_CONSOLE_START		(0x500) | 
|  | 19 | #define SHADOW_CONSOLE_END		(0x1000) | 
|  | 20 | #define SHADOW_CONSOLE_MAGIC_LOC	(0x4F0) | 
|  | 21 | #define SHADOW_CONSOLE_MAGIC		(0xDEADBEEF) | 
|  | 22 |  | 
|  | 23 | static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START; | 
|  | 24 |  | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 25 | __init void early_shadow_write(struct console *con, const char *s, | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 26 | unsigned int n) | 
|  | 27 | { | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 28 | unsigned int i; | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 29 | /* | 
|  | 30 | * save 2 bytes for the double null at the end | 
|  | 31 | * once we fail on a long line, make sure we don't write a short line afterwards | 
|  | 32 | */ | 
|  | 33 | if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) { | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 34 | /* can't use memcpy - it may not be relocated yet */ | 
|  | 35 | for (i = 0; i <= n; i++) | 
|  | 36 | shadow_console_buffer[i] = s[i]; | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 37 | shadow_console_buffer += n; | 
|  | 38 | shadow_console_buffer[0] = 0; | 
|  | 39 | shadow_console_buffer[1] = 0; | 
|  | 40 | } else | 
|  | 41 | shadow_console_buffer = (char *)SHADOW_CONSOLE_END; | 
|  | 42 | } | 
|  | 43 |  | 
|  | 44 | static __initdata struct console early_shadow_console = { | 
|  | 45 | .name = "early_shadow", | 
|  | 46 | .write = early_shadow_write, | 
|  | 47 | .flags = CON_BOOT | CON_PRINTBUFFER, | 
|  | 48 | .index = -1, | 
|  | 49 | .device = 0, | 
|  | 50 | }; | 
|  | 51 |  | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 52 | __init int shadow_console_enabled(void) | 
|  | 53 | { | 
|  | 54 | return early_shadow_console.flags & CON_ENABLED; | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | __init void mark_shadow_error(void) | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 58 | { | 
|  | 59 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 60 | loc[0] = SHADOW_CONSOLE_MAGIC; | 
|  | 61 | loc[1] = SHADOW_CONSOLE_START; | 
|  | 62 | } | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 63 |  | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 64 | __init void enable_shadow_console(void) | 
|  | 65 | { | 
|  | 66 | if (!shadow_console_enabled()) { | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 67 | register_console(&early_shadow_console); | 
|  | 68 | /* for now, assume things are going to fail */ | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 69 | mark_shadow_error(); | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 70 | } | 
|  | 71 | } | 
|  | 72 |  | 
|  | 73 | static __init int disable_shadow_console(void) | 
|  | 74 | { | 
|  | 75 | /* | 
|  | 76 | * by the time pure_initcall runs, the standard console is enabled, | 
|  | 77 | * and the early_console is off, so unset the magic numbers | 
|  | 78 | * unregistering the console is taken care of in common code (See | 
|  | 79 | * ./kernel/printk:disable_boot_consoles() ) | 
|  | 80 | */ | 
|  | 81 | int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | 
|  | 82 |  | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 83 | loc[0] = 0; | 
| Robin Getz | 3f871fe | 2009-07-06 14:53:19 +0000 | [diff] [blame] | 84 |  | 
|  | 85 | return 0; | 
|  | 86 | } | 
|  | 87 | pure_initcall(disable_shadow_console); | 
| Robin Getz | 837ec2d | 2009-07-07 20:17:09 +0000 | [diff] [blame] | 88 |  | 
|  | 89 | /* | 
|  | 90 | * since we can't use printk, dump numbers (as hex), n = # bits | 
|  | 91 | */ | 
|  | 92 | __init void early_shadow_reg(unsigned long reg, unsigned int n) | 
|  | 93 | { | 
|  | 94 | /* | 
|  | 95 | * can't use any "normal" kernel features, since thay | 
|  | 96 | * may not be relocated to their execute address yet | 
|  | 97 | */ | 
|  | 98 | int i; | 
|  | 99 | char ascii[11] = " 0x"; | 
|  | 100 |  | 
|  | 101 | n = n / 4; | 
|  | 102 | reg = reg << ((8 - n) * 4); | 
|  | 103 | n += 3; | 
|  | 104 |  | 
|  | 105 | for (i = 3; i <= n ; i++) { | 
|  | 106 | ascii[i] = hex_asc_lo(reg >> 28); | 
|  | 107 | reg <<= 4; | 
|  | 108 | } | 
|  | 109 | early_shadow_write(NULL, ascii, n); | 
|  | 110 |  | 
|  | 111 | } |