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