1 1.16 thorpej /* $NetBSD: pmax.c,v 1.16 2019/05/07 04:35:31 thorpej Exp $ */ 2 1.1 lukem 3 1.1 lukem /*- 4 1.1 lukem * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc. 5 1.1 lukem * All rights reserved. 6 1.1 lukem * 7 1.1 lukem * This code is derived from software contributed to The NetBSD Foundation 8 1.1 lukem * by Simon Burge. 9 1.1 lukem * 10 1.1 lukem * This code is derived from software contributed to The NetBSD Foundation 11 1.1 lukem * by Luke Mewburn of Wasabi Systems. 12 1.1 lukem * 13 1.1 lukem * Redistribution and use in source and binary forms, with or without 14 1.1 lukem * modification, are permitted provided that the following conditions 15 1.1 lukem * are met: 16 1.1 lukem * 1. Redistributions of source code must retain the above copyright 17 1.1 lukem * notice, this list of conditions and the following disclaimer. 18 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright 19 1.1 lukem * notice, this list of conditions and the following disclaimer in the 20 1.1 lukem * documentation and/or other materials provided with the distribution. 21 1.1 lukem * 22 1.1 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 1.1 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 1.1 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 1.1 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 1.1 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 1.1 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 1.1 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 1.1 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 1.1 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 1.1 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 1.1 lukem * POSSIBILITY OF SUCH DAMAGE. 33 1.1 lukem */ 34 1.1 lukem 35 1.1 lukem /* 36 1.1 lukem * Copyright (c) 1999 Ross Harvey. All rights reserved. 37 1.1 lukem * 38 1.1 lukem * Redistribution and use in source and binary forms, with or without 39 1.1 lukem * modification, are permitted provided that the following conditions 40 1.1 lukem * are met: 41 1.1 lukem * 1. Redistributions of source code must retain the above copyright 42 1.1 lukem * notice, this list of conditions and the following disclaimer. 43 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright 44 1.1 lukem * notice, this list of conditions and the following disclaimer in the 45 1.1 lukem * documentation and/or other materials provided with the distribution. 46 1.1 lukem * 3. All advertising materials mentioning features or use of this software 47 1.1 lukem * must display the following acknowledgement: 48 1.1 lukem * This product includes software developed by Ross Harvey 49 1.1 lukem * for the NetBSD Project. 50 1.1 lukem * 4. The name of the author may not be used to endorse or promote products 51 1.1 lukem * derived from this software without specific prior written permission 52 1.1 lukem * 53 1.1 lukem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 54 1.1 lukem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 55 1.1 lukem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 56 1.1 lukem * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 57 1.1 lukem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 58 1.1 lukem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 59 1.1 lukem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 60 1.1 lukem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 61 1.1 lukem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 62 1.1 lukem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 63 1.1 lukem */ 64 1.1 lukem 65 1.1 lukem /* 66 1.1 lukem * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. 67 1.1 lukem * 68 1.1 lukem * Redistribution and use in source and binary forms, with or without 69 1.1 lukem * modification, are permitted provided that the following conditions 70 1.1 lukem * are met: 71 1.1 lukem * 1. Redistributions of source code must retain the above copyright 72 1.1 lukem * notice, this list of conditions and the following disclaimer. 73 1.1 lukem * 2. Redistributions in binary form must reproduce the above copyright 74 1.1 lukem * notice, this list of conditions and the following disclaimer in the 75 1.1 lukem * documentation and/or other materials provided with the distribution. 76 1.1 lukem * 3. All advertising materials mentioning features or use of this software 77 1.1 lukem * must display the following acknowledgement: 78 1.1 lukem * This product includes software developed by Christopher G. Demetriou 79 1.1 lukem * for the NetBSD Project. 80 1.1 lukem * 4. The name of the author may not be used to endorse or promote products 81 1.1 lukem * derived from this software without specific prior written permission 82 1.1 lukem * 83 1.1 lukem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 84 1.1 lukem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 85 1.1 lukem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 86 1.1 lukem * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 87 1.1 lukem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 88 1.1 lukem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 89 1.1 lukem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 90 1.1 lukem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 91 1.1 lukem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 92 1.1 lukem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 93 1.1 lukem */ 94 1.1 lukem 95 1.11 lukem #if HAVE_NBTOOL_CONFIG_H 96 1.11 lukem #include "nbtool_config.h" 97 1.11 lukem #endif 98 1.11 lukem 99 1.1 lukem #include <sys/cdefs.h> 100 1.11 lukem #if !defined(__lint) 101 1.16 thorpej __RCSID("$NetBSD: pmax.c,v 1.16 2019/05/07 04:35:31 thorpej Exp $"); 102 1.1 lukem #endif /* !__lint */ 103 1.5 tv 104 1.1 lukem #include <sys/param.h> 105 1.1 lukem 106 1.1 lukem #include <assert.h> 107 1.1 lukem #include <err.h> 108 1.1 lukem #include <stddef.h> 109 1.1 lukem #include <stdio.h> 110 1.1 lukem #include <stdlib.h> 111 1.2 thorpej #include <string.h> 112 1.1 lukem #include <unistd.h> 113 1.1 lukem 114 1.1 lukem #include <sys/exec_elf.h> 115 1.1 lukem 116 1.1 lukem #include "installboot.h" 117 1.1 lukem 118 1.1 lukem static int load_bootstrap(ib_params *, char **, 119 1.4 lukem uint32_t *, uint32_t *, size_t *); 120 1.1 lukem 121 1.12 dsl static int pmax_clearboot(ib_params *); 122 1.12 dsl static int pmax_setboot(ib_params *); 123 1.1 lukem 124 1.16 thorpej struct ib_mach ib_mach_pmax = { 125 1.16 thorpej .name = "pmax", 126 1.16 thorpej .setboot = pmax_setboot, 127 1.16 thorpej .clearboot = pmax_clearboot, 128 1.16 thorpej .editboot = no_editboot, 129 1.16 thorpej .valid_flags = IB_STAGE1START | IB_APPEND | IB_SUNSUM, 130 1.16 thorpej }; 131 1.12 dsl 132 1.12 dsl 133 1.12 dsl static int 134 1.1 lukem pmax_clearboot(ib_params *params) 135 1.1 lukem { 136 1.1 lukem struct pmax_boot_block bb; 137 1.1 lukem ssize_t rv; 138 1.1 lukem 139 1.1 lukem assert(params != NULL); 140 1.1 lukem assert(params->fsfd != -1); 141 1.1 lukem assert(params->filesystem != NULL); 142 1.1 lukem assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE); 143 1.1 lukem 144 1.1 lukem rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); 145 1.1 lukem if (rv == -1) { 146 1.1 lukem warn("Reading `%s'", params->filesystem); 147 1.1 lukem return (0); 148 1.1 lukem } else if (rv != sizeof(bb)) { 149 1.1 lukem warnx("Reading `%s': short read", params->filesystem); 150 1.1 lukem return (0); 151 1.1 lukem } 152 1.1 lukem 153 1.1 lukem if (le32toh(bb.magic) != PMAX_BOOT_MAGIC) { 154 1.1 lukem warnx( 155 1.1 lukem "Old boot block magic number invalid; boot block invalid"); 156 1.1 lukem return (0); 157 1.1 lukem } 158 1.1 lukem 159 1.1 lukem bb.map[0].num_blocks = bb.map[0].start_block = bb.mode = 0; 160 1.1 lukem bb.magic = htole32(PMAX_BOOT_MAGIC); 161 1.1 lukem 162 1.1 lukem if (params->flags & IB_SUNSUM) { 163 1.4 lukem uint16_t sum; 164 1.1 lukem 165 1.4 lukem sum = compute_sunsum((uint16_t *)&bb); 166 1.4 lukem if (! set_sunsum(params, (uint16_t *)&bb, sum)) 167 1.1 lukem return (0); 168 1.1 lukem } 169 1.1 lukem 170 1.1 lukem if (params->flags & IB_VERBOSE) 171 1.1 lukem printf("%slearing boot block\n", 172 1.1 lukem (params->flags & IB_NOWRITE) ? "Not c" : "C"); 173 1.1 lukem if (params->flags & IB_NOWRITE) 174 1.1 lukem return (1); 175 1.1 lukem 176 1.1 lukem rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); 177 1.1 lukem if (rv == -1) { 178 1.1 lukem warn("Writing `%s'", params->filesystem); 179 1.1 lukem return (0); 180 1.1 lukem } else if (rv != sizeof(bb)) { 181 1.1 lukem warnx("Writing `%s': short write", params->filesystem); 182 1.1 lukem return (0); 183 1.1 lukem } 184 1.1 lukem 185 1.1 lukem return (1); 186 1.1 lukem } 187 1.1 lukem 188 1.12 dsl static int 189 1.1 lukem pmax_setboot(ib_params *params) 190 1.1 lukem { 191 1.1 lukem struct pmax_boot_block bb; 192 1.4 lukem uint32_t startblock; 193 1.4 lukem int retval; 194 1.1 lukem char *bootstrapbuf; 195 1.15 christos size_t bootstrapsize = 0; /* XXX: gcc */ 196 1.4 lukem uint32_t bootstrapload, bootstrapexec; 197 1.1 lukem ssize_t rv; 198 1.1 lukem 199 1.1 lukem assert(params != NULL); 200 1.1 lukem assert(params->fsfd != -1); 201 1.1 lukem assert(params->filesystem != NULL); 202 1.3 lukem assert(params->s1fd != -1); 203 1.3 lukem assert(params->stage1 != NULL); 204 1.1 lukem assert(sizeof(struct pmax_boot_block) == PMAX_BOOT_BLOCK_BLOCKSIZE); 205 1.1 lukem 206 1.1 lukem retval = 0; 207 1.1 lukem bootstrapbuf = NULL; 208 1.1 lukem 209 1.1 lukem if (! load_bootstrap(params, &bootstrapbuf, &bootstrapload, 210 1.1 lukem &bootstrapexec, &bootstrapsize)) 211 1.1 lukem goto done; 212 1.1 lukem 213 1.1 lukem rv = pread(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); 214 1.1 lukem if (rv == -1) { 215 1.1 lukem warn("Reading `%s'", params->filesystem); 216 1.1 lukem goto done; 217 1.1 lukem } else if (rv != sizeof(bb)) { 218 1.1 lukem warnx("Reading `%s': short read", params->filesystem); 219 1.1 lukem goto done; 220 1.1 lukem } 221 1.1 lukem 222 1.1 lukem /* fill in the updated boot block fields */ 223 1.1 lukem if (params->flags & IB_APPEND) { 224 1.9 lukem if (! S_ISREG(params->fsstat.st_mode)) { 225 1.1 lukem warnx( 226 1.3 lukem "`%s' must be a regular file to append a bootstrap", 227 1.1 lukem params->filesystem); 228 1.1 lukem goto done; 229 1.1 lukem } 230 1.9 lukem startblock = howmany(params->fsstat.st_size, 231 1.1 lukem PMAX_BOOT_BLOCK_BLOCKSIZE); 232 1.7 lukem } else if (params->flags & IB_STAGE1START) { 233 1.7 lukem startblock = params->s1start; 234 1.1 lukem } else { 235 1.1 lukem startblock = PMAX_BOOT_BLOCK_OFFSET / PMAX_BOOT_BLOCK_BLOCKSIZE 236 1.1 lukem + 1; 237 1.1 lukem } 238 1.1 lukem 239 1.1 lukem bb.map[0].start_block = htole32(startblock); 240 1.1 lukem bb.map[0].num_blocks = 241 1.1 lukem htole32(howmany(bootstrapsize, PMAX_BOOT_BLOCK_BLOCKSIZE)); 242 1.1 lukem bb.magic = htole32(PMAX_BOOT_MAGIC); 243 1.1 lukem bb.load_addr = htole32(bootstrapload); 244 1.1 lukem bb.exec_addr = htole32(bootstrapexec); 245 1.1 lukem bb.mode = htole32(PMAX_BOOTMODE_CONTIGUOUS); 246 1.1 lukem 247 1.1 lukem if (params->flags & IB_SUNSUM) { 248 1.4 lukem uint16_t sum; 249 1.1 lukem 250 1.4 lukem sum = compute_sunsum((uint16_t *)&bb); 251 1.4 lukem if (! set_sunsum(params, (uint16_t *)&bb, sum)) 252 1.1 lukem goto done; 253 1.1 lukem } 254 1.1 lukem 255 1.1 lukem if (params->flags & IB_VERBOSE) { 256 1.6 lukem printf("Bootstrap start sector: %u\n", 257 1.1 lukem le32toh(bb.map[0].start_block)); 258 1.6 lukem printf("Bootstrap sector count: %u\n", 259 1.1 lukem le32toh(bb.map[0].num_blocks)); 260 1.1 lukem printf("Bootstrap load address: %#x\n", 261 1.1 lukem le32toh(bb.load_addr)); 262 1.1 lukem printf("Bootstrap exec address: %#x\n", 263 1.1 lukem le32toh(bb.exec_addr)); 264 1.1 lukem printf("%sriting bootstrap\n", 265 1.1 lukem (params->flags & IB_NOWRITE) ? "Not w" : "W"); 266 1.1 lukem } 267 1.1 lukem if (params->flags & IB_NOWRITE) { 268 1.1 lukem retval = 1; 269 1.1 lukem goto done; 270 1.1 lukem } 271 1.1 lukem rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, 272 1.1 lukem startblock * PMAX_BOOT_BLOCK_BLOCKSIZE); 273 1.1 lukem if (rv == -1) { 274 1.1 lukem warn("Writing `%s'", params->filesystem); 275 1.1 lukem goto done; 276 1.14 lukem } else if ((size_t)rv != bootstrapsize) { 277 1.1 lukem warnx("Writing `%s': short write", params->filesystem); 278 1.1 lukem goto done; 279 1.1 lukem } 280 1.1 lukem 281 1.1 lukem if (params->flags & IB_VERBOSE) 282 1.1 lukem printf("Writing boot block\n"); 283 1.1 lukem rv = pwrite(params->fsfd, &bb, sizeof(bb), PMAX_BOOT_BLOCK_OFFSET); 284 1.1 lukem if (rv == -1) { 285 1.1 lukem warn("Writing `%s'", params->filesystem); 286 1.1 lukem goto done; 287 1.1 lukem } else if (rv != sizeof(bb)) { 288 1.1 lukem warnx("Writing `%s': short write", params->filesystem); 289 1.1 lukem goto done; 290 1.1 lukem } else { 291 1.1 lukem retval = 1; 292 1.1 lukem } 293 1.1 lukem 294 1.1 lukem done: 295 1.1 lukem if (bootstrapbuf) 296 1.1 lukem free(bootstrapbuf); 297 1.1 lukem return (retval); 298 1.1 lukem } 299 1.1 lukem 300 1.1 lukem 301 1.1 lukem #define MAX_SEGMENTS 10 /* We can load up to 10 segments */ 302 1.1 lukem 303 1.1 lukem struct seglist { 304 1.1 lukem Elf32_Addr addr; 305 1.1 lukem Elf32_Off f_offset; 306 1.1 lukem Elf32_Word f_size; 307 1.1 lukem }; 308 1.1 lukem 309 1.1 lukem static int 310 1.1 lukem load_bootstrap(ib_params *params, char **data, 311 1.4 lukem uint32_t *loadaddr, uint32_t *execaddr, size_t *len) 312 1.1 lukem { 313 1.1 lukem int i, nsegs; 314 1.1 lukem Elf32_Addr lowaddr, highaddr; 315 1.1 lukem Elf32_Ehdr ehdr; 316 1.1 lukem Elf32_Phdr phdr; 317 1.1 lukem struct seglist seglist[MAX_SEGMENTS]; 318 1.1 lukem 319 1.3 lukem if ((pread(params->s1fd, &ehdr, sizeof(ehdr), 0)) != sizeof(ehdr)) { 320 1.3 lukem warn("Reading `%s'", params->stage1); 321 1.1 lukem return (0); 322 1.1 lukem } 323 1.1 lukem if ((memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) || 324 1.1 lukem (ehdr.e_ident[EI_CLASS] != ELFCLASS32)) { 325 1.3 lukem warnx("No ELF header in `%s'", params->stage1); 326 1.1 lukem return (0); 327 1.1 lukem } 328 1.1 lukem 329 1.1 lukem nsegs = highaddr = 0; 330 1.4 lukem lowaddr = (uint32_t) ULONG_MAX; 331 1.1 lukem 332 1.1 lukem for (i = 0; i < le16toh(ehdr.e_phnum); i++) { 333 1.3 lukem if (pread(params->s1fd, &phdr, sizeof(phdr), 334 1.1 lukem (off_t) le32toh(ehdr.e_phoff) + i * sizeof(phdr)) 335 1.1 lukem != sizeof(phdr)) { 336 1.3 lukem warn("Reading `%s'", params->stage1); 337 1.1 lukem return (0); 338 1.1 lukem } 339 1.1 lukem if (le32toh(phdr.p_type) != PT_LOAD) 340 1.1 lukem continue; 341 1.1 lukem 342 1.1 lukem seglist[nsegs].addr = le32toh(phdr.p_paddr); 343 1.1 lukem seglist[nsegs].f_offset = le32toh(phdr.p_offset); 344 1.1 lukem seglist[nsegs].f_size = le32toh(phdr.p_filesz); 345 1.1 lukem nsegs++; 346 1.1 lukem 347 1.1 lukem if (le32toh(phdr.p_paddr) < lowaddr) 348 1.1 lukem lowaddr = le32toh(phdr.p_paddr); 349 1.1 lukem if (le32toh(phdr.p_paddr) + le32toh(phdr.p_filesz) > highaddr) 350 1.1 lukem highaddr = le32toh(phdr.p_paddr) + 351 1.1 lukem le32toh(phdr.p_filesz); 352 1.1 lukem } 353 1.1 lukem 354 1.1 lukem *loadaddr = lowaddr; 355 1.1 lukem *execaddr = le32toh(ehdr.e_entry); 356 1.1 lukem *len = roundup(highaddr - lowaddr, PMAX_BOOT_BLOCK_BLOCKSIZE); 357 1.1 lukem if ((*data = malloc(*len)) == NULL) { 358 1.1 lukem warn("Allocating %lu bytes", (unsigned long) *len); 359 1.1 lukem return (0); 360 1.1 lukem } 361 1.1 lukem 362 1.1 lukem /* Now load the bootstrap into memory */ 363 1.1 lukem for (i = 0; i < nsegs; i++) { 364 1.14 lukem if ((Elf32_Word)pread(params->s1fd, 365 1.14 lukem *data + seglist[i].addr - lowaddr, 366 1.1 lukem seglist[i].f_size, (off_t)seglist[i].f_offset) 367 1.1 lukem != seglist[i].f_size) { 368 1.3 lukem warn("Reading `%s'", params->stage1); 369 1.1 lukem return (0); 370 1.1 lukem } 371 1.1 lukem } 372 1.1 lukem return (1); 373 1.1 lukem } 374