Commit 1075c4ef707ca83afbeb0950094436eb0245ec86
Committed by
David S. Miller
1 parent
a020bb17b7
Exists in
master
and in
4 other branches
sparc: fix tftpboot.img for sparc64 on little-endian host
piggyback_32 adapted to support sparc64: - locating "HdrS" differs for sparc and sparc64 - sparc64 updates a_text, a_data + a_bss in the final a.out header Updated Makefile to use piggyback_32 for sparc64. Deleted the now unused piggyback_64.c piggyback_32.c is host endian neutral and works on both little-endian and big-endian hosts. This fixes a long standing bug where sparc64 could not generate tftpboot.img on a x86 host. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 3 changed files with 80 additions and 133 deletions Side-by-side Diff
arch/sparc/boot/Makefile
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | ROOT_IMG := /usr/src/root.img |
7 | 7 | ELFTOAOUT := elftoaout |
8 | 8 | |
9 | -hostprogs-y := piggyback_32 piggyback_64 btfixupprep | |
9 | +hostprogs-y := piggyback_32 btfixupprep | |
10 | 10 | targets := tftpboot.img btfix.o btfix.S image zImage vmlinux.aout |
11 | 11 | clean-files := System.map |
12 | 12 | |
... | ... | @@ -69,7 +69,7 @@ |
69 | 69 | |
70 | 70 | ifeq ($(CONFIG_SPARC64),y) |
71 | 71 | quiet_cmd_piggy = PIGGY $@ |
72 | - cmd_piggy = $(obj)/piggyback_64 $@ System.map $(ROOT_IMG) | |
72 | + cmd_piggy = $(obj)/piggyback_32 $(BITS) $@ System.map $(ROOT_IMG) | |
73 | 73 | quiet_cmd_strip = STRIP $@ |
74 | 74 | cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@ |
75 | 75 | |
... | ... | @@ -82,7 +82,7 @@ |
82 | 82 | $(obj)/zImage: $(obj)/image |
83 | 83 | $(call if_changed,gzip) |
84 | 84 | |
85 | -$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE | |
85 | +$(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback_32 System.map $(ROOT_IMG) FORCE | |
86 | 86 | $(call if_changed,elftoaout) |
87 | 87 | $(call if_changed,piggy) |
88 | 88 | @echo ' kernel: $@ is ready' |
arch/sparc/boot/piggyback_32.c
... | ... | @@ -107,7 +107,8 @@ |
107 | 107 | * |
108 | 108 | * Return 0 if either start or end is not found |
109 | 109 | */ |
110 | -static int get_start_end(const char *filename, unsigned int *start, unsigned int *end) | |
110 | +static int get_start_end(const char *filename, unsigned int *start, | |
111 | + unsigned int *end) | |
111 | 112 | { |
112 | 113 | FILE *map; |
113 | 114 | char buffer[1024]; |
114 | 115 | |
... | ... | @@ -131,11 +132,60 @@ |
131 | 132 | return 1; |
132 | 133 | } |
133 | 134 | |
135 | +#define LOOKBACK (128 * 4) | |
136 | +#define BUFSIZE 1024 | |
137 | +/* | |
138 | + * Find the HdrS entry from head_32/head_64. | |
139 | + * We check if it is at the beginning of the file (sparc64 case) | |
140 | + * and if not we search for it. | |
141 | + * When we search do so in steps of 4 as HdrS is on a 4-byte aligned | |
142 | + * address (it is on same alignment as sparc instructions) | |
143 | + * Return the offset to the HdrS entry (as off_t) | |
144 | + */ | |
145 | +static off_t get_hdrs_offset(int kernelfd, const char *filename) | |
146 | +{ | |
147 | + char buffer[BUFSIZE]; | |
148 | + off_t offset; | |
149 | + int i; | |
150 | + | |
151 | + if (lseek(kernelfd, 0, SEEK_SET) < 0) | |
152 | + die("lseek"); | |
153 | + if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE) | |
154 | + die(filename); | |
155 | + | |
156 | + if (buffer[40] == 'H' && buffer[41] == 'd' && | |
157 | + buffer[42] == 'r' && buffer[43] == 'S') { | |
158 | + return 40; | |
159 | + } else { | |
160 | + /* Find the gokernel label */ | |
161 | + /* Decode offset from branch instruction */ | |
162 | + offset = ld2(buffer + AOUT_TEXT_OFFSET + 2) << 2; | |
163 | + /* Go back 512 bytes so we do not miss HdrS */ | |
164 | + offset -= LOOKBACK; | |
165 | + /* skip a.out header */ | |
166 | + offset += AOUT_TEXT_OFFSET; | |
167 | + if (lseek(kernelfd, offset, SEEK_SET) < 0) | |
168 | + die("lseek"); | |
169 | + if (read(kernelfd, buffer, BUFSIZE) != BUFSIZE) | |
170 | + die(filename); | |
171 | + | |
172 | + for (i = 0; i < LOOKBACK; i += 4) { | |
173 | + if (buffer[i + 0] == 'H' && buffer[i + 1] == 'd' && | |
174 | + buffer[i + 2] == 'r' && buffer[i + 3] == 'S') { | |
175 | + return offset + i; | |
176 | + } | |
177 | + } | |
178 | + } | |
179 | + fprintf (stderr, "Couldn't find headers signature in %s\n", filename); | |
180 | + exit(1); | |
181 | +} | |
182 | + | |
134 | 183 | int main(int argc,char **argv) |
135 | 184 | { |
136 | 185 | static char aout_magic[] = { 0x01, 0x03, 0x01, 0x07 }; |
137 | - char buffer[1024], *q, *r; | |
138 | - unsigned int i, start, end, offset; | |
186 | + char buffer[1024]; | |
187 | + unsigned int i, start, end; | |
188 | + off_t offset; | |
139 | 189 | struct stat s; |
140 | 190 | int image, tail; |
141 | 191 | |
... | ... | @@ -147,7 +197,8 @@ |
147 | 197 | die(argv[4]); |
148 | 198 | |
149 | 199 | if (!get_start_end(argv[3], &start, &end)) { |
150 | - fprintf (stderr, "Could not determine start and end from %s\n", argv[3]); | |
200 | + fprintf(stderr, "Could not determine start and end from %s\n", | |
201 | + argv[3]); | |
151 | 202 | exit(1); |
152 | 203 | } |
153 | 204 | if ((image = open(argv[2], O_RDWR)) < 0) |
154 | 205 | |
... | ... | @@ -159,27 +210,17 @@ |
159 | 210 | exit(1); |
160 | 211 | } |
161 | 212 | /* |
162 | - * We need to fill in values for sparc_ramdisk_image + sparc_ramdisk_size | |
213 | + * We need to fill in values for | |
214 | + * sparc_ramdisk_image + sparc_ramdisk_size | |
163 | 215 | * To locate these symbols search for the "HdrS" text which appear |
164 | 216 | * in the image a little before the gokernel symbol. |
165 | 217 | * See definition of these in init_32.S |
166 | 218 | */ |
167 | 219 | |
168 | - /* Find the gokernel label */ | |
169 | - i = AOUT_TEXT_OFFSET + (ld2(buffer + AOUT_TEXT_OFFSET + 2) << 2) - 512; | |
170 | - if (lseek(image, i, 0) < 0) | |
171 | - die("lseek"); | |
172 | - if (read(image, buffer, 1024) != 1024) | |
173 | - die(argv[2]); | |
174 | - for (q = buffer, r = q + 512; q < r; q += 4) { | |
175 | - if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S') | |
176 | - break; | |
177 | - } | |
178 | - if (q == r) { | |
179 | - fprintf (stderr, "Couldn't find headers signature in the kernel.\n"); | |
180 | - exit(1); | |
181 | - } | |
182 | - offset = i + (q - buffer) + 10; | |
220 | + offset = get_hdrs_offset(image, argv[2]); | |
221 | + /* skip HdrS + LINUX_VERSION_CODE + HdrS version */ | |
222 | + offset += 10; | |
223 | + | |
183 | 224 | if (lseek(image, offset, 0) < 0) |
184 | 225 | die("lseek"); |
185 | 226 | |
... | ... | @@ -197,6 +238,22 @@ |
197 | 238 | |
198 | 239 | if (write(image, buffer + 2, 14) != 14) |
199 | 240 | die(argv[2]); |
241 | + | |
242 | + /* For sparc64 update a_text and clear a_data + a_bss */ | |
243 | + if (is64bit) | |
244 | + { | |
245 | + if (lseek(image, 4, 0) < 0) | |
246 | + die("lseek"); | |
247 | + /* a_text */ | |
248 | + st4(buffer, align(end + 32 + 8191) - (start & ~0x3fffffUL) + | |
249 | + s.st_size); | |
250 | + /* a_data */ | |
251 | + st4(buffer + 4, 0); | |
252 | + /* a_bss */ | |
253 | + st4(buffer + 8, 0); | |
254 | + if (write(image, buffer, 12) != 12) | |
255 | + die(argv[2]); | |
256 | + } | |
200 | 257 | |
201 | 258 | /* seek page aligned boundary in the image file and add boot image */ |
202 | 259 | if (lseek(image, AOUT_TEXT_OFFSET - start + align(end + 32), 0) < 0) |
arch/sparc/boot/piggyback_64.c
1 | -/* | |
2 | - Simple utility to make a single-image install kernel with initial ramdisk | |
3 | - for Sparc64 tftpbooting without need to set up nfs. | |
4 | - | |
5 | - Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | |
6 | - | |
7 | - This program is free software; you can redistribute it and/or modify | |
8 | - it under the terms of the GNU General Public License as published by | |
9 | - the Free Software Foundation; either version 2 of the License, or | |
10 | - (at your option) any later version. | |
11 | - | |
12 | - This program is distributed in the hope that it will be useful, | |
13 | - but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | - GNU General Public License for more details. | |
16 | - | |
17 | - You should have received a copy of the GNU General Public License | |
18 | - along with this program; if not, write to the Free Software | |
19 | - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | - | |
21 | -#include <stdio.h> | |
22 | -#include <string.h> | |
23 | -#include <ctype.h> | |
24 | -#include <errno.h> | |
25 | -#include <fcntl.h> | |
26 | -#include <dirent.h> | |
27 | -#include <unistd.h> | |
28 | -#include <stdlib.h> | |
29 | -#include <sys/types.h> | |
30 | -#include <sys/stat.h> | |
31 | - | |
32 | -/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly | |
33 | - usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */ | |
34 | - | |
35 | -static void die(char *str) | |
36 | -{ | |
37 | - perror (str); | |
38 | - exit(1); | |
39 | -} | |
40 | - | |
41 | -int main(int argc,char **argv) | |
42 | -{ | |
43 | - char buffer [1024], *q, *r; | |
44 | - unsigned int i, j, k, start, end, offset; | |
45 | - FILE *map; | |
46 | - struct stat s; | |
47 | - int image, tail; | |
48 | - | |
49 | - start = end = 0; | |
50 | - if (stat (argv[3], &s) < 0) die (argv[3]); | |
51 | - map = fopen (argv[2], "r"); | |
52 | - if (!map) die(argv[2]); | |
53 | - while (fgets (buffer, 1024, map)) { | |
54 | - if (!strcmp (buffer + 19, "_start\n")) | |
55 | - start = strtoul (buffer + 8, NULL, 16); | |
56 | - else if (!strcmp (buffer + 19, "_end\n")) | |
57 | - end = strtoul (buffer + 8, NULL, 16); | |
58 | - } | |
59 | - fclose (map); | |
60 | - if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]); | |
61 | - if (read(image,buffer,512) != 512) die(argv[1]); | |
62 | - if (!memcmp (buffer, "\177ELF", 4)) { | |
63 | - unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28)); | |
64 | - | |
65 | - i = p[1] + *(unsigned int *)(buffer + 24) - p[2]; | |
66 | - if (lseek(image,i,0) < 0) die("lseek"); | |
67 | - if (read(image,buffer,512) != 512) die(argv[1]); | |
68 | - j = 0; | |
69 | - } else if (*(unsigned int *)buffer == 0x01030107) { | |
70 | - i = j = 32; | |
71 | - } else { | |
72 | - fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n"); | |
73 | - exit(1); | |
74 | - } | |
75 | - k = i; | |
76 | - if (j == 32 && buffer[40] == 'H' && buffer[41] == 'd' && buffer[42] == 'r' && buffer[43] == 'S') { | |
77 | - offset = 40 + 10; | |
78 | - } else { | |
79 | - i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512; | |
80 | - if (lseek(image,i,0) < 0) die("lseek"); | |
81 | - if (read(image,buffer,1024) != 1024) die(argv[1]); | |
82 | - for (q = buffer, r = q + 512; q < r; q += 4) { | |
83 | - if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S') | |
84 | - break; | |
85 | - } | |
86 | - if (q == r) { | |
87 | - fprintf (stderr, "Couldn't find headers signature in the kernel.\n"); | |
88 | - exit(1); | |
89 | - } | |
90 | - offset = i + (q - buffer) + 10; | |
91 | - } | |
92 | - if (lseek(image, offset, 0) < 0) die ("lseek"); | |
93 | - *(unsigned *)buffer = 0; | |
94 | - *(unsigned *)(buffer + 4) = 0x01000000; | |
95 | - *(unsigned *)(buffer + 8) = ((end + 32 + 8191) & ~8191); | |
96 | - *(unsigned *)(buffer + 12) = s.st_size; | |
97 | - if (write(image,buffer+2,14) != 14) die (argv[1]); | |
98 | - if (lseek(image, 4, 0) < 0) die ("lseek"); | |
99 | - *(unsigned *)buffer = ((end + 32 + 8191) & ~8191) - (start & ~0x3fffffUL) + s.st_size; | |
100 | - *(unsigned *)(buffer + 4) = 0; | |
101 | - *(unsigned *)(buffer + 8) = 0; | |
102 | - if (write(image,buffer,12) != 12) die (argv[1]); | |
103 | - if (lseek(image, k - start + ((end + 32 + 8191) & ~8191), 0) < 0) die ("lseek"); | |
104 | - if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]); | |
105 | - while ((i = read (tail,buffer,1024)) > 0) | |
106 | - if (write(image,buffer,i) != i) die (argv[1]); | |
107 | - if (close(image) < 0) die("close"); | |
108 | - if (close(tail) < 0) die("close"); | |
109 | - return 0; | |
110 | -} |