|  | /* | 
|  | * 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); | 
|  |  | 
|  | } |