Blame view

arch/sparc/boot/piggyback.c 6.59 KB
88278ca27   Adrian Bunk   sparc: remove CVS...
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
     Simple utility to make a single-image install kernel with initial ramdisk
     for Sparc tftpbooting without need to set up nfs.
050855887   Sam Ravnborg   sparc: update cop...
4
     Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
     Pete Zaitcev <zaitcev@yahoo.com> endian fixes for cross-compiles, 2000.
050855887   Sam Ravnborg   sparc: update cop...
6
     Copyright (C) 2011 Sam Ravnborg <sam@ravnborg.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
  
     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.
2fe74fa96   Sam Ravnborg   sparc: refactor p...
12

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
     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 02139, USA.  */
2fe74fa96   Sam Ravnborg   sparc: refactor p...
21
22
23
  
  #include <dirent.h>
  #include <stdlib.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <string.h>
2fe74fa96   Sam Ravnborg   sparc: refactor p...
25
  #include <unistd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
  #include <ctype.h>
  #include <errno.h>
  #include <fcntl.h>
2fe74fa96   Sam Ravnborg   sparc: refactor p...
29
  #include <stdio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
  #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.
   */
9c2390530   Sam Ravnborg   sparc: additional...
37
  #define AOUT_TEXT_OFFSET   32
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
38
39
40
41
42
43
44
45
46
47
  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;
  }
2fe74fa96   Sam Ravnborg   sparc: refactor p...
48
  /* read two bytes as big endian */
c843e3154   Josh Triplett   arch/sparc/boot/*...
49
  static unsigned short ld2(char *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
  {
  	return (p[0] << 8) | p[1];
  }
2fe74fa96   Sam Ravnborg   sparc: refactor p...
53
  /* save 4 bytes as big endian */
c843e3154   Josh Triplett   arch/sparc/boot/*...
54
  static void st4(char *p, unsigned int x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
  {
  	p[0] = x >> 24;
  	p[1] = x >> 16;
  	p[2] = x >> 8;
  	p[3] = x;
  }
2fe74fa96   Sam Ravnborg   sparc: refactor p...
61
62
63
64
65
  static void die(const char *str)
  {
  	perror(str);
  	exit(1);
  }
c843e3154   Josh Triplett   arch/sparc/boot/*...
66
  static void usage(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  {
  	/* fs_img.gz is an image of initial ramdisk. */
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
69
70
  	fprintf(stderr, "Usage: piggyback bits vmlinux.aout System.map fs_img.gz
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  	fprintf(stderr, "\tKernel image will be modified in place.
  ");
  	exit(1);
  }
2fe74fa96   Sam Ravnborg   sparc: refactor p...
75
  static int start_line(const char *line)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  {
b2a39b0d8   Sam Ravnborg   sparc: use _start...
77
78
  	if (strcmp(line + 8, " T _start
  ") == 0)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
79
  		return 1;
b2a39b0d8   Sam Ravnborg   sparc: use _start...
80
81
  	else if (strcmp(line + 16, " T _start
  ") == 0)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  		return 1;
  	return 0;
  }
  
  static int end_line(const char *line)
  {
  	if (strcmp(line + 8, " A _end
  ") == 0)
  		return 1;
  	else if (strcmp (line + 16, " A _end
  ") == 0)
  		return 1;
  	return 0;
  }
  
  /*
   * Find address for start and end in System.map.
   * The file looks like this:
b2a39b0d8   Sam Ravnborg   sparc: use _start...
100
   * f0004000 T _start
2fe74fa96   Sam Ravnborg   sparc: refactor p...
101
102
103
104
105
106
107
   * f0379f79 A _end
   * 1234567890123456
   * ^coloumn 1
   * There is support for 64 bit addresses too.
   *
   * Return 0 if either start or end is not found
   */
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
108
109
  static int get_start_end(const char *filename, unsigned int *start,
                                                 unsigned int *end)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  {
  	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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  }
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  #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
  ", filename);
  	exit(1);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  int main(int argc,char **argv)
  {
  	static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 };
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
183
184
185
  	char buffer[1024];
  	unsigned int i, start, end;
  	off_t offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
  	struct stat s;
  	int image, tail;
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
188
  	if (argc != 5)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
189
  		usage();
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
190
191
192
193
  	if (strcmp(argv[1], "64") == 0)
  		is64bit = 1;
  	if (stat (argv[4], &s) < 0)
  		die(argv[4]);
2fe74fa96   Sam Ravnborg   sparc: refactor p...
194

a020bb17b   Sam Ravnborg   sparc: add $BITS ...
195
  	if (!get_start_end(argv[3], &start, &end)) {
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
196
197
198
  		fprintf(stderr, "Could not determine start and end from %s
  ",
  		        argv[3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  		exit(1);
  	}
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
201
202
  	if ((image = open(argv[2], O_RDWR)) < 0)
  		die(argv[2]);
2fe74fa96   Sam Ravnborg   sparc: refactor p...
203
  	if (read(image, buffer, 512) != 512)
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
204
  		die(argv[2]);
571e08f6e   Sam Ravnborg   sparc: remove obs...
205
206
207
  	if (memcmp(buffer, aout_magic, 4) != 0) {
  		fprintf (stderr, "Not a.out. Don't blame me.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  		exit(1);
  	}
9c2390530   Sam Ravnborg   sparc: additional...
210
  	/*
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
211
212
  	 * We need to fill in values for
  	 * sparc_ramdisk_image + sparc_ramdisk_size
9c2390530   Sam Ravnborg   sparc: additional...
213
214
215
216
  	 * 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
  	 */
1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
217
218
219
  	offset = get_hdrs_offset(image, argv[2]);
  	/* skip HdrS + LINUX_VERSION_CODE + HdrS version */
  	offset += 10;
2fe74fa96   Sam Ravnborg   sparc: refactor p...
220
221
  	if (lseek(image, offset, 0) < 0)
  		die("lseek");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222

9c2390530   Sam Ravnborg   sparc: additional...
223
224
225
226
227
228
229
  	/*
  	 * 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
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
231
  	st4(buffer, 0);
  	st4(buffer + 4, 0x01000000);
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
232
  	st4(buffer + 8, align(end + 32));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  	st4(buffer + 12, s.st_size);
2fe74fa96   Sam Ravnborg   sparc: refactor p...
234
  	if (write(image, buffer + 2, 14) != 14)
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
235
  		die(argv[2]);
9c2390530   Sam Ravnborg   sparc: additional...
236

1075c4ef7   Sam Ravnborg   sparc: fix tftpbo...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  	/* 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]);
  	}
9c2390530   Sam Ravnborg   sparc: additional...
252
  	/* seek page aligned boundary in the image file and add boot image */
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
253
  	if (lseek(image, AOUT_TEXT_OFFSET - start + align(end + 32), 0) < 0)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
254
  		die("lseek");
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
255
256
  	if ((tail = open(argv[4], O_RDONLY)) < 0)
  		die(argv[4]);
9c2390530   Sam Ravnborg   sparc: additional...
257
  	while ((i = read(tail, buffer, 1024)) > 0)
2fe74fa96   Sam Ravnborg   sparc: refactor p...
258
  		if (write(image, buffer, i) != i)
a020bb17b   Sam Ravnborg   sparc: add $BITS ...
259
  			die(argv[2]);
2fe74fa96   Sam Ravnborg   sparc: refactor p...
260
261
262
263
264
  	if (close(image) < 0)
  		die("close");
  	if (close(tail) < 0)
  		die("close");
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  }