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