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