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