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