2005-04-17 02:20:36 +04:00
/*
* Program to hack in a PT_NOTE program header entry in an ELF file .
* This is needed for OF on RS / 6000 s to load an image correctly .
* Note that OF needs a program header entry for the note , not an
* ELF section .
*
* Copyright 2000 Paul Mackerras .
*
2014-04-24 11:23:34 +04:00
* Adapted for 64 bit little endian images by Andrew Tauferner .
*
2005-04-17 02:20:36 +04:00
* 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 .
*
2008-10-31 14:27:17 +03:00
* Usage : addnote zImage
2005-04-17 02:20:36 +04:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
2005-05-01 19:58:45 +04:00
/* CHRP note section */
2010-09-13 13:47:40 +04:00
static const char arch [ ] = " PowerPC " ;
2005-04-17 02:20:36 +04:00
# define N_DESCR 6
unsigned int descr [ N_DESCR ] = {
0xffffffff , /* real-mode = true */
2008-06-24 08:20:29 +04:00
0x02000000 , /* real-base, i.e. where we expect OF to be */
2005-04-17 02:20:36 +04:00
0xffffffff , /* real-size */
0xffffffff , /* virt-base */
0xffffffff , /* virt-size */
0x4000 , /* load-base */
} ;
2005-05-01 19:58:45 +04:00
/* RPA note section */
2010-09-13 13:47:40 +04:00
static const char rpaname [ ] = " IBM,RPA-Client-Config " ;
2005-05-01 19:58:45 +04:00
/*
* Note : setting ignore_my_client_config * should * mean that OF ignores
* all the other fields , but there is a firmware bug which means that
* it looks at the splpar field at least . So these values need to be
* reasonable .
*/
# define N_RPA_DESCR 8
unsigned int rpanote [ N_RPA_DESCR ] = {
2008-10-31 14:27:17 +03:00
0 , /* lparaffinity */
64 , /* min_rmo_size */
2005-05-01 19:58:45 +04:00
0 , /* min_rmo_percent */
2008-10-31 14:27:17 +03:00
40 , /* max_pft_size */
2005-05-01 19:58:45 +04:00
1 , /* splpar */
- 1 , /* min_load */
2008-10-31 14:27:17 +03:00
0 , /* new_mem_def */
1 , /* ignore_my_client_config */
2005-05-01 19:58:45 +04:00
} ;
# define ROUNDUP(len) (((len) + 3) & ~3)
2014-04-24 11:23:34 +04:00
unsigned char buf [ 1024 ] ;
# define ELFDATA2LSB 1
# define ELFDATA2MSB 2
static int e_data = ELFDATA2MSB ;
# define ELFCLASS32 1
# define ELFCLASS64 2
static int e_class = ELFCLASS32 ;
2005-04-17 02:20:36 +04:00
2008-10-31 14:27:17 +03:00
# define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
2014-04-24 11:23:34 +04:00
# define GET_32BE(off) ((GET_16BE(off) << 16U) + GET_16BE((off)+2U))
# define GET_64BE(off) ((((unsigned long long)GET_32BE(off)) << 32ULL) + \
( ( unsigned long long ) GET_32BE ( ( off ) + 4ULL ) ) )
# define PUT_16BE(off, v)(buf[off] = ((v) >> 8) & 0xff, \
buf [ ( off ) + 1 ] = ( v ) & 0xff )
# define PUT_32BE(off, v)(PUT_16BE((off), (v) >> 16L), PUT_16BE((off) + 2, (v)))
# define PUT_64BE(off, v)((PUT_32BE((off), (v) >> 32L), \
PUT_32BE ( ( off ) + 4 , ( v ) ) ) )
# define GET_16LE(off) ((buf[off]) + (buf[(off)+1] << 8))
# define GET_32LE(off) (GET_16LE(off) + (GET_16LE((off)+2U) << 16U))
# define GET_64LE(off) ((unsigned long long)GET_32LE(off) + \
( ( ( unsigned long long ) GET_32LE ( ( off ) + 4ULL ) ) < < 32ULL ) )
# define PUT_16LE(off, v) (buf[off] = (v) & 0xff, \
buf [ ( off ) + 1 ] = ( ( v ) > > 8 ) & 0xff )
# define PUT_32LE(off, v) (PUT_16LE((off), (v)), PUT_16LE((off) + 2, (v) >> 16L))
# define PUT_64LE(off, v) (PUT_32LE((off), (v)), PUT_32LE((off) + 4, (v) >> 32L))
# define GET_16(off) (e_data == ELFDATA2MSB ? GET_16BE(off) : GET_16LE(off))
# define GET_32(off) (e_data == ELFDATA2MSB ? GET_32BE(off) : GET_32LE(off))
# define GET_64(off) (e_data == ELFDATA2MSB ? GET_64BE(off) : GET_64LE(off))
# define PUT_16(off, v) (e_data == ELFDATA2MSB ? PUT_16BE(off, v) : \
PUT_16LE ( off , v ) )
# define PUT_32(off, v) (e_data == ELFDATA2MSB ? PUT_32BE(off, v) : \
PUT_32LE ( off , v ) )
# define PUT_64(off, v) (e_data == ELFDATA2MSB ? PUT_64BE(off, v) : \
PUT_64LE ( off , v ) )
2005-04-17 02:20:36 +04:00
/* Structure of an ELF file */
# define E_IDENT 0 /* ELF header */
2014-04-24 11:23:34 +04:00
# define E_PHOFF (e_class == ELFCLASS32 ? 28 : 32)
# define E_PHENTSIZE (e_class == ELFCLASS32 ? 42 : 54)
# define E_PHNUM (e_class == ELFCLASS32 ? 44 : 56)
# define E_HSIZE (e_class == ELFCLASS32 ? 52 : 64)
2005-04-17 02:20:36 +04:00
# define EI_MAGIC 0 /* offsets in E_IDENT area */
# define EI_CLASS 4
# define EI_DATA 5
# define PH_TYPE 0 /* ELF program header */
2014-04-24 11:23:34 +04:00
# define PH_OFFSET (e_class == ELFCLASS32 ? 4 : 8)
# define PH_FILESZ (e_class == ELFCLASS32 ? 16 : 32)
# define PH_HSIZE (e_class == ELFCLASS32 ? 32 : 56)
2005-04-17 02:20:36 +04:00
# define PT_NOTE 4 /* Program header type = note */
unsigned char elf_magic [ 4 ] = { 0x7f , ' E ' , ' L ' , ' F ' } ;
int
main ( int ac , char * * av )
{
2008-10-31 14:27:17 +03:00
int fd , n , i ;
2014-04-24 11:23:34 +04:00
unsigned long ph , ps , np ;
long nnote , nnote2 , ns ;
2008-10-31 14:27:17 +03:00
if ( ac ! = 2 ) {
fprintf ( stderr , " Usage: %s elf-file \n " , av [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
2008-10-31 14:27:17 +03:00
fd = open ( av [ 1 ] , O_RDWR ) ;
2005-04-17 02:20:36 +04:00
if ( fd < 0 ) {
2008-10-31 14:27:17 +03:00
perror ( av [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
2005-05-01 19:58:45 +04:00
nnote = 12 + ROUNDUP ( strlen ( arch ) + 1 ) + sizeof ( descr ) ;
nnote2 = 12 + ROUNDUP ( strlen ( rpaname ) + 1 ) + sizeof ( rpanote ) ;
2005-04-17 02:20:36 +04:00
n = read ( fd , buf , sizeof ( buf ) ) ;
if ( n < 0 ) {
perror ( " read " ) ;
exit ( 1 ) ;
}
2014-04-24 11:23:34 +04:00
if ( memcmp ( & buf [ E_IDENT + EI_MAGIC ] , elf_magic , 4 ) ! = 0 )
goto notelf ;
e_class = buf [ E_IDENT + EI_CLASS ] ;
if ( e_class ! = ELFCLASS32 & & e_class ! = ELFCLASS64 )
goto notelf ;
e_data = buf [ E_IDENT + EI_DATA ] ;
if ( e_data ! = ELFDATA2MSB & & e_data ! = ELFDATA2LSB )
goto notelf ;
if ( n < E_HSIZE )
2005-04-17 02:20:36 +04:00
goto notelf ;
2014-04-24 11:23:34 +04:00
ph = ( e_class = = ELFCLASS32 ? GET_32 ( E_PHOFF ) : GET_64 ( E_PHOFF ) ) ;
ps = GET_16 ( E_PHENTSIZE ) ;
np = GET_16 ( E_PHNUM ) ;
2005-04-17 02:20:36 +04:00
if ( ph < E_HSIZE | | ps < PH_HSIZE | | np < 1 )
goto notelf ;
2005-05-01 19:58:45 +04:00
if ( ph + ( np + 2 ) * ps + nnote + nnote2 > n )
2005-04-17 02:20:36 +04:00
goto nospace ;
for ( i = 0 ; i < np ; + + i ) {
2014-04-24 11:23:34 +04:00
if ( GET_32 ( ph + PH_TYPE ) = = PT_NOTE ) {
2005-04-17 02:20:36 +04:00
fprintf ( stderr , " %s already has a note entry \n " ,
2008-10-31 14:27:17 +03:00
av [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 0 ) ;
}
ph + = ps ;
}
/* XXX check that the area we want to use is all zeroes */
2005-05-01 19:58:45 +04:00
for ( i = 0 ; i < 2 * ps + nnote + nnote2 ; + + i )
2005-04-17 02:20:36 +04:00
if ( buf [ ph + i ] ! = 0 )
goto nospace ;
/* fill in the program header entry */
2005-05-01 19:58:45 +04:00
ns = ph + 2 * ps ;
2014-04-24 11:23:34 +04:00
PUT_32 ( ph + PH_TYPE , PT_NOTE ) ;
if ( e_class = = ELFCLASS32 )
PUT_32 ( ph + PH_OFFSET , ns ) ;
else
PUT_64 ( ph + PH_OFFSET , ns ) ;
if ( e_class = = ELFCLASS32 )
PUT_32 ( ph + PH_FILESZ , nnote ) ;
else
PUT_64 ( ph + PH_FILESZ , nnote ) ;
2005-04-17 02:20:36 +04:00
/* fill in the note area we point to */
/* XXX we should probably make this a proper section */
2014-04-24 11:23:34 +04:00
PUT_32 ( ns , strlen ( arch ) + 1 ) ;
PUT_32 ( ns + 4 , N_DESCR * 4 ) ;
PUT_32 ( ns + 8 , 0x1275 ) ;
2005-08-08 07:24:38 +04:00
strcpy ( ( char * ) & buf [ ns + 12 ] , arch ) ;
2005-04-17 02:20:36 +04:00
ns + = 12 + strlen ( arch ) + 1 ;
2005-05-01 19:58:45 +04:00
for ( i = 0 ; i < N_DESCR ; + + i , ns + = 4 )
2008-10-31 14:27:17 +03:00
PUT_32BE ( ns , descr [ i ] ) ;
2005-05-01 19:58:45 +04:00
/* fill in the second program header entry and the RPA note area */
ph + = ps ;
2014-04-24 11:23:34 +04:00
PUT_32 ( ph + PH_TYPE , PT_NOTE ) ;
if ( e_class = = ELFCLASS32 )
PUT_32 ( ph + PH_OFFSET , ns ) ;
else
PUT_64 ( ph + PH_OFFSET , ns ) ;
if ( e_class = = ELFCLASS32 )
PUT_32 ( ph + PH_FILESZ , nnote ) ;
else
PUT_64 ( ph + PH_FILESZ , nnote2 ) ;
2005-05-01 19:58:45 +04:00
/* fill in the note area we point to */
2014-04-24 11:23:34 +04:00
PUT_32 ( ns , strlen ( rpaname ) + 1 ) ;
PUT_32 ( ns + 4 , sizeof ( rpanote ) ) ;
PUT_32 ( ns + 8 , 0x12759999 ) ;
2008-10-31 14:27:17 +03:00
strcpy ( ( char * ) & buf [ ns + 12 ] , rpaname ) ;
ns + = 12 + ROUNDUP ( strlen ( rpaname ) + 1 ) ;
for ( i = 0 ; i < N_RPA_DESCR ; + + i , ns + = 4 )
PUT_32BE ( ns , rpanote [ i ] ) ;
2005-04-17 02:20:36 +04:00
/* Update the number of program headers */
2014-04-24 11:23:34 +04:00
PUT_16 ( E_PHNUM , np + 2 ) ;
2005-04-17 02:20:36 +04:00
/* write back */
lseek ( fd , ( long ) 0 , SEEK_SET ) ;
i = write ( fd , buf , n ) ;
if ( i < 0 ) {
perror ( " write " ) ;
exit ( 1 ) ;
}
if ( i < n ) {
2008-10-31 14:27:17 +03:00
fprintf ( stderr , " %s: write truncated \n " , av [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}
exit ( 0 ) ;
notelf :
2008-10-31 14:27:17 +03:00
fprintf ( stderr , " %s does not appear to be an ELF file \n " , av [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
nospace :
fprintf ( stderr , " sorry, I can't find space in %s to put the note \n " ,
2008-10-31 14:27:17 +03:00
av [ 1 ] ) ;
2005-04-17 02:20:36 +04:00
exit ( 1 ) ;
}