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