pmax.c revision 1.8 1 /* $NetBSD: pmax.c,v 1.8 2002/05/14 06:40:33 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Simon Burge.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Luke Mewburn of Wasabi Systems.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the NetBSD
24 * Foundation, Inc. and its contributors.
25 * 4. Neither the name of The NetBSD Foundation nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
40 */
41
42 /*
43 * Copyright (c) 1999 Ross Harvey. All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software
54 * must display the following acknowledgement:
55 * This product includes software developed by Ross Harvey
56 * for the NetBSD Project.
57 * 4. The name of the author may not be used to endorse or promote products
58 * derived from this software without specific prior written permission
59 *
60 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
61 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
62 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
63 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
64 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
65 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 */
71
72 /*
73 * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved.
74 *
75 * Redistribution and use in source and binary forms, with or without
76 * modification, are permitted provided that the following conditions
77 * are met:
78 * 1. Redistributions of source code must retain the above copyright
79 * notice, this list of conditions and the following disclaimer.
80 * 2. Redistributions in binary form must reproduce the above copyright
81 * notice, this list of conditions and the following disclaimer in the
82 * documentation and/or other materials provided with the distribution.
83 * 3. All advertising materials mentioning features or use of this software
84 * must display the following acknowledgement:
85 * This product includes software developed by Christopher G. Demetriou
86 * for the NetBSD Project.
87 * 4. The name of the author may not be used to endorse or promote products
88 * derived from this software without specific prior written permission
89 *
90 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
91 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
92 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
93 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
94 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
95 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
96 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
97 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
98 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
99 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
100 */
101
102 #include <sys/cdefs.h>
103 #if defined(__RCSID) && !defined(__lint)
104 __RCSID("$NetBSD: pmax.c,v 1.8 2002/05/14 06:40:33 lukem Exp $");
105 #endif /* !__lint */
106
107 #if HAVE_CONFIG_H
108 #include "config.h"
109 #endif
110
111 #include <sys/param.h>
112 #include <sys/stat.h>
113
114 #include <assert.h>
115 #include <err.h>
116 #include <stddef.h>
117 #include <stdio.h>
118 #include <stdlib.h>
119 #include <string.h>
120 #include <unistd.h>
121
122 #include <sys/exec_elf.h>
123
124 #include "installboot.h"
125
126 static int load_bootstrap(ib_params *, char **,
127 uint32_t *, uint32_t *, size_t *);
128
129
130 int
131 pmax_parseopt(ib_params *params, const char *option)
132 {
133
134 if (parseoptionflag(params, option, IB_APPEND | IB_SUNSUM))
135 return (1);
136
137 warnx("Unknown -o option `%s'", option);
138 return (0);
139 }
140
141 int
142 pmax_clearboot(ib_params *params)
143 {
144 struct pmax_boot_block bb;
145 ssize_t rv;
146
147 assert(params != NULL);
148 assert(params->fsfd != -1);
149 assert(params->filesystem != NULL);
150 assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
151
152 if (params->flags & (IB_STAGE1START | IB_APPEND)) {
153 warnx("Can't use `-b bno' or `-o append' with `-c'");
154 return (0);
155 }
156 if (params->flags & IB_STAGE2START) {
157 warnx("`-B bno' is not supported for %s",
158 params->machine->name);
159 return (0);
160 }
161
162 rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
163 if (rv == -1) {
164 warn("Reading `%s'", params->filesystem);
165 return (0);
166 } else if (rv != sizeof(bb)) {
167 warnx("Reading `%s': short read", params->filesystem);
168 return (0);
169 }
170
171 if (le32toh(bb.magic) != PMAX_BOOT_MAGIC) {
172 warnx(
173 "Old boot block magic number invalid; boot block invalid");
174 return (0);
175 }
176
177 bb.map[0].num_blocks = bb.map[0].start_block = bb.mode = 0;
178 bb.magic = htole32(PMAX_BOOT_MAGIC);
179
180 if (params->flags & IB_SUNSUM) {
181 uint16_t sum;
182
183 sum = compute_sunsum((uint16_t *)&bb);
184 if (! set_sunsum(params, (uint16_t *)&bb, sum))
185 return (0);
186 }
187
188 if (params->flags & IB_VERBOSE)
189 printf("%slearing boot block\n",
190 (params->flags & IB_NOWRITE) ? "Not c" : "C");
191 if (params->flags & IB_NOWRITE)
192 return (1);
193
194 rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
195 if (rv == -1) {
196 warn("Writing `%s'", params->filesystem);
197 return (0);
198 } else if (rv != sizeof(bb)) {
199 warnx("Writing `%s': short write", params->filesystem);
200 return (0);
201 }
202
203 return (1);
204 }
205
206 int
207 pmax_setboot(ib_params *params)
208 {
209 struct stat bootstrapsb;
210 struct pmax_boot_block bb;
211 uint32_t startblock;
212 int retval;
213 char *bootstrapbuf;
214 size_t bootstrapsize;
215 uint32_t bootstrapload, bootstrapexec;
216 ssize_t rv;
217
218 assert(params != NULL);
219 assert(params->fsfd != -1);
220 assert(params->filesystem != NULL);
221 assert(params->s1fd != -1);
222 assert(params->stage1 != NULL);
223 assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
224
225 retval = 0;
226 bootstrapbuf = NULL;
227
228 if ((params->flags & IB_STAGE1START) &&
229 (params->flags & IB_APPEND)) {
230 warnx("Can't use `-b bno' with `-o append'");
231 goto done;
232 }
233 if (params->flags & IB_STAGE2START) {
234 warnx("`-B bno' is not supported for %s",
235 params->machine->name);
236 goto done;
237 }
238
239 if (fstat(params->s1fd, &bootstrapsb) == -1) {
240 warn("Examining `%s'", params->stage1);
241 goto done;
242 }
243 if (!S_ISREG(bootstrapsb.st_mode)) {
244 warnx("`%s' must be a regular file", params->stage1);
245 goto done;
246 }
247 if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
248 &bootstrapexec, &bootstrapsize))
249 goto done;
250
251 rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
252 if (rv == -1) {
253 warn("Reading `%s'", params->filesystem);
254 goto done;
255 } else if (rv != sizeof(bb)) {
256 warnx("Reading `%s': short read", params->filesystem);
257 goto done;
258 }
259
260 /* fill in the updated boot block fields */
261 if (params->flags & IB_APPEND) {
262 struct stat filesyssb;
263
264 if (fstat(params->fsfd, &filesyssb) == -1) {
265 warn("Examining `%s'", params->filesystem);
266 goto done;
267 }
268 if (!S_ISREG(filesyssb.st_mode)) {
269 warnx(
270 "`%s' must be a regular file to append a bootstrap",
271 params->filesystem);
272 goto done;
273 }
274 startblock = howmany(filesyssb.st_size,
275 PMAX_BOOT_BLOCK_BLOCKSIZE);
276 } else if (params->flags & IB_STAGE1START) {
277 startblock = params->s1start;
278 } else {
279 startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE
280 + 1;
281 }
282
283 bb.map[0].start_block = htole32(startblock);
284 bb.map[0].num_blocks =
285 htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE));
286 bb.magic = htole32(PMAX_BOOT_MAGIC);
287 bb.load_addr = htole32(bootstrapload);
288 bb.exec_addr = htole32(bootstrapexec);
289 bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS);
290
291 if (params->flags & IB_SUNSUM) {
292 uint16_t sum;
293
294 sum = compute_sunsum((uint16_t *)&bb);
295 if (! set_sunsum(params, (uint16_t *)&bb, sum))
296 goto done;
297 }
298
299 if (params->flags & IB_VERBOSE) {
300 printf("Bootstrap start sector: %u\n",
301 le32toh(bb.map[0].start_block));
302 printf("Bootstrap sector count: %u\n",
303 le32toh(bb.map[0].num_blocks));
304 printf("Bootstrap load address: %#x\n",
305 le32toh(bb.load_addr));
306 printf("Bootstrap exec address: %#x\n",
307 le32toh(bb.exec_addr));
308 printf("%sriting bootstrap\n",
309 (params->flags & IB_NOWRITE) ? "Not w" : "W");
310 }
311 if (params->flags & IB_NOWRITE) {
312 retval = 1;
313 goto done;
314 }
315 rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
316 startblock * PMAX_BOOT_BLOCK_BLOCKSIZE);
317 if (rv == -1) {
318 warn("Writing `%s'", params->filesystem);
319 goto done;
320 } else if (rv != bootstrapsize) {
321 warnx("Writing `%s': short write", params->filesystem);
322 goto done;
323 }
324
325 if (params->flags & IB_VERBOSE)
326 printf("Writing boot block\n");
327 rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
328 if (rv == -1) {
329 warn("Writing `%s'", params->filesystem);
330 goto done;
331 } else if (rv != sizeof(bb)) {
332 warnx("Writing `%s': short write", params->filesystem);
333 goto done;
334 } else {
335 retval = 1;
336 }
337
338 done:
339 if (bootstrapbuf)
340 free(bootstrapbuf);
341 return (retval);
342 }
343
344
345 #define MAX_SEGMENTS 10 /* We can load up to 10 segments */
346
347 struct seglist {
348 Elf32_Addr addr;
349 Elf32_Off f_offset;
350 Elf32_Word f_size;
351 };
352
353 static int
354 load_bootstrap(ib_params *params, char **data,
355 uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
356 {
357 int i, nsegs;
358 Elf32_Addr lowaddr, highaddr;
359 Elf32_Ehdr ehdr;
360 Elf32_Phdr phdr;
361 struct seglist seglist[MAX_SEGMENTS];
362
363 if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) {
364 warn("Reading `%s'", params->stage1);
365 return (0);
366 }
367 if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||
368 (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) {
369 warnx("No ELF header in `%s'", params->stage1);
370 return (0);
371 }
372
373 nsegs = highaddr = 0;
374 lowaddr = (uint32_t) ULONG_MAX;
375
376 for (i = 0; i < le16toh(ehdr.e_phnum); i++) {
377 if (pread(params->s1fd, &phdr, sizeof(phdr),
378 (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr))
379 != sizeof(phdr)) {
380 warn("Reading `%s'", params->stage1);
381 return (0);
382 }
383 if (le32toh(phdr.p_type) != PT_LOAD)
384 continue;
385
386 seglist[nsegs].addr = le32toh(phdr.p_paddr);
387 seglist[nsegs].f_offset = le32toh(phdr.p_offset);
388 seglist[nsegs].f_size = le32toh(phdr.p_filesz);
389 nsegs++;
390
391 if (le32toh(phdr.p_paddr) < lowaddr)
392 lowaddr = le32toh(phdr.p_paddr);
393 if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr)
394 highaddr = le32toh(phdr.p_paddr) +
395 le32toh(phdr.p_filesz);
396 }
397
398 *loadaddr = lowaddr;
399 *execaddr = le32toh(ehdr.e_entry);
400 *len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE);
401 if ((*data = malloc(*len)) == NULL) {
402 warn("Allocating %lu bytes", (unsigned long) *len);
403 return (0);
404 }
405
406 /* Now load the bootstrap into memory */
407 for (i = 0; i < nsegs; i++) {
408 if (pread(params->s1fd, *data + seglist[i].addr - lowaddr,
409 seglist[i].f_size, (off_t)seglist[i].f_offset)
410 != seglist[i].f_size) {
411 warn("Reading `%s'", params->stage1);
412 return (0);
413 }
414 }
415 return (1);
416 }
417