xref: /minix3/usr.sbin/installboot/arch/pmax.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1 /*	$NetBSD: pmax.c,v 1.15 2013/10/21 15:37:46 christos 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  *
22  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*
36  * Copyright (c) 1999 Ross Harvey.  All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *      This product includes software developed by Ross Harvey
49  *	for the NetBSD Project.
50  * 4. The name of the author may not be used to endorse or promote products
51  *    derived from this software without specific prior written permission
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
58  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
62  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63  */
64 
65 /*
66  * Copyright (c) 1999 Christopher G. Demetriou.  All rights reserved.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. All advertising materials mentioning features or use of this software
77  *    must display the following acknowledgement:
78  *      This product includes software developed by Christopher G. Demetriou
79  *	for the NetBSD Project.
80  * 4. The name of the author may not be used to endorse or promote products
81  *    derived from this software without specific prior written permission
82  *
83  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
84  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
85  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
86  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
87  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
88  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
89  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
90  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
91  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
92  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
93  */
94 
95 #if HAVE_NBTOOL_CONFIG_H
96 #include "nbtool_config.h"
97 #endif
98 
99 #include <sys/cdefs.h>
100 #if !defined(__lint)
101 __RCSID("$NetBSD: pmax.c,v 1.15 2013/10/21 15:37:46 christos Exp $");
102 #endif	/* !__lint */
103 
104 #include <sys/param.h>
105 
106 #include <assert.h>
107 #include <err.h>
108 #include <stddef.h>
109 #include <stdio.h>
110 #include <stdlib.h>
111 #include <string.h>
112 #include <unistd.h>
113 
114 #include <sys/exec_elf.h>
115 
116 #include "installboot.h"
117 
118 static int	load_bootstrap(ib_params *, char **,
119 				uint32_t *, uint32_t *, size_t *);
120 
121 static int pmax_clearboot(ib_params *);
122 static int pmax_setboot(ib_params *);
123 
124 struct ib_mach ib_mach_pmax =
125 	{ "pmax", pmax_setboot, pmax_clearboot, no_editboot,
126 		IB_STAGE1START | IB_APPEND | IB_SUNSUM };
127 
128 
129 static int
pmax_clearboot(ib_params * params)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 static int
pmax_setboot(ib_params * params)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 = 0;	/* XXX: gcc */
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 ((size_t)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
load_bootstrap(ib_params * params,char ** data,uint32_t * loadaddr,uint32_t * execaddr,size_t * len)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 ((Elf32_Word)pread(params->s1fd,
361 		    *data + seglist[i].addr - lowaddr,
362 		    seglist[i].f_size, (off_t)seglist[i].f_offset)
363 		    != seglist[i].f_size) {
364 			warn("Reading `%s'", params->stage1);
365 			return (0);
366 		}
367 	}
368 	return (1);
369 }
370