@ -1,4 +1,8 @@
/*
/* Copyright (C) 2011
* Corscience GmbH & Co . KG - Simon Schwarz < schwarz @ corscience . de >
* - Added prep subcommand support
* - Reorganized source - modeled after powerpc version
*
* ( C ) Copyright 2002
* Sysgo Real - Time Solutions , GmbH < www . elinos . com >
* Marius Groeger < mgroeger @ sysgo . de >
@ -29,35 +33,26 @@
# include <fdt.h>
# include <libfdt.h>
# include <fdt_support.h>
# include <asm/bootm.h>
DECLARE_GLOBAL_DATA_PTR ;
# if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
static void setup_start_tag ( bd_t * bd ) ;
# ifdef CONFIG_SETUP_MEMORY_TAGS
static void setup_memory_tags ( bd_t * bd ) ;
# endif
static void setup_commandline_tag ( bd_t * bd , char * commandline ) ;
# ifdef CONFIG_INITRD_TAG
static void setup_initrd_tag ( bd_t * bd , ulong initrd_start ,
ulong initrd_end ) ;
# endif
static void setup_end_tag ( bd_t * bd ) ;
# if defined(CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
static struct tag * params ;
# endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
static ulong get_sp ( void ) ;
# if defined(CONFIG_OF_LIBFDT)
static int bootm_linux_fdt ( int machid , bootm_headers_t * images ) ;
# endif
static ulong get_sp ( void )
{
ulong ret ;
asm ( " mov %0, sp " : " =r " ( ret ) : ) ;
return ret ;
}
void arch_lmb_reserve ( struct lmb * lmb )
{
ulong sp ;
@ -80,89 +75,7 @@ void arch_lmb_reserve(struct lmb *lmb)
gd - > bd - > bi_dram [ 0 ] . start + gd - > bd - > bi_dram [ 0 ] . size - sp ) ;
}
static void announce_and_cleanup ( void )
{
printf ( " \n Starting kernel ... \n \n " ) ;
bootstage_mark_name ( BOOTSTAGE_ID_BOOTM_HANDOFF , " start_kernel " ) ;
# ifdef CONFIG_BOOTSTAGE_REPORT
bootstage_report ( ) ;
# endif
# ifdef CONFIG_USB_DEVICE
{
extern void udc_disconnect ( void ) ;
udc_disconnect ( ) ;
}
# endif
cleanup_before_linux ( ) ;
}
int do_bootm_linux ( int flag , int argc , char * argv [ ] , bootm_headers_t * images )
{
bd_t * bd = gd - > bd ;
char * s ;
int machid = bd - > bi_arch_number ;
void ( * kernel_entry ) ( int zero , int arch , uint params ) ;
# ifdef CONFIG_CMDLINE_TAG
char * commandline = getenv ( " bootargs " ) ;
# endif
if ( ( flag ! = 0 ) & & ( flag ! = BOOTM_STATE_OS_GO ) )
return 1 ;
s = getenv ( " machid " ) ;
if ( s ) {
machid = simple_strtoul ( s , NULL , 16 ) ;
printf ( " Using machid 0x%x from environment \n " , machid ) ;
}
bootstage_mark ( BOOTSTAGE_ID_RUN_OS ) ;
# ifdef CONFIG_OF_LIBFDT
if ( images - > ft_len )
return bootm_linux_fdt ( machid , images ) ;
# endif
kernel_entry = ( void ( * ) ( int , int , uint ) ) images - > ep ;
debug ( " ## Transferring control to Linux (at address %08lx) ... \n " ,
( ulong ) kernel_entry ) ;
# if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
setup_start_tag ( bd ) ;
# ifdef CONFIG_SERIAL_TAG
setup_serial_tag ( & params ) ;
# endif
# ifdef CONFIG_REVISION_TAG
setup_revision_tag ( & params ) ;
# endif
# ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags ( bd ) ;
# endif
# ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag ( bd , commandline ) ;
# endif
# ifdef CONFIG_INITRD_TAG
if ( images - > rd_start & & images - > rd_end )
setup_initrd_tag ( bd , images - > rd_start , images - > rd_end ) ;
# endif
setup_end_tag ( bd ) ;
# endif
announce_and_cleanup ( ) ;
kernel_entry ( 0 , machid , bd - > bi_boot_params ) ;
/* does not return */
return 1 ;
}
# if defined(CONFIG_OF_LIBFDT)
static int fixup_memory_node ( void * blob )
{
bd_t * bd = gd - > bd ;
@ -177,60 +90,30 @@ static int fixup_memory_node(void *blob)
return fdt_fixup_memory_banks ( blob , start , size , CONFIG_NR_DRAM_BANKS ) ;
}
# endif
static int bootm_linux_fdt ( int machid , bootm_headers_t * images )
static void announce_and_cleanup ( void )
{
ulong rd_len ;
void ( * kernel_entry ) ( int zero , int dt_machid , void * dtblob ) ;
ulong of_size = images - > ft_len ;
char * * of_flat_tree = & images - > ft_addr ;
ulong * initrd_start = & images - > initrd_start ;
ulong * initrd_end = & images - > initrd_end ;
struct lmb * lmb = & images - > lmb ;
int ret ;
kernel_entry = ( void ( * ) ( int , int , void * ) ) images - > ep ;
boot_fdt_add_mem_rsv_regions ( lmb , * of_flat_tree ) ;
rd_len = images - > rd_end - images - > rd_start ;
ret = boot_ramdisk_high ( lmb , images - > rd_start , rd_len ,
initrd_start , initrd_end ) ;
if ( ret )
return ret ;
ret = boot_relocate_fdt ( lmb , of_flat_tree , & of_size ) ;
if ( ret )
return ret ;
debug ( " ## Transferring control to Linux (at address %08lx) ... \n " ,
( ulong ) kernel_entry ) ;
fdt_chosen ( * of_flat_tree , 1 ) ;
fixup_memory_node ( * of_flat_tree ) ;
fdt_fixup_ethernet ( * of_flat_tree ) ;
fdt_initrd ( * of_flat_tree , * initrd_start , * initrd_end , 1 ) ;
announce_and_cleanup ( ) ;
kernel_entry ( 0 , machid , * of_flat_tree ) ;
/* does not return */
printf ( " \n Starting kernel ... \n \n " ) ;
bootstage_mark_name ( BOOTSTAGE_ID_BOOTM_HANDOFF , " start_kernel " ) ;
# ifdef CONFIG_BOOTSTAGE_REPORT
bootstage_report ( ) ;
# endif
return 1 ;
}
# ifdef CONFIG_USB_DEVICE
udc_disconnect ( ) ;
# endif
cleanup_before_linux ( ) ;
}
# if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
# if defined(CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
static void setup_start_tag ( bd_t * bd )
{
params = ( struct tag * ) bd - > bi_boot_params ;
params = ( struct tag * ) bd - > bi_boot_params ;
params - > hdr . tag = ATAG_CORE ;
params - > hdr . size = tag_size ( tag_core ) ;
@ -241,10 +124,10 @@ static void setup_start_tag (bd_t *bd)
params = tag_next ( params ) ;
}
# endif
# ifdef CONFIG_SETUP_MEMORY_TAGS
static void setup_memory_tags ( bd_t * bd )
static void setup_memory_tags ( bd_t * bd )
{
int i ;
@ -258,10 +141,10 @@ static void setup_memory_tags (bd_t *bd)
params = tag_next ( params ) ;
}
}
# endif /* CONFIG_SETUP_MEMORY_TAGS */
# endif
static void setup_commandline_tag ( bd_t * bd , char * commandline )
# ifdef CONFIG_CMDLINE_TAG
static void setup_commandline_tag ( bd_t * bd , char * commandline )
{
char * p ;
@ -285,10 +168,10 @@ static void setup_commandline_tag (bd_t *bd, char *commandline)
params = tag_next ( params ) ;
}
# endif
# ifdef CONFIG_INITRD_TAG
static void setup_initrd_tag ( bd_t * bd , ulong initrd_start , ulong initrd_end )
static void setup_initrd_tag ( bd_t * bd , ulong initrd_start , ulong initrd_end )
{
/* an ATAG_INITRD node tells the kernel where the compressed
* ramdisk can be found . ATAG_RDIMG is a better name , actually .
@ -301,10 +184,10 @@ static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
params = tag_next ( params ) ;
}
# endif /* CONFIG_INITRD_TAG */
# endif
# ifdef CONFIG_SERIAL_TAG
void setup_serial_tag ( struct tag * * tmp )
void setup_serial_tag ( struct tag * * tmp )
{
struct tag * params = * tmp ;
struct tag_serialnr serialnr ;
@ -332,19 +215,147 @@ void setup_revision_tag(struct tag **in_params)
params - > u . revision . rev = rev ;
params = tag_next ( params ) ;
}
# endif /* CONFIG_REVISION_TAG */
# endif
static void setup_end_tag ( bd_t * bd )
# if defined(CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
static void setup_end_tag ( bd_t * bd )
{
params - > hdr . tag = ATAG_NONE ;
params - > hdr . size = 0 ;
}
# endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
# endif
static ulong get_sp ( void )
# ifdef CONFIG_OF_LIBFDT
static int create_fdt ( bootm_headers_t * images )
{
ulong ret ;
ulong of_size = images - > ft_len ;
char * * of_flat_tree = & images - > ft_addr ;
ulong * initrd_start = & images - > initrd_start ;
ulong * initrd_end = & images - > initrd_end ;
struct lmb * lmb = & images - > lmb ;
ulong rd_len ;
int ret ;
asm ( " mov %0, sp " : " =r " ( ret ) : ) ;
return ret ;
debug ( " using: FDT \n " ) ;
boot_fdt_add_mem_rsv_regions ( lmb , * of_flat_tree ) ;
rd_len = images - > rd_end - images - > rd_start ;
ret = boot_ramdisk_high ( lmb , images - > rd_start , rd_len ,
initrd_start , initrd_end ) ;
if ( ret )
return ret ;
ret = boot_relocate_fdt ( lmb , of_flat_tree , & of_size ) ;
if ( ret )
return ret ;
fdt_chosen ( * of_flat_tree , 1 ) ;
fixup_memory_node ( * of_flat_tree ) ;
fdt_initrd ( * of_flat_tree , * initrd_start , * initrd_end , 1 ) ;
return 0 ;
}
# endif
/* Subcommand: PREP */
static void boot_prep_linux ( bootm_headers_t * images )
{
# ifdef CONFIG_CMDLINE_TAG
char * commandline = getenv ( " bootargs " ) ;
# endif
# ifdef CONFIG_OF_LIBFDT
if ( images - > ft_len ) {
debug ( " using: FDT \n " ) ;
if ( create_fdt ( images ) ) {
printf ( " FDT creation failed! hanging... " ) ;
hang ( ) ;
}
} else
# endif
{
# if defined(CONFIG_SETUP_MEMORY_TAGS) || \
defined ( CONFIG_CMDLINE_TAG ) | | \
defined ( CONFIG_INITRD_TAG ) | | \
defined ( CONFIG_SERIAL_TAG ) | | \
defined ( CONFIG_REVISION_TAG )
debug ( " using: ATAGS \n " ) ;
setup_start_tag ( gd - > bd ) ;
# ifdef CONFIG_SERIAL_TAG
setup_serial_tag ( & params ) ;
# endif
# ifdef CONFIG_CMDLINE_TAG
setup_commandline_tag ( gd - > bd , commandline ) ;
# endif
# ifdef CONFIG_REVISION_TAG
setup_revision_tag ( & params ) ;
# endif
# ifdef CONFIG_SETUP_MEMORY_TAGS
setup_memory_tags ( gd - > bd ) ;
# endif
# ifdef CONFIG_INITRD_TAG
if ( images - > rd_start & & images - > rd_end )
setup_initrd_tag ( gd - > bd , images - > rd_start ,
images - > rd_end ) ;
# endif
setup_end_tag ( gd - > bd ) ;
# else /* all tags */
printf ( " FDT and ATAGS support not compiled in - hanging \n " ) ;
hang ( ) ;
# endif /* all tags */
}
}
/* Subcommand: GO */
static void boot_jump_linux ( bootm_headers_t * images )
{
unsigned long machid = gd - > bd - > bi_arch_number ;
char * s ;
void ( * kernel_entry ) ( int zero , int arch , uint params ) ;
kernel_entry = ( void ( * ) ( int , int , uint ) ) images - > ep ;
s = getenv ( " machid " ) ;
if ( s ) {
strict_strtoul ( s , 16 , & machid ) ;
printf ( " Using machid 0x%lx from environment \n " , machid ) ;
}
debug ( " ## Transferring control to Linux (at address %08lx) " \
" ... \n " , ( ulong ) kernel_entry ) ;
bootstage_mark ( BOOTSTAGE_ID_RUN_OS ) ;
announce_and_cleanup ( ) ;
kernel_entry ( 0 , machid , gd - > bd - > bi_boot_params ) ;
}
/* Main Entry point for arm bootm implementation
*
* Modeled after the powerpc implementation
* DIFFERENCE : Instead of calling prep and go at the end
* they are called if subcommand is equal 0.
*/
int do_bootm_linux ( int flag , int argc , char * argv [ ] , bootm_headers_t * images )
{
/* No need for those on ARM */
if ( flag & BOOTM_STATE_OS_BD_T | | flag & BOOTM_STATE_OS_CMDLINE )
return - 1 ;
if ( flag & BOOTM_STATE_OS_PREP ) {
boot_prep_linux ( images ) ;
return 0 ;
}
if ( flag & BOOTM_STATE_OS_GO ) {
boot_jump_linux ( images ) ;
return 0 ;
}
boot_prep_linux ( images ) ;
boot_jump_linux ( images ) ;
return 0 ;
}