2009-07-06 14:53:19 +00:00
/*
* 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>
2012-05-16 17:37:24 +08:00
# 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)
2009-07-06 14:53:19 +00:00
# define SHADOW_CONSOLE_MAGIC (0xDEADBEEF)
static __initdata char * shadow_console_buffer = ( char * ) SHADOW_CONSOLE_START ;
2009-07-07 20:17:09 +00:00
__init void early_shadow_write ( struct console * con , const char * s ,
2009-07-06 14:53:19 +00:00
unsigned int n )
{
2009-07-07 20:17:09 +00:00
unsigned int i ;
2009-07-06 14:53:19 +00:00
/*
* 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 ) ) {
2009-07-07 20:17:09 +00:00
/* can't use memcpy - it may not be relocated yet */
for ( i = 0 ; i < = n ; i + + )
shadow_console_buffer [ i ] = s [ i ] ;
2009-07-06 14:53:19 +00:00
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 ,
} ;
2009-07-07 20:17:09 +00:00
__init int shadow_console_enabled ( void )
{
return early_shadow_console . flags & CON_ENABLED ;
}
__init void mark_shadow_error ( void )
2009-07-06 14:53:19 +00:00
{
int * loc = ( int * ) SHADOW_CONSOLE_MAGIC_LOC ;
2009-07-07 20:17:09 +00:00
loc [ 0 ] = SHADOW_CONSOLE_MAGIC ;
loc [ 1 ] = SHADOW_CONSOLE_START ;
}
2009-07-06 14:53:19 +00:00
2009-07-07 20:17:09 +00:00
__init void enable_shadow_console ( void )
{
if ( ! shadow_console_enabled ( ) ) {
2009-07-06 14:53:19 +00:00
register_console ( & early_shadow_console ) ;
/* for now, assume things are going to fail */
2009-07-07 20:17:09 +00:00
mark_shadow_error ( ) ;
2009-07-06 14:53:19 +00:00
}
}
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 ;
2009-07-07 20:17:09 +00:00
loc [ 0 ] = 0 ;
2009-07-06 14:53:19 +00:00
return 0 ;
}
pure_initcall ( disable_shadow_console ) ;
2009-07-07 20:17:09 +00:00
/*
* 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 ) ;
}