root/arch/sparc/boot/piggyback.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. align
  2. ld2
  3. st4
  4. die
  5. usage
  6. start_line
  7. end_line
  8. get_start_end
  9. get_hdrs_offset
  10. main

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3    Simple utility to make a single-image install kernel with initial ramdisk
   4    for Sparc tftpbooting without need to set up nfs.
   5 
   6    Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
   7    Pete Zaitcev <zaitcev@yahoo.com> endian fixes for cross-compiles, 2000.
   8    Copyright (C) 2011 Sam Ravnborg <sam@ravnborg.org>
   9 
  10  */
  11 
  12 #include <dirent.h>
  13 #include <stdlib.h>
  14 #include <string.h>
  15 #include <unistd.h>
  16 #include <ctype.h>
  17 #include <errno.h>
  18 #include <fcntl.h>
  19 #include <stdio.h>
  20 
  21 #include <sys/types.h>
  22 #include <sys/stat.h>
  23 
  24 /*
  25  * Note: run this on an a.out kernel (use elftoaout for it),
  26  * as PROM looks for a.out image only.
  27  */
  28 
  29 #define AOUT_TEXT_OFFSET   32
  30 
  31 static int is64bit = 0;
  32 
  33 /* align to power-of-two size */
  34 static int align(int n)
  35 {
  36         if (is64bit)
  37                 return (n + 0x1fff) & ~0x1fff;
  38         else
  39                 return (n + 0xfff) & ~0xfff;
  40 }
  41 
  42 /* read two bytes as big endian */
  43 static unsigned short ld2(char *p)
  44 {
  45         return (p[0] << 8) | p[1];
  46 }
  47 
  48 /* save 4 bytes as big endian */
  49 static void st4(char *p, unsigned int x)
  50 {
  51         p[0] = x >> 24;
  52         p[1] = x >> 16;
  53         p[2] = x >> 8;
  54         p[3] = x;
  55 }
  56 
  57 static void die(const char *str)
  58 {
  59         perror(str);
  60         exit(1);
  61 }
  62 
  63 static void usage(void)
  64 {
  65         /* fs_img.gz is an image of initial ramdisk. */
  66         fprintf(stderr, "Usage: piggyback bits vmlinux.aout System.map fs_img.gz\n");
  67         fprintf(stderr, "\tKernel image will be modified in place.\n");
  68         exit(1);
  69 }
  70 
  71 static int start_line(const char *line)
  72 {
  73         if (strcmp(line + 10, " _start\n") == 0)
  74                 return 1;
  75         else if (strcmp(line + 18, " _start\n") == 0)
  76                 return 1;
  77         return 0;
  78 }
  79 
  80 static int end_line(const char *line)
  81 {
  82         if (strcmp(line + 10, " _end\n") == 0)
  83                 return 1;
  84         else if (strcmp (line + 18, " _end\n") == 0)
  85                 return 1;
  86         return 0;
  87 }
  88 
  89 /*
  90  * Find address for start and end in System.map.
  91  * The file looks like this:
  92  * f0004000 ... _start
  93  * f0379f79 ... _end
  94  * 1234567890123456
  95  * ^coloumn 1
  96  * There is support for 64 bit addresses too.
  97  *
  98  * Return 0 if either start or end is not found
  99  */
 100 static int get_start_end(const char *filename, unsigned int *start,
 101                                                unsigned int *end)
 102 {
 103         FILE *map;
 104         char buffer[1024];
 105 
 106         *start = 0;
 107         *end = 0;
 108         map = fopen(filename, "r");
 109         if (!map)
 110                 die(filename);
 111         while (fgets(buffer, 1024, map)) {
 112                 if (start_line(buffer))
 113                         *start = strtoul(buffer, NULL, 16);
 114                 else if (end_line(buffer))
 115                         *end = strtoul(buffer, NULL, 16);
 116         }
 117         fclose (map);
 118 
 119         if (*start == 0 || *end == 0)
 120                 return 0;
 121 
 122         return 1;
 123 }
 124 
 125 #define LOOKBACK (128 * 4)
 126 #define BUFSIZE 1024
 127 /*
 128  * Find the HdrS entry from head_32/head_64.
 129  * We check if it is at the beginning of the file (sparc64 case)
 130  * and if not we search for it.
 131  * When we search do so in steps of 4 as HdrS is on a 4-byte aligned
 132  * address (it is on same alignment as sparc instructions)
 133  * Return the offset to the HdrS entry (as off_t)
 134  */
 135 static off_t get_hdrs_offset(int kernelfd, const char *filename)
 136 {
 137         char buffer[BUFSIZE];
 138         off_t offset;
 139         int i;
 140 
 141         if (lseek(kernelfd, 0, SEEK_SET) < 0)
 142                 die("lseek");
 143         if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE)
 144                 die(filename);
 145 
 146         if (buffer[40] == 'H' && buffer[41] == 'd' &&
 147             buffer[42] == 'r' && buffer[43] == 'S') {
 148                 return 40;
 149         } else {
 150                 /*  Find the gokernel label */
 151                 /* Decode offset from branch instruction */
 152                 offset = ld2(buffer + AOUT_TEXT_OFFSET + 2) << 2;
 153                 /* Go back 512 bytes so we do not miss HdrS */
 154                 offset -= LOOKBACK;
 155                 /* skip a.out header */
 156                 offset += AOUT_TEXT_OFFSET;
 157                 if (lseek(kernelfd, offset, SEEK_SET) < 0)
 158                         die("lseek");
 159                 if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE)
 160                         die(filename);
 161 
 162                 for (i = 0; i < LOOKBACK; i += 4) {
 163                         if (buffer[i + 0] == 'H' && buffer[i + 1] == 'd' &&
 164                             buffer[i + 2] == 'r' && buffer[i + 3] == 'S') {
 165                                 return offset + i;
 166                         }
 167                 }
 168         }
 169         fprintf (stderr, "Couldn't find headers signature in %s\n", filename);
 170         exit(1);
 171 }
 172 
 173 int main(int argc,char **argv)
 174 {
 175         static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 };
 176         char buffer[1024];
 177         unsigned int i, start, end;
 178         off_t offset;
 179         struct stat s;
 180         int image, tail;
 181 
 182         if (argc != 5)
 183                 usage();
 184         if (strcmp(argv[1], "64") == 0)
 185                 is64bit = 1;
 186         if (stat (argv[4], &s) < 0)
 187                 die(argv[4]);
 188 
 189         if (!get_start_end(argv[3], &start, &end)) {
 190                 fprintf(stderr, "Could not determine start and end from %s\n",
 191                         argv[3]);
 192                 exit(1);
 193         }
 194         if ((image = open(argv[2], O_RDWR)) < 0)
 195                 die(argv[2]);
 196         if (read(image, buffer, 512) != 512)
 197                 die(argv[2]);
 198         if (memcmp(buffer, aout_magic, 4) != 0) {
 199                 fprintf (stderr, "Not a.out. Don't blame me.\n");
 200                 exit(1);
 201         }
 202         /*
 203          * We need to fill in values for
 204          * sparc_ramdisk_image + sparc_ramdisk_size
 205          * To locate these symbols search for the "HdrS" text which appear
 206          * in the image a little before the gokernel symbol.
 207          * See definition of these in init_32.S
 208          */
 209 
 210         offset = get_hdrs_offset(image, argv[2]);
 211         /* skip HdrS + LINUX_VERSION_CODE + HdrS version */
 212         offset += 10;
 213 
 214         if (lseek(image, offset, 0) < 0)
 215                 die("lseek");
 216 
 217         /*
 218          * root_flags = 0
 219          * root_dev = 1 (RAMDISK_MAJOR)
 220          * ram_flags = 0
 221          * sparc_ramdisk_image = "PAGE aligned address after _end")
 222          * sparc_ramdisk_size = size of image
 223          */
 224         st4(buffer, 0);
 225         st4(buffer + 4, 0x01000000);
 226         st4(buffer + 8, align(end + 32));
 227         st4(buffer + 12, s.st_size);
 228 
 229         if (write(image, buffer + 2, 14) != 14)
 230                 die(argv[2]);
 231 
 232         /* For sparc64 update a_text and clear a_data + a_bss */
 233         if (is64bit)
 234         {
 235                 if (lseek(image, 4, 0) < 0)
 236                         die("lseek");
 237                 /* a_text */
 238                 st4(buffer, align(end + 32 + 8191) - (start & ~0x3fffffUL) +
 239                             s.st_size);
 240                 /* a_data */
 241                 st4(buffer + 4, 0);
 242                 /* a_bss */
 243                 st4(buffer + 8, 0);
 244                 if (write(image, buffer, 12) != 12)
 245                         die(argv[2]);
 246         }
 247 
 248         /* seek page aligned boundary in the image file and add boot image */
 249         if (lseek(image, AOUT_TEXT_OFFSET - start + align(end + 32), 0) < 0)
 250                 die("lseek");
 251         if ((tail = open(argv[4], O_RDONLY)) < 0)
 252                 die(argv[4]);
 253         while ((i = read(tail, buffer, 1024)) > 0)
 254                 if (write(image, buffer, i) != i)
 255                         die(argv[2]);
 256         if (close(image) < 0)
 257                 die("close");
 258         if (close(tail) < 0)
 259                 die("close");
 260         return 0;
 261 }

/* [<][>][^][v][top][bottom][index][help] */