xref: /netbsd/usr.sbin/installboot/arch/pmax.c (revision bf9ec67e)
1 /*	$NetBSD: pmax.c,v 1.9 2002/05/15 02:18:23 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.9 2002/05/15 02:18:23 lukem Exp $");
105 #endif	/* !__lint */
106 
107 #if HAVE_CONFIG_H
108 #include "config.h"
109 #endif
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 
129 int
130 pmax_parseopt(ib_params *params, const char *option)
131 {
132 
133 	if (parseoptionflag(params, option, IB_APPEND | IB_SUNSUM))
134 		return (1);
135 
136 	warnx("Unknown -o option `%s'", option);
137 	return (0);
138 }
139 
140 int
141 pmax_clearboot(ib_params *params)
142 {
143 	struct pmax_boot_block	bb;
144 	ssize_t			rv;
145 
146 	assert(params != NULL);
147 	assert(params->fsfd != -1);
148 	assert(params->filesystem != NULL);
149 	assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
150 
151 	if (params->flags & (IB_STAGE1START | IB_APPEND)) {
152 		warnx("Can't use `-b bno' or `-o append' with `-c'");
153 		return (0);
154 	}
155 	if (params->flags & IB_STAGE2START) {
156 		warnx("`-B bno' is not supported for %s",
157 		    params->machine->name);
158 		return (0);
159 	}
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 pmax_boot_block	bb;
209 	uint32_t		startblock;
210 	int			retval;
211 	char			*bootstrapbuf;
212 	size_t			bootstrapsize;
213 	uint32_t		bootstrapload, bootstrapexec;
214 	ssize_t			rv;
215 
216 	assert(params != NULL);
217 	assert(params->fsfd != -1);
218 	assert(params->filesystem != NULL);
219 	assert(params->s1fd != -1);
220 	assert(params->stage1 != NULL);
221 	assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE);
222 
223 	retval = 0;
224 	bootstrapbuf = NULL;
225 
226 	if ((params->flags & IB_STAGE1START) &&
227 	    (params->flags & IB_APPEND)) {
228 		warnx("Can't use `-b bno' with `-o append'");
229 		goto done;
230 	}
231 	if (params->flags & IB_STAGE2START) {
232 		warnx("`-B bno' is not supported for %s",
233 		    params->machine->name);
234 		goto done;
235 	}
236 
237 	if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload,
238 	    &bootstrapexec, &bootstrapsize))
239 		goto done;
240 
241 	rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
242 	if (rv == -1) {
243 		warn("Reading `%s'", params->filesystem);
244 		goto done;
245 	} else if (rv != sizeof(bb)) {
246 		warnx("Reading `%s': short read", params->filesystem);
247 		goto done;
248 	}
249 
250 		/* fill in the updated boot block fields */
251 	if (params->flags & IB_APPEND) {
252 		if (! S_ISREG(params->fsstat.st_mode)) {
253 			warnx(
254 		    "`%s' must be a regular file to append a bootstrap",
255 			    params->filesystem);
256 			goto done;
257 		}
258 		startblock = howmany(params->fsstat.st_size,
259 		    PMAX_BOOT_BLOCK_BLOCKSIZE);
260 	} else if (params->flags & IB_STAGE1START) {
261 		startblock = params->s1start;
262 	} else {
263 		startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE
264 		    + 1;
265 	}
266 
267 	bb.map[0].start_block = htole32(startblock);
268 	bb.map[0].num_blocks =
269 	    htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE));
270 	bb.magic = htole32(PMAX_BOOT_MAGIC);
271 	bb.load_addr = htole32(bootstrapload);
272 	bb.exec_addr = htole32(bootstrapexec);
273 	bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS);
274 
275 	if (params->flags & IB_SUNSUM) {
276 		uint16_t	sum;
277 
278 		sum = compute_sunsum((uint16_t *)&bb);
279 		if (! set_sunsum(params, (uint16_t *)&bb, sum))
280 			goto done;
281 	}
282 
283 	if (params->flags & IB_VERBOSE) {
284 		printf("Bootstrap start sector: %u\n",
285 		    le32toh(bb.map[0].start_block));
286 		printf("Bootstrap sector count: %u\n",
287 		    le32toh(bb.map[0].num_blocks));
288 		printf("Bootstrap load address: %#x\n",
289 		    le32toh(bb.load_addr));
290 		printf("Bootstrap exec address: %#x\n",
291 		    le32toh(bb.exec_addr));
292 		printf("%sriting bootstrap\n",
293 		    (params->flags & IB_NOWRITE) ? "Not w" : "W");
294 	}
295 	if (params->flags & IB_NOWRITE) {
296 		retval = 1;
297 		goto done;
298 	}
299 	rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize,
300 	     startblock * PMAX_BOOT_BLOCK_BLOCKSIZE);
301 	if (rv == -1) {
302 		warn("Writing `%s'", params->filesystem);
303 		goto done;
304 	} else if (rv != bootstrapsize) {
305 		warnx("Writing `%s': short write", params->filesystem);
306 		goto done;
307 	}
308 
309 	if (params->flags & IB_VERBOSE)
310 		printf("Writing boot block\n");
311 	rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET);
312 	if (rv == -1) {
313 		warn("Writing `%s'", params->filesystem);
314 		goto done;
315 	} else if (rv != sizeof(bb)) {
316 		warnx("Writing `%s': short write", params->filesystem);
317 		goto done;
318 	} else {
319 		retval = 1;
320 	}
321 
322  done:
323 	if (bootstrapbuf)
324 		free(bootstrapbuf);
325 	return (retval);
326 }
327 
328 
329 #define MAX_SEGMENTS	10	/* We can load up to 10 segments */
330 
331 struct seglist {
332 	Elf32_Addr	addr;
333 	Elf32_Off	f_offset;
334 	Elf32_Word	f_size;
335 };
336 
337 static int
338 load_bootstrap(ib_params *params, char **data,
339 	uint32_t *loadaddr, uint32_t *execaddr, size_t *len)
340 {
341 	int		i, nsegs;
342 	Elf32_Addr	lowaddr, highaddr;
343 	Elf32_Ehdr	ehdr;
344 	Elf32_Phdr	phdr;
345 	struct seglist	seglist[MAX_SEGMENTS];
346 
347 	if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) {
348 		warn("Reading `%s'", params->stage1);
349 		return (0);
350 	}
351 	if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) ||
352 	    (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) {
353 		warnx("No ELF header in `%s'", params->stage1);
354 		return (0);
355 	}
356 
357 	nsegs = highaddr = 0;
358 	lowaddr = (uint32_t) ULONG_MAX;
359 
360 	for (i = 0; i < le16toh(ehdr.e_phnum); i++) {
361 		if (pread(params->s1fd, &phdr, sizeof(phdr),
362 		    (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr))
363 		    != sizeof(phdr)) {
364 			warn("Reading `%s'", params->stage1);
365 			return (0);
366 		}
367 		if (le32toh(phdr.p_type) != PT_LOAD)
368 			continue;
369 
370 		seglist[nsegs].addr = le32toh(phdr.p_paddr);
371 		seglist[nsegs].f_offset = le32toh(phdr.p_offset);
372 		seglist[nsegs].f_size = le32toh(phdr.p_filesz);
373 		nsegs++;
374 
375 		if (le32toh(phdr.p_paddr) < lowaddr)
376 			lowaddr = le32toh(phdr.p_paddr);
377 		if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr)
378 			highaddr = le32toh(phdr.p_paddr) +
379 			    le32toh(phdr.p_filesz);
380 	}
381 
382 	*loadaddr = lowaddr;
383 	*execaddr = le32toh(ehdr.e_entry);
384 	*len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE);
385 	if ((*data = malloc(*len)) == NULL) {
386 		warn("Allocating %lu bytes", (unsigned long) *len);
387 		return (0);
388 	}
389 
390 	/* Now load the bootstrap into memory */
391 	for (i = 0; i < nsegs; i++) {
392 		if (pread(params->s1fd, *data + seglist[i].addr - lowaddr,
393 		    seglist[i].f_size, (off_t)seglist[i].f_offset)
394 		    != seglist[i].f_size) {
395 			warn("Reading `%s'", params->stage1);
396 			return (0);
397 		}
398 	}
399 	return (1);
400 }
401