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