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