| /* | |
| * 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. | |
| * | |
| * 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 (CONFIG_PHY_RAM_BASE_ADDRESS + 0x500) | |
| #define SHADOW_CONSOLE_END (CONFIG_PHY_RAM_BASE_ADDRESS + 0x1000) | |
| #define SHADOW_CONSOLE_MAGIC_LOC (CONFIG_PHY_RAM_BASE_ADDRESS + 0x4F0) | |
| #define SHADOW_CONSOLE_MAGIC (0xDEADBEEF) | |
| static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START; | |
| __init void early_shadow_write(struct console *con, const char *s, | |
| unsigned int n) | |
| { | |
| unsigned int i; | |
| /* | |
| * 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)) { | |
| /* can't use memcpy - it may not be relocated yet */ | |
| for (i = 0; i <= n; i++) | |
| shadow_console_buffer[i] = s[i]; | |
| 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 int shadow_console_enabled(void) | |
| { | |
| return early_shadow_console.flags & CON_ENABLED; | |
| } | |
| __init void mark_shadow_error(void) | |
| { | |
| int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC; | |
| loc[0] = SHADOW_CONSOLE_MAGIC; | |
| loc[1] = SHADOW_CONSOLE_START; | |
| } | |
| __init void enable_shadow_console(void) | |
| { | |
| if (!shadow_console_enabled()) { | |
| register_console(&early_shadow_console); | |
| /* for now, assume things are going to fail */ | |
| mark_shadow_error(); | |
| } | |
| } | |
| 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] = 0; | |
| return 0; | |
| } | |
| pure_initcall(disable_shadow_console); | |
| /* | |
| * since we can't use printk, dump numbers (as hex), n = # bits | |
| */ | |
| __init void early_shadow_reg(unsigned long reg, unsigned int n) | |
| { | |
| /* | |
| * can't use any "normal" kernel features, since thay | |
| * may not be relocated to their execute address yet | |
| */ | |
| int i; | |
| char ascii[11] = " 0x"; | |
| n = n / 4; | |
| reg = reg << ((8 - n) * 4); | |
| n += 3; | |
| for (i = 3; i <= n ; i++) { | |
| ascii[i] = hex_asc_lo(reg >> 28); | |
| reg <<= 4; | |
| } | |
| early_shadow_write(NULL, ascii, n); | |
| } |