xref: /netbsd-src/usr.sbin/installboot/arch/pmax.c (revision 0dfdd76021dded97c9454f8152f173507b21859d)
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