1 /* $NetBSD: alpha.c,v 1.22 2019/05/07 04:35:31 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn of Wasabi Systems. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1999 Ross Harvey. All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgement: 45 * This product includes software developed by Ross Harvey 46 * for the NetBSD Project. 47 * 4. The name of the author may not be used to endorse or promote products 48 * derived from this software without specific prior written permission 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. 64 * 65 * Redistribution and use in source and binary forms, with or without 66 * modification, are permitted provided that the following conditions 67 * are met: 68 * 1. Redistributions of source code must retain the above copyright 69 * notice, this list of conditions and the following disclaimer. 70 * 2. Redistributions in binary form must reproduce the above copyright 71 * notice, this list of conditions and the following disclaimer in the 72 * documentation and/or other materials provided with the distribution. 73 * 3. All advertising materials mentioning features or use of this software 74 * must display the following acknowledgement: 75 * This product includes software developed by Christopher G. Demetriou 76 * for the NetBSD Project. 77 * 4. The name of the author may not be used to endorse or promote products 78 * derived from this software without specific prior written permission 79 * 80 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 81 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 82 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 83 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 84 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 85 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 86 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 87 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 88 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 89 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 90 */ 91 92 #if HAVE_NBTOOL_CONFIG_H 93 #include "nbtool_config.h" 94 #endif 95 96 #include <sys/cdefs.h> 97 #if !defined(__lint) 98 __RCSID("$NetBSD: alpha.c,v 1.22 2019/05/07 04:35:31 thorpej Exp $"); 99 #endif /* !__lint */ 100 101 #include <sys/param.h> 102 103 #include <assert.h> 104 #include <err.h> 105 #include <stddef.h> 106 #include <stdio.h> 107 #include <stdlib.h> 108 #include <string.h> 109 #include <unistd.h> 110 111 #include "installboot.h" 112 113 #define SUN_DKMAGIC 55998 /* XXX: from <dev/sun/disklabel.h> */ 114 115 static void resum(ib_params *, struct alpha_boot_block * const bb, 116 uint16_t *bb16); 117 static void sun_bootstrap(ib_params *, struct alpha_boot_block * const); 118 static void check_sparc(const struct alpha_boot_block * const, 119 const char *); 120 121 static int alpha_clearboot(ib_params *); 122 static int alpha_setboot(ib_params *); 123 124 struct ib_mach ib_mach_alpha = { 125 .name = "alpha", 126 .setboot = alpha_setboot, 127 .clearboot = alpha_clearboot, 128 .editboot = no_editboot, 129 .valid_flags = IB_STAGE1START | IB_ALPHASUM | IB_APPEND | 130 IB_SUNSUM, 131 }; 132 133 static int 134 alpha_clearboot(ib_params *params) 135 { 136 struct alpha_boot_block bb; 137 uint64_t cksum; 138 ssize_t rv; 139 140 assert(params != NULL); 141 assert(params->fsfd != -1); 142 assert(params->filesystem != NULL); 143 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 144 145 if (params->flags & (IB_STAGE1START | IB_APPEND)) { 146 warnx("Can't use `-b bno' or `-o append' with `-c'"); 147 return (0); 148 } 149 150 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 151 if (rv == -1) { 152 warn("Reading `%s'", params->filesystem); 153 return (0); 154 } else if (rv != sizeof(bb)) { 155 warnx("Reading `%s': short read", params->filesystem); 156 return (0); 157 } 158 ALPHA_BOOT_BLOCK_CKSUM(&bb, &cksum); 159 if (cksum != bb.bb_cksum) { // XXX check bb_cksum endian? 160 warnx( 161 "Old boot block checksum invalid (was %#llx, calculated %#llx)", 162 (unsigned long long)le64toh(bb.bb_cksum), 163 (unsigned long long)le64toh(cksum)); 164 warnx("Boot block invalid"); 165 return (0); 166 } 167 168 if (params->flags & IB_VERBOSE) { 169 printf("Old bootstrap start sector: %llu\n", 170 (unsigned long long)le64toh(bb.bb_secstart)); 171 printf("Old bootstrap size: %llu\n", 172 (unsigned long long)le64toh(bb.bb_secsize)); 173 printf("Old bootstrap checksum: %#llx\n", 174 (unsigned long long)le64toh(bb.bb_cksum)); 175 } 176 177 bb.bb_secstart = bb.bb_secsize = bb.bb_flags = 0; 178 179 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 180 if (params->flags & IB_SUNSUM) 181 sun_bootstrap(params, &bb); 182 183 printf("New bootstrap start sector: %llu\n", 184 (unsigned long long)le64toh(bb.bb_secstart)); 185 printf("New bootstrap size: %llu\n", 186 (unsigned long long)le64toh(bb.bb_secsize)); 187 printf("New bootstrap checksum: %#llx\n", 188 (unsigned long long)le64toh(bb.bb_cksum)); 189 190 if (params->flags & IB_VERBOSE) 191 printf("%slearing boot block\n", 192 (params->flags & IB_NOWRITE) ? "Not c" : "C"); 193 if (params->flags & IB_NOWRITE) 194 return (1); 195 196 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 197 if (rv == -1) { 198 warn("Writing `%s'", params->filesystem); 199 return (0); 200 } else if (rv != sizeof(bb)) { 201 warnx("Writing `%s': short write", params->filesystem); 202 return (0); 203 } 204 205 return (1); 206 } 207 208 static int 209 alpha_setboot(ib_params *params) 210 { 211 struct alpha_boot_block bb; 212 uint64_t startblock; 213 int retval; 214 char *bootstrapbuf; 215 size_t bootstrapsize; 216 ssize_t rv; 217 218 assert(params != NULL); 219 assert(params->fsfd != -1); 220 assert(params->filesystem != NULL); 221 assert(params->s1fd != -1); 222 assert(params->stage1 != NULL); 223 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 224 225 retval = 0; 226 bootstrapbuf = NULL; 227 228 /* 229 * Allocate a buffer, with space to round up the input file 230 * to the next block size boundary, and with space for the boot 231 * block. 232 */ 233 bootstrapsize = roundup(params->s1stat.st_size, 234 ALPHA_BOOT_BLOCK_BLOCKSIZE); 235 236 bootstrapbuf = malloc(bootstrapsize); 237 if (bootstrapbuf == NULL) { 238 warn("Allocating %lu bytes", (unsigned long) bootstrapsize); 239 goto done; 240 } 241 memset(bootstrapbuf, 0, bootstrapsize); 242 243 /* read the file into the buffer */ 244 rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0); 245 if (rv == -1) { 246 warn("Reading `%s'", params->stage1); 247 goto done; 248 } else if (rv != params->s1stat.st_size) { 249 warnx("Reading `%s': short read", params->stage1); 250 goto done; 251 } 252 253 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 254 if (rv == -1) { 255 warn("Reading `%s'", params->filesystem); 256 goto done; 257 } else if (rv != sizeof(bb)) { 258 warnx("Reading `%s': short read", params->filesystem); 259 goto done; 260 } 261 262 if (params->flags & IB_SUNSUM) 263 check_sparc(&bb, "Initial"); 264 265 /* fill in the updated bootstrap fields */ 266 if (params->flags & IB_APPEND) { 267 struct stat filesyssb; 268 269 if (fstat(params->fsfd, &filesyssb) == -1) { 270 warn("Examining `%s'", params->filesystem); 271 goto done; 272 } 273 if (!S_ISREG(filesyssb.st_mode)) { 274 warnx( 275 "`%s' must be a regular file to append a bootstrap", 276 params->filesystem); 277 goto done; 278 } 279 startblock = howmany(filesyssb.st_size, 280 ALPHA_BOOT_BLOCK_BLOCKSIZE); 281 } else if (params->flags & IB_STAGE1START) { 282 startblock = params->s1start; 283 } else { 284 startblock = ALPHA_BOOT_BLOCK_OFFSET / 285 ALPHA_BOOT_BLOCK_BLOCKSIZE + 1; 286 } 287 288 bb.bb_secsize = 289 htole64(howmany(params->s1stat.st_size, 290 ALPHA_BOOT_BLOCK_BLOCKSIZE)); 291 bb.bb_secstart = htole64(startblock); 292 bb.bb_flags = 0; 293 294 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 295 if (params->flags & IB_SUNSUM) 296 sun_bootstrap(params, &bb); 297 298 if (params->flags & IB_VERBOSE) { 299 printf("Bootstrap start sector: %llu\n", 300 (unsigned long long)startblock); 301 printf("Bootstrap sector count: %llu\n", 302 (unsigned long long)le64toh(bb.bb_secsize)); 303 printf("New boot block checksum: %#llx\n", 304 (unsigned long long)le64toh(bb.bb_cksum)); 305 printf("%sriting bootstrap\n", 306 (params->flags & IB_NOWRITE) ? "Not w" : "W"); 307 } 308 if (params->flags & IB_NOWRITE) { 309 retval = 1; 310 goto done; 311 } 312 rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, 313 startblock * ALPHA_BOOT_BLOCK_BLOCKSIZE); 314 if (rv == -1) { 315 warn("Writing `%s'", params->filesystem); 316 goto done; 317 } else if ((size_t)rv != bootstrapsize) { 318 warnx("Writing `%s': short write", params->filesystem); 319 goto done; 320 } 321 322 if (params->flags & IB_VERBOSE) 323 printf("Writing boot block\n"); 324 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 325 if (rv == -1) { 326 warn("Writing `%s'", params->filesystem); 327 goto done; 328 } else if (rv != sizeof(bb)) { 329 warnx("Writing `%s': short write", params->filesystem); 330 goto done; 331 } else { 332 retval = 1; 333 } 334 335 done: 336 if (bootstrapbuf) 337 free(bootstrapbuf); 338 return (retval); 339 } 340 341 342 /* 343 * The Sun and alpha checksums overlay, and the Sun magic number also 344 * overlays the alpha checksum. If you think you are smart: stop here 345 * and do exercise one: figure out how to salt unimportant uint16_t 346 * words in mid-sector so that the alpha and sparc checksums match, 347 * and so the Sun magic number is embedded in the alpha checksum. 348 * 349 * The last uint64_t in the sector is the alpha arithmetic checksum. 350 * The last uint16_t in the sector is the sun xor checksum. 351 * The penultimate uint16_t in the sector is the sun magic number. 352 * 353 * A: 511 510 509 508 507 506 505 504 354 * S: 510 511 508 509 506 507 504 505 355 * 63 : : : 32:31 : : : 0 356 * | : : : \:| : : : | 357 * 7654321076543210765432107654321076543210765432107654321076543210 358 * |-- sparc --||-- sparc --| 359 * |-- checksum --||-- magic --| 360 * |----------------------- alpha checksum -----------------------| 361 * 1011111011011010 362 * b e d a 363 */ 364 365 static void 366 resum(ib_params *params, struct alpha_boot_block * const bb, uint16_t *bb16) 367 { 368 static uint64_t lastsum; 369 370 if (bb16 != NULL) 371 memcpy(bb, bb16, sizeof(*bb)); 372 ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 373 if (bb16 != NULL) 374 memcpy(bb16, bb, sizeof(*bb)); 375 if ((params->flags & IB_VERBOSE) && lastsum != bb->bb_cksum) 376 printf("alpha checksum now %016llx\n", 377 (unsigned long long)le64toh(bb->bb_cksum)); 378 lastsum = bb->bb_cksum; 379 } 380 381 static void 382 sun_bootstrap(ib_params *params, struct alpha_boot_block * const bb) 383 { 384 # define BB_ADJUST_OFFSET 64 385 static char our_int16s[] = "\2\3\6\7\12"; 386 uint16_t i, j, chkdelta, sunsum, bb16[256]; 387 388 /* 389 * Theory: the alpha checksum is adjusted so bits 47:32 add up 390 * to the Sun magic number. Then, another adjustment is computed 391 * so bits 63:48 add up to the Sun checksum, and applied in pieces 392 * so it changes the alpha checksum but not the Sun value. 393 * 394 * Note: using memcpy(3) instead of a union as a strict c89/c9x 395 * conformance experiment and to avoid a public interface delta. 396 */ 397 assert(sizeof(bb16) == sizeof(*bb)); 398 memcpy(bb16, bb, sizeof(bb16)); 399 for (i = 0; our_int16s[i]; ++i) { 400 j = BB_ADJUST_OFFSET + our_int16s[i]; 401 if (bb16[j]) { 402 warnx("Non-zero bits %04x in bytes %d..%d", 403 bb16[j], j * 2, j * 2 + 1); 404 bb16[j] = 0; 405 resum(params, bb, bb16); 406 } 407 } 408 /* 409 * Make alpha checksum <47:32> come out to the sun magic. 410 */ 411 bb16[BB_ADJUST_OFFSET + 2] = htobe16(SUN_DKMAGIC) - bb16[254]; 412 resum(params, bb, bb16); 413 sunsum = compute_sunsum(bb16); /* might be the final value */ 414 if (params->flags & IB_VERBOSE) 415 printf("target sun checksum is %04x\n", sunsum); 416 /* 417 * Arrange to have alpha 63:48 add up to the sparc checksum. 418 */ 419 chkdelta = sunsum - bb16[255]; 420 bb16[BB_ADJUST_OFFSET + 3] = chkdelta >> 1; 421 bb16[BB_ADJUST_OFFSET + 7] = chkdelta >> 1; 422 /* 423 * By placing half the correction in two different uint64_t words at 424 * positions 63:48, the sparc sum will not change but the alpha sum 425 * will have the full correction, but only if the target adjustment 426 * was even. If it was odd, reverse propagate the carry one place. 427 */ 428 if (chkdelta & 1) { 429 if (params->flags & IB_VERBOSE) 430 printf("target adjustment %04x was odd, correcting\n", 431 chkdelta); 432 assert(bb16[BB_ADJUST_OFFSET + 6] == 0); 433 assert(bb16[BB_ADJUST_OFFSET + 012] == 0); 434 bb16[BB_ADJUST_OFFSET + 6] += 0x8000; 435 bb16[BB_ADJUST_OFFSET + 012] += 0x8000; 436 } 437 resum(params, bb, bb16); 438 if (params->flags & IB_VERBOSE) 439 printf("final harmonized checksum: %016llx\n", 440 (unsigned long long)le64toh(bb->bb_cksum)); 441 check_sparc(bb, "Final"); 442 } 443 444 static void 445 check_sparc(const struct alpha_boot_block * const bb, const char *when) 446 { 447 uint16_t bb16[256]; 448 #define wmsg "%s sparc %s 0x%04x invalid, expected 0x%04x" 449 450 memcpy(bb16, bb, sizeof(bb16)); 451 if (compute_sunsum(bb16) != bb16[255]) 452 warnx(wmsg, when, "checksum", bb16[255], compute_sunsum(bb16)); 453 if (bb16[254] != htobe16(SUN_DKMAGIC)) 454 warnx(wmsg, when, "magic number", bb16[254], 455 htobe16(SUN_DKMAGIC)); 456 } 457