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