pmax.c revision 1.7 1 /* $NetBSD: pmax.c,v 1.7 2002/05/14 06:18:52 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.7 2002/05/14 06:18:52 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 #if HAVE_CONFIG_H
124 #include "../../sys/dev/dec/dec_boot.h"
125 #else
126 #include <dev/dec/dec_boot.h>
127 #endif
128
129 #include "installboot.h"
130
131 static int load_bootstrap(ib_params *, char **,
132 uint32_t *, uint32_t *, size_t *);
133
134
135 int
136 pmax_parseopt(ib_params *params, const char *option)
137 {
138
139 if (parseoptionflag(params, option, IB_APPEND | IB_SUNSUM))
140 return (1);
141
142 warnx("Unknown -o option `%s'", option);
143 return (0);
144 }
145
146 int
147 pmax_clearboot(ib_params *params)
148 {
149 struct pmax_boot_block bb;
150 ssize_t rv;
151
152 assert(params != NULL);
153 assert(params->fsfd != -1);
154 assert(params->filesystem != NULL);
155 assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
156
157 if (params->flags & (IB_STAGE1START | IB_APPEND)) {
158 warnx("Can't use `-b bno' or `-o append' with `-c'");
159 return (0);
160 }
161 if (params->flags & IB_STAGE2START) {
162 warnx("`-B bno' is not supported for %s",
163 params->machine->name);
164 return (0);
165 }
166
167 rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
168 if (rv == -1) {
169 warn("Reading `%s'", params->filesystem);
170 return (0);
171 } else if (rv != sizeof(bb)) {
172 warnx("Reading `%s': short read", params->filesystem);
173 return (0);
174 }
175
176 if (le32toh(bb.magic) != PMAX_BOOT_MAGIC) {
177 warnx(
178 "Old boot block magic number invalid; boot block invalid");
179 return (0);
180 }
181
182 bb.map[0].num_blocks = bb.map[0].start_block = bb.mode = 0;
183 bb.magic = htole32(PMAX_BOOT_MAGIC);
184
185 if (params->flags & IB_SUNSUM) {
186 uint16_t sum;
187
188 sum = compute_sunsum((uint16_t *)&bb);
189 if (! set_sunsum(params, (uint16_t *)&bb, sum))
190 return (0);
191 }
192
193 if (params->flags & IB_VERBOSE)
194 printf("%slearing boot block\n",
195 (params->flags & IB_NOWRITE) ? "Not c" : "C");
196 if (params->flags & IB_NOWRITE)
197 return (1);
198
199 rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
200 if (rv == -1) {
201 warn("Writing `%s'", params->filesystem);
202 return (0);
203 } else if (rv != sizeof(bb)) {
204 warnx("Writing `%s': short write", params->filesystem);
205 return (0);
206 }
207
208 return (1);
209 }
210
211 int
212 pmax_setboot(ib_params *params)
213 {
214 struct stat bootstrapsb;
215 struct pmax_boot_block bb;
216 uint32_t startblock;
217 int retval;
218 char *bootstrapbuf;
219 size_t bootstrapsize;
220 uint32_t bootstrapload, bootstrapexec;
221 ssize_t rv;
222
223 assert(params != NULL);
224 assert(params->fsfd != -1);
225 assert(params->filesystem != NULL);
226 assert(params->s1fd != -1);
227 assert(params->stage1 != NULL);
228 assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
229
230 retval = 0;
231 bootstrapbuf = NULL;
232
233 if ((params->flags & IB_STAGE1START) &&
234 (params->flags & IB_APPEND)) {
235 warnx("Can't use `-b bno' with `-o append'");
236 goto done;
237 }
238 if (params->flags & IB_STAGE2START) {
239 warnx("`-B bno' is not supported for %s",
240 params->machine->name);
241 goto done;
242 }
243
244 if (fstat(params->s1fd, &bootstrapsb) == -1) {
245 warn("Examining `%s'", params->stage1);
246 goto done;
247 }
248 if (!S_ISREG(bootstrapsb.st_mode)) {
249 warnx("`%s' must be a regular file", params->stage1);
250 goto done;
251 }
252 if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
253 &bootstrapexec, &bootstrapsize))
254 goto done;
255
256 rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
257 if (rv == -1) {
258 warn("Reading `%s'", params->filesystem);
259 goto done;
260 } else if (rv != sizeof(bb)) {
261 warnx("Reading `%s': short read", params->filesystem);
262 goto done;
263 }
264
265 /* fill in the updated boot block fields */
266 if (params->flags & IB_APPEND) {
267 struct stat filesyssb;
268
269 if (fstat(params->fsfd, &filesyssb) == -1) {
270 warn("Examining `%s'", params->filesystem);
271 goto done;
272 }
273 if (!S_ISREG(filesyssb.st_mode)) {
274 warnx(
275 "`%s' must be a regular file to append a bootstrap",
276 params->filesystem);
277 goto done;
278 }
279 startblock = howmany(filesyssb.st_size,
280 PMAX_BOOT_BLOCK_BLOCKSIZE);
281 } else if (params->flags & IB_STAGE1START) {
282 startblock = params->s1start;
283 } else {
284 startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE
285 + 1;
286 }
287
288 bb.map[0].start_block = htole32(startblock);
289 bb.map[0].num_blocks =
290 htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE));
291 bb.magic = htole32(PMAX_BOOT_MAGIC);
292 bb.load_addr = htole32(bootstrapload);
293 bb.exec_addr = htole32(bootstrapexec);
294 bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS);
295
296 if (params->flags & IB_SUNSUM) {
297 uint16_t sum;
298
299 sum = compute_sunsum((uint16_t *)&bb);
300 if (! set_sunsum(params, (uint16_t *)&bb, sum))
301 goto done;
302 }
303
304 if (params->flags & IB_VERBOSE) {
305 printf("Bootstrap start sector: %u\n",
306 le32toh(bb.map[0].start_block));
307 printf("Bootstrap sector count: %u\n",
308 le32toh(bb.map[0].num_blocks));
309 printf("Bootstrap load address: %#x\n",
310 le32toh(bb.load_addr));
311 printf("Bootstrap exec address: %#x\n",
312 le32toh(bb.exec_addr));
313 printf("%sriting bootstrap\n",
314 (params->flags & IB_NOWRITE) ? "Not w" : "W");
315 }
316 if (params->flags & IB_NOWRITE) {
317 retval = 1;
318 goto done;
319 }
320 rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
321 startblock * PMAX_BOOT_BLOCK_BLOCKSIZE);
322 if (rv == -1) {
323 warn("Writing `%s'", params->filesystem);
324 goto done;
325 } else if (rv != bootstrapsize) {
326 warnx("Writing `%s': short write", params->filesystem);
327 goto done;
328 }
329
330 if (params->flags & IB_VERBOSE)
331 printf("Writing boot block\n");
332 rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
333 if (rv == -1) {
334 warn("Writing `%s'", params->filesystem);
335 goto done;
336 } else if (rv != sizeof(bb)) {
337 warnx("Writing `%s': short write", params->filesystem);
338 goto done;
339 } else {
340 retval = 1;
341 }
342
343 done:
344 if (bootstrapbuf)
345 free(bootstrapbuf);
346 return (retval);
347 }
348
349
350 #define MAX_SEGMENTS 10 /* We can load up to 10 segments */
351
352 struct seglist {
353 Elf32_Addr addr;
354 Elf32_Off f_offset;
355 Elf32_Word f_size;
356 };
357
358 static int
359 load_bootstrap(ib_params *params, char **data,
360 uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
361 {
362 int i, nsegs;
363 Elf32_Addr lowaddr, highaddr;
364 Elf32_Ehdr ehdr;
365 Elf32_Phdr phdr;
366 struct seglist seglist[MAX_SEGMENTS];
367
368 if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) {
369 warn("Reading `%s'", params->stage1);
370 return (0);
371 }
372 if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||
373 (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) {
374 warnx("No ELF header in `%s'", params->stage1);
375 return (0);
376 }
377
378 nsegs = highaddr = 0;
379 lowaddr = (uint32_t) ULONG_MAX;
380
381 for (i = 0; i < le16toh(ehdr.e_phnum); i++) {
382 if (pread(params->s1fd, &phdr, sizeof(phdr),
383 (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr))
384 != sizeof(phdr)) {
385 warn("Reading `%s'", params->stage1);
386 return (0);
387 }
388 if (le32toh(phdr.p_type) != PT_LOAD)
389 continue;
390
391 seglist[nsegs].addr = le32toh(phdr.p_paddr);
392 seglist[nsegs].f_offset = le32toh(phdr.p_offset);
393 seglist[nsegs].f_size = le32toh(phdr.p_filesz);
394 nsegs++;
395
396 if (le32toh(phdr.p_paddr) < lowaddr)
397 lowaddr = le32toh(phdr.p_paddr);
398 if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr)
399 highaddr = le32toh(phdr.p_paddr) +
400 le32toh(phdr.p_filesz);
401 }
402
403 *loadaddr = lowaddr;
404 *execaddr = le32toh(ehdr.e_entry);
405 *len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE);
406 if ((*data = malloc(*len)) == NULL) {
407 warn("Allocating %lu bytes", (unsigned long) *len);
408 return (0);
409 }
410
411 /* Now load the bootstrap into memory */
412 for (i = 0; i < nsegs; i++) {
413 if (pread(params->s1fd, *data + seglist[i].addr - lowaddr,
414 seglist[i].f_size, (off_t)seglist[i].f_offset)
415 != seglist[i].f_size) {
416 warn("Reading `%s'", params->stage1);
417 return (0);
418 }
419 }
420 return (1);
421 }
422