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