2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
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 .
2011-01-04 14:39:19 +03:00
Copyright ( C ) 1996 , 1997 Jakub Jelinek ( jj @ sunsite . mff . cuni . cz )
2005-04-17 02:20:36 +04:00
Pete Zaitcev < zaitcev @ yahoo . com > endian fixes for cross - compiles , 2000.
2011-01-04 14:39:19 +03:00
Copyright ( C ) 2011 Sam Ravnborg < sam @ ravnborg . org >
2005-04-17 02:20:36 +04:00
2019-05-20 10:19:02 +03:00
*/
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:15 +03:00
static int is64bit = 0 ;
/* align to power-of-two size */
static int align ( int n )
{
if ( is64bit )
return ( n + 0x1fff ) & ~ 0x1fff ;
else
return ( n + 0xfff ) & ~ 0xfff ;
}
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. */
2011-01-04 14:39:15 +03:00
fprintf ( stderr , " Usage: piggyback bits vmlinux.aout System.map fs_img.gz \n " ) ;
2005-04-17 02:20:36 +04:00
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
{
2012-12-03 23:24:25 +04:00
if ( strcmp ( line + 10 , " _start \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
2012-12-03 23:24:25 +04:00
else if ( strcmp ( line + 18 , " _start \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
return 0 ;
}
static int end_line ( const char * line )
{
2012-12-03 23:24:25 +04:00
if ( strcmp ( line + 10 , " _end \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
2012-12-03 23:24:25 +04:00
else if ( strcmp ( line + 18 , " _end \n " ) = = 0 )
2011-01-04 14:39:10 +03:00
return 1 ;
return 0 ;
}
/*
* Find address for start and end in System . map .
* The file looks like this :
2012-12-03 23:24:25 +04:00
* f0004000 . . . _start
* f0379f79 . . . _end
2011-01-04 14:39:10 +03:00
* 1234567890123456
* ^ coloumn 1
* There is support for 64 bit addresses too .
*
* Return 0 if either start or end is not found
*/
2011-01-04 14:39:16 +03:00
static int get_start_end ( const char * filename , unsigned int * start ,
unsigned int * end )
2011-01-04 14:39:10 +03:00
{
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
}
2011-01-04 14:39:16 +03:00
# define LOOKBACK (128 * 4)
# define BUFSIZE 1024
/*
* Find the HdrS entry from head_32 / head_64 .
* We check if it is at the beginning of the file ( sparc64 case )
* and if not we search for it .
* When we search do so in steps of 4 as HdrS is on a 4 - byte aligned
* address ( it is on same alignment as sparc instructions )
* Return the offset to the HdrS entry ( as off_t )
*/
static off_t get_hdrs_offset ( int kernelfd , const char * filename )
{
char buffer [ BUFSIZE ] ;
off_t offset ;
int i ;
if ( lseek ( kernelfd , 0 , SEEK_SET ) < 0 )
die ( " lseek " ) ;
if ( read ( kernelfd , buffer , BUFSIZE ) ! = BUFSIZE )
die ( filename ) ;
if ( buffer [ 40 ] = = ' H ' & & buffer [ 41 ] = = ' d ' & &
buffer [ 42 ] = = ' r ' & & buffer [ 43 ] = = ' S ' ) {
return 40 ;
} else {
/* Find the gokernel label */
/* Decode offset from branch instruction */
offset = ld2 ( buffer + AOUT_TEXT_OFFSET + 2 ) < < 2 ;
/* Go back 512 bytes so we do not miss HdrS */
offset - = LOOKBACK ;
/* skip a.out header */
offset + = AOUT_TEXT_OFFSET ;
if ( lseek ( kernelfd , offset , SEEK_SET ) < 0 )
die ( " lseek " ) ;
if ( read ( kernelfd , buffer , BUFSIZE ) ! = BUFSIZE )
die ( filename ) ;
for ( i = 0 ; i < LOOKBACK ; i + = 4 ) {
if ( buffer [ i + 0 ] = = ' H ' & & buffer [ i + 1 ] = = ' d ' & &
buffer [ i + 2 ] = = ' r ' & & buffer [ i + 3 ] = = ' S ' ) {
return offset + i ;
}
}
}
fprintf ( stderr , " Couldn't find headers signature in %s \n " , filename ) ;
exit ( 1 ) ;
}
2005-04-17 02:20:36 +04:00
int main ( int argc , char * * argv )
{
static char aout_magic [ ] = { 0x01 , 0x03 , 0x01 , 0x07 } ;
2011-01-04 14:39:16 +03:00
char buffer [ 1024 ] ;
unsigned int i , start , end ;
off_t offset ;
2005-04-17 02:20:36 +04:00
struct stat s ;
int image , tail ;
2011-01-04 14:39:15 +03:00
if ( argc ! = 5 )
2011-01-04 14:39:10 +03:00
usage ( ) ;
2011-01-04 14:39:15 +03:00
if ( strcmp ( argv [ 1 ] , " 64 " ) = = 0 )
is64bit = 1 ;
if ( stat ( argv [ 4 ] , & s ) < 0 )
die ( argv [ 4 ] ) ;
2011-01-04 14:39:10 +03:00
2011-01-04 14:39:15 +03:00
if ( ! get_start_end ( argv [ 3 ] , & start , & end ) ) {
2011-01-04 14:39:16 +03:00
fprintf ( stderr , " Could not determine start and end from %s \n " ,
argv [ 3 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
2011-01-04 14:39:15 +03:00
if ( ( image = open ( argv [ 2 ] , O_RDWR ) ) < 0 )
die ( argv [ 2 ] ) ;
2011-01-04 14:39:10 +03:00
if ( read ( image , buffer , 512 ) ! = 512 )
2011-01-04 14:39:15 +03:00
die ( argv [ 2 ] ) ;
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
/*
2011-01-04 14:39:16 +03:00
* We need to fill in values for
* sparc_ramdisk_image + sparc_ramdisk_size
2011-01-04 14:39:13 +03:00
* 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
*/
2011-01-04 14:39:16 +03:00
offset = get_hdrs_offset ( image , argv [ 2 ] ) ;
/* skip HdrS + LINUX_VERSION_CODE + HdrS version */
offset + = 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 ) ;
2011-01-04 14:39:15 +03:00
st4 ( buffer + 8 , align ( end + 32 ) ) ;
2005-04-17 02:20:36 +04:00
st4 ( buffer + 12 , s . st_size ) ;
2011-01-04 14:39:10 +03:00
if ( write ( image , buffer + 2 , 14 ) ! = 14 )
2011-01-04 14:39:15 +03:00
die ( argv [ 2 ] ) ;
2011-01-04 14:39:13 +03:00
2011-01-04 14:39:16 +03:00
/* For sparc64 update a_text and clear a_data + a_bss */
if ( is64bit )
{
if ( lseek ( image , 4 , 0 ) < 0 )
die ( " lseek " ) ;
/* a_text */
st4 ( buffer , align ( end + 32 + 8191 ) - ( start & ~ 0x3fffffUL ) +
s . st_size ) ;
/* a_data */
st4 ( buffer + 4 , 0 ) ;
/* a_bss */
st4 ( buffer + 8 , 0 ) ;
if ( write ( image , buffer , 12 ) ! = 12 )
die ( argv [ 2 ] ) ;
}
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:15 +03:00
if ( lseek ( image , AOUT_TEXT_OFFSET - start + align ( end + 32 ) , 0 ) < 0 )
2011-01-04 14:39:10 +03:00
die ( " lseek " ) ;
2011-01-04 14:39:15 +03:00
if ( ( tail = open ( argv [ 4 ] , O_RDONLY ) ) < 0 )
die ( argv [ 4 ] ) ;
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 )
2011-01-04 14:39:15 +03:00
die ( argv [ 2 ] ) ;
2011-01-04 14:39:10 +03:00
if ( close ( image ) < 0 )
die ( " close " ) ;
if ( close ( tail ) < 0 )
die ( " close " ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}