2008-05-20 03:53:02 +04:00
/*
2005-04-17 02:20:36 +04:00
Simple utility to make a single - image install kernel with initial ramdisk
for Sparc tftpbooting without need to set up nfs .
Copyright ( C ) 1996 Jakub Jelinek ( jj @ sunsite . mff . cuni . cz )
Pete Zaitcev < zaitcev @ yahoo . com > endian fixes for cross - compiles , 2000.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
2011-01-04 14:39:10 +03:00
2005-04-17 02:20:36 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA . */
2011-01-04 14:39:10 +03:00
# include <dirent.h>
# include <stdlib.h>
2005-04-17 02:20:36 +04:00
# include <string.h>
2011-01-04 14:39:10 +03:00
# include <unistd.h>
2005-04-17 02:20:36 +04:00
# include <ctype.h>
# include <errno.h>
# include <fcntl.h>
2011-01-04 14:39:10 +03:00
# include <stdio.h>
2005-04-17 02:20:36 +04:00
# include <sys/types.h>
# include <sys/stat.h>
/*
* Note : run this on an a . out kernel ( use elftoaout for it ) ,
* as PROM looks for a . out image only .
*/
2011-01-04 14:39:13 +03:00
# define AOUT_TEXT_OFFSET 32
2011-01-04 14:39:10 +03:00
/* read two bytes as big endian */
2009-10-17 01:58:29 +04:00
static unsigned short ld2 ( char * p )
2005-04-17 02:20:36 +04:00
{
return ( p [ 0 ] < < 8 ) | p [ 1 ] ;
}
2011-01-04 14:39:10 +03:00
/* save 4 bytes as big endian */
2009-10-17 01:58:29 +04:00
static void st4 ( char * p , unsigned int x )
2005-04-17 02:20:36 +04:00
{
p [ 0 ] = x > > 24 ;
p [ 1 ] = x > > 16 ;
p [ 2 ] = x > > 8 ;
p [ 3 ] = x ;
}
2011-01-04 14:39:10 +03:00
static void die ( const char * str )
{
perror ( str ) ;
exit ( 1 ) ;
}
2009-10-17 01:58:29 +04:00
static void usage ( void )
2005-04-17 02:20:36 +04:00
{
/* fs_img.gz is an image of initial ramdisk. */
fprintf ( stderr , " Usage: piggyback vmlinux.aout System.map fs_img.gz \n " ) ;
fprintf ( stderr , " \t Kernel image will be modified in place. \n " ) ;
exit ( 1 ) ;
}
2011-01-04 14:39:10 +03:00
static int start_line ( const char * line )
2005-04-17 02:20:36 +04:00
{
2011-01-04 14:39:12 +03:00
if ( strcmp ( line + 8 , " T _start \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
2011-01-04 14:39:12 +03:00
else if ( strcmp ( line + 16 , " T _start \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
return 0 ;
}
static int end_line ( const char * line )
{
if ( strcmp ( line + 8 , " A _end \n " ) = = 0 )
return 1 ;
else if ( strcmp ( line + 16 , " A _end \n " ) = = 0 )
return 1 ;
return 0 ;
}
/*
* Find address for start and end in System . map .
* The file looks like this :
2011-01-04 14:39:12 +03:00
* f0004000 T _start
2011-01-04 14:39:10 +03:00
* f0379f79 A _end
* 1234567890123456
* ^ coloumn 1
* There is support for 64 bit addresses too .
*
* Return 0 if either start or end is not found
*/
static int get_start_end ( const char * filename , unsigned int * start , unsigned int * end )
{
FILE * map ;
char buffer [ 1024 ] ;
* start = 0 ;
* end = 0 ;
map = fopen ( filename , " r " ) ;
if ( ! map )
die ( filename ) ;
while ( fgets ( buffer , 1024 , map ) ) {
if ( start_line ( buffer ) )
* start = strtoul ( buffer , NULL , 16 ) ;
else if ( end_line ( buffer ) )
* end = strtoul ( buffer , NULL , 16 ) ;
}
fclose ( map ) ;
if ( * start = = 0 | | * end = = 0 )
return 0 ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
int main ( int argc , char * * argv )
{
static char aout_magic [ ] = { 0x01 , 0x03 , 0x01 , 0x07 } ;
2009-06-21 20:45:44 +04:00
char buffer [ 1024 ] , * q , * r ;
2011-01-04 14:39:14 +03:00
unsigned int i , start , end , offset ;
2005-04-17 02:20:36 +04:00
struct stat s ;
int image , tail ;
2011-01-04 14:39:10 +03:00
if ( argc ! = 4 )
usage ( ) ;
if ( stat ( argv [ 3 ] , & s ) < 0 )
die ( argv [ 3 ] ) ;
if ( ! get_start_end ( argv [ 2 ] , & start , & end ) ) {
fprintf ( stderr , " Could not determine start and end from %s \n " , argv [ 2 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
2011-01-04 14:39:10 +03:00
if ( ( image = open ( argv [ 1 ] , O_RDWR ) ) < 0 )
die ( argv [ 1 ] ) ;
if ( read ( image , buffer , 512 ) ! = 512 )
die ( argv [ 1 ] ) ;
2011-01-04 14:39:14 +03:00
if ( memcmp ( buffer , aout_magic , 4 ) ! = 0 ) {
fprintf ( stderr , " Not a.out. Don't blame me. \n " ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
2011-01-04 14:39:13 +03:00
/*
* We need to fill in values for sparc_ramdisk_image + sparc_ramdisk_size
* To locate these symbols search for the " HdrS " text which appear
* in the image a little before the gokernel symbol .
* See definition of these in init_32 . S
*/
/* Find the gokernel label */
2011-01-04 14:39:14 +03:00
i = AOUT_TEXT_OFFSET + ( ld2 ( buffer + AOUT_TEXT_OFFSET + 2 ) < < 2 ) - 512 ;
2011-01-04 14:39:10 +03:00
if ( lseek ( image , i , 0 ) < 0 )
die ( " lseek " ) ;
if ( read ( image , buffer , 1024 ) ! = 1024 )
die ( argv [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
for ( q = buffer , r = q + 512 ; q < r ; q + = 4 ) {
if ( * q = = ' H ' & & q [ 1 ] = = ' d ' & & q [ 2 ] = = ' r ' & & q [ 3 ] = = ' S ' )
break ;
}
if ( q = = r ) {
fprintf ( stderr , " Couldn't find headers signature in the kernel. \n " ) ;
exit ( 1 ) ;
}
offset = i + ( q - buffer ) + 10 ;
2011-01-04 14:39:10 +03:00
if ( lseek ( image , offset , 0 ) < 0 )
die ( " lseek " ) ;
2005-04-17 02:20:36 +04:00
2011-01-04 14:39:13 +03:00
/*
* root_flags = 0
* root_dev = 1 ( RAMDISK_MAJOR )
* ram_flags = 0
* sparc_ramdisk_image = " PAGE aligned address after _end " )
* sparc_ramdisk_size = size of image
*/
2005-04-17 02:20:36 +04:00
st4 ( buffer , 0 ) ;
st4 ( buffer + 4 , 0x01000000 ) ;
st4 ( buffer + 8 , ( end + 32 + 4095 ) & ~ 4095 ) ;
st4 ( buffer + 12 , s . st_size ) ;
2011-01-04 14:39:10 +03:00
if ( write ( image , buffer + 2 , 14 ) ! = 14 )
die ( argv [ 1 ] ) ;
2011-01-04 14:39:13 +03:00
/* seek page aligned boundary in the image file and add boot image */
2011-01-04 14:39:14 +03:00
if ( lseek ( image , AOUT_TEXT_OFFSET - start + ( ( end + 32 + 4095 ) & ~ 4095 ) , 0 ) < 0 )
2011-01-04 14:39:10 +03:00
die ( " lseek " ) ;
if ( ( tail = open ( argv [ 3 ] , O_RDONLY ) ) < 0 )
die ( argv [ 3 ] ) ;
2011-01-04 14:39:13 +03:00
while ( ( i = read ( tail , buffer , 1024 ) ) > 0 )
2011-01-04 14:39:10 +03:00
if ( write ( image , buffer , i ) ! = i )
die ( argv [ 1 ] ) ;
if ( close ( image ) < 0 )
die ( " close " ) ;
if ( close ( tail ) < 0 )
die ( " close " ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}