1 /* $NetBSD: alpha.c,v 1.3 2002/04/04 14:00:55 mrg 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.3 2002/04/04 14:00:55 mrg Exp $"); 102 #endif /* !__lint */ 103 104 #include <sys/param.h> 105 #include <sys/stat.h> 106 107 #include <assert.h> 108 #include <err.h> 109 #include <stddef.h> 110 #include <stdio.h> 111 #include <stdlib.h> 112 #include <string.h> 113 #include <unistd.h> 114 115 #include <dev/dec/dec_boot.h> 116 117 #include "installboot.h" 118 119 #define SUN_DKMAGIC 55998 /* XXX: from <dev/sun/disklabel.h> */ 120 121 int alpha_parseopt(ib_params *, const char *); 122 int alpha_setboot(ib_params *); 123 int alpha_clearboot(ib_params *); 124 static void resum(ib_params *, struct alpha_boot_block * const bb, 125 u_int16_t *bb16); 126 static void sun_bootstrap(ib_params *, struct alpha_boot_block * const); 127 static void check_sparc(const struct alpha_boot_block * const, 128 const char *); 129 130 131 int 132 alpha_parseopt(ib_params *params, const char *option) 133 { 134 135 if (parseoptionflag(params, option, 136 IB_ALPHASUM | IB_APPEND | IB_SUNSUM)) 137 return (1); 138 139 warnx("Unknown -o option `%s'", option); 140 return (0); 141 } 142 143 int 144 alpha_clearboot(ib_params *params) 145 { 146 struct alpha_boot_block bb; 147 u_int64_t cksum; 148 ssize_t rv; 149 150 assert(params != NULL); 151 assert(params->fsfd != -1); 152 assert(params->filesystem != NULL); 153 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 154 155 if (params->flags & (IB_STARTBLOCK | IB_APPEND)) { 156 warnx("Can't use `-b bno' or `-o append' with `-c'"); 157 return (0); 158 } 159 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 160 if (rv == -1) { 161 warn("Reading `%s'", params->filesystem); 162 return (0); 163 } else if (rv != sizeof(bb)) { 164 warnx("Reading `%s': short read", params->filesystem); 165 return (0); 166 } 167 ALPHA_BOOT_BLOCK_CKSUM(&bb, &cksum); 168 if (cksum != bb.bb_cksum) { // XXX check bb_cksum endian? 169 warnx( 170 "Old boot block checksum invalid (was %#llx, calculated %#llx)", 171 (unsigned long long)bb.bb_cksum, 172 (unsigned long long)cksum); 173 warnx("Boot block invalid\n"); 174 return (0); 175 } 176 177 if (params->flags & IB_VERBOSE) { 178 printf("Old boot block start sector: %#llx\n", 179 (unsigned long long)le64toh(bb.bb_secstart)); 180 printf("Old boot block size: %#llx\n", 181 (unsigned long long)le64toh(bb.bb_secsize)); 182 printf("Old boot block checksum: %#llx\n", 183 (unsigned long long)bb.bb_cksum); 184 } 185 186 bb.bb_secstart = bb.bb_secsize = bb.bb_flags = 0; 187 188 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 189 if (params->flags & IB_SUNSUM) 190 sun_bootstrap(params, &bb); 191 192 printf("New boot block start sector: %#llx\n", 193 (unsigned long long)le64toh(bb.bb_secstart)); 194 printf("New boot block size: %#llx\n", 195 (unsigned long long)le64toh(bb.bb_secsize)); 196 printf("New boot block checksum: %#llx\n", 197 (unsigned long long)bb.bb_cksum); 198 199 if (params->flags & IB_VERBOSE) 200 printf("%slearing boot block\n", 201 (params->flags & IB_NOWRITE) ? "Not c" : "C"); 202 if (params->flags & IB_NOWRITE) 203 return (1); 204 205 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 206 if (rv == -1) { 207 warn("Writing `%s'", params->filesystem); 208 return (0); 209 } else if (rv != sizeof(bb)) { 210 warnx("Writing `%s': short write", params->filesystem); 211 return (0); 212 } 213 214 return (1); 215 } 216 217 int 218 alpha_setboot(ib_params *params) 219 { 220 struct stat bootstrapsb; 221 struct alpha_boot_block bb; 222 u_int64_t startblock; 223 int retval; 224 char *bootstrapbuf; 225 size_t bootstrapsize; 226 ssize_t rv; 227 228 assert(params != NULL); 229 assert(params->fsfd != -1); 230 assert(params->filesystem != NULL); 231 assert(params->bbfd != -1); 232 assert(params->bootblock != NULL); 233 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 234 235 retval = 0; 236 bootstrapbuf = NULL; 237 238 if ((params->flags & IB_STARTBLOCK) && 239 (params->flags & IB_APPEND)) { 240 warnx("Can't use `-b bno' with `-o append'"); 241 goto done; 242 } 243 244 if (fstat(params->bbfd, &bootstrapsb) == -1) { 245 warn("Examining `%s'", params->bootblock); 246 goto done; 247 } 248 if (!S_ISREG(bootstrapsb.st_mode)) { 249 warnx("`%s' must be a regular file", params->bootblock); 250 goto done; 251 } 252 /* 253 * Allocate a buffer, with space to round up the input file 254 * to the next block size boundary, and with space for the boot 255 * block. 256 */ 257 bootstrapsize = roundup(bootstrapsb.st_size, 258 ALPHA_BOOT_BLOCK_BLOCKSIZE); 259 260 bootstrapbuf = malloc(bootstrapsize); 261 if (bootstrapbuf == NULL) { 262 warn("Allocating %lu bytes", (unsigned long) bootstrapsize); 263 goto done; 264 } 265 memset(bootstrapbuf, 0, bootstrapsize); 266 267 /* read the file into the buffer */ 268 rv = pread(params->bbfd, bootstrapbuf, bootstrapsb.st_size, 0); 269 if (rv == -1) { 270 warn("Reading `%s'", params->bootblock); 271 return (0); 272 } else if (rv != sizeof(bb)) { 273 warnx("Reading `%s': short read", params->bootblock); 274 return (0); 275 } 276 277 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 278 if (rv == -1) { 279 warn("Reading `%s'", params->filesystem); 280 goto done; 281 } else if (rv != sizeof(bb)) { 282 warnx("Reading `%s': short read", params->filesystem); 283 goto done; 284 } 285 286 if (params->flags & IB_SUNSUM) 287 check_sparc(&bb, "Initial"); 288 289 /* fill in the updated boot block fields */ 290 if (params->flags & IB_APPEND) { 291 struct stat filesyssb; 292 293 if (fstat(params->fsfd, &filesyssb) == -1) { 294 warn("Examining `%s'", params->filesystem); 295 goto done; 296 } 297 if (!S_ISREG(filesyssb.st_mode)) { 298 warnx( 299 "`%s' must be a regular file to append a boot block", 300 params->filesystem); 301 goto done; 302 } 303 startblock = howmany(filesyssb.st_size, 304 ALPHA_BOOT_BLOCK_BLOCKSIZE); 305 } else if (params->flags & IB_STARTBLOCK) { 306 startblock = params->startblock; 307 } else { 308 startblock = ALPHA_BOOT_BLOCK_OFFSET / 309 ALPHA_BOOT_BLOCK_BLOCKSIZE + 1; 310 } 311 312 bb.bb_secsize = 313 htole64(howmany(bootstrapsb.st_size, ALPHA_BOOT_BLOCK_BLOCKSIZE)); 314 bb.bb_secstart = htole64(startblock); 315 bb.bb_flags = 0; 316 317 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 318 if (params->flags & IB_SUNSUM) 319 sun_bootstrap(params, &bb); 320 321 if (params->flags & IB_VERBOSE) { 322 printf("Bootstrap start sector: %#llx\n", 323 (unsigned long long)startblock); 324 printf("Bootstrap sector count: %#llx\n", 325 (unsigned long long)le64toh(bb.bb_secsize)); 326 printf("New boot block checksum: %#llx\n", 327 (unsigned long long)bb.bb_cksum); 328 printf("%sriting bootstrap\n", 329 (params->flags & IB_NOWRITE) ? "Not w" : "W"); 330 } 331 if (params->flags & IB_NOWRITE) { 332 retval = 1; 333 goto done; 334 } 335 rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, 336 startblock * ALPHA_BOOT_BLOCK_BLOCKSIZE); 337 if (rv == -1) { 338 warn("Writing `%s'", params->filesystem); 339 goto done; 340 } else if (rv != bootstrapsize) { 341 warnx("Writing `%s': short write", params->filesystem); 342 goto done; 343 } 344 345 if (params->flags & IB_VERBOSE) 346 printf("Writing boot block\n"); 347 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 348 if (rv == -1) { 349 warn("Writing `%s'", params->filesystem); 350 goto done; 351 } else if (rv != sizeof(bb)) { 352 warnx("Writing `%s': short write", params->filesystem); 353 goto done; 354 } else { 355 retval = 1; 356 } 357 358 done: 359 if (bootstrapbuf) 360 free(bootstrapbuf); 361 return (retval); 362 } 363 364 365 /* 366 * The Sun and alpha checksums overlay, and the Sun magic number also 367 * overlays the alpha checksum. If you think you are smart: stop here 368 * and do exercise one: figure out how to salt unimportant u_int16_t 369 * words in mid-sector so that the alpha and sparc checksums match, 370 * and so the Sun magic number is embedded in the alpha checksum. 371 * 372 * The last u_int64_t in the sector is the alpha arithmetic checksum. 373 * The last u_int16_t in the sector is the sun xor checksum. 374 * The penultimate u_int16_t in the sector is the sun magic number. 375 * 376 * A: 511 510 509 508 507 506 505 504 377 * S: 510 511 508 509 506 507 504 505 378 * 63 : : : 32:31 : : : 0 379 * | : : : \:| : : : | 380 * 7654321076543210765432107654321076543210765432107654321076543210 381 * |-- sparc --||-- sparc --| 382 * |-- checksum --||-- magic --| 383 * |----------------------- alpha checksum -----------------------| 384 * 1011111011011010 385 * b e d a 386 */ 387 388 static void 389 resum(ib_params *params, struct alpha_boot_block * const bb, u_int16_t *bb16) 390 { 391 static u_int64_t lastsum; 392 393 if (bb16 != NULL) 394 memcpy(bb, bb16, sizeof(*bb)); 395 ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 396 if (bb16 != NULL) 397 memcpy(bb16, bb, sizeof(*bb)); 398 if ((params->flags & IB_VERBOSE) && lastsum != bb->bb_cksum) 399 printf("alpha checksum now %016llx\n", (long long)bb->bb_cksum); 400 lastsum = bb->bb_cksum; 401 } 402 403 static void 404 sun_bootstrap(ib_params *params, struct alpha_boot_block * const bb) 405 { 406 # define BB_ADJUST_OFFSET 64 407 static char our_int16s[] = "\2\3\6\7\12"; 408 u_int16_t i, j, chkdelta, sunsum, bb16[256]; 409 410 /* 411 * Theory: the alpha checksum is adjusted so bits 47:32 add up 412 * to the Sun magic number. Then, another adjustment is computed 413 * so bits 63:48 add up to the Sun checksum, and applied in pieces 414 * so it changes the alpha checksum but not the Sun value. 415 * 416 * Note: using memcpy(3) instead of a union as a strict c89/c9x 417 * conformance experiment and to avoid a public interface delta. 418 */ 419 assert(sizeof(bb16) == sizeof(*bb)); 420 memcpy(bb16, bb, sizeof(bb16)); 421 for (i = 0; our_int16s[i]; ++i) { 422 j = BB_ADJUST_OFFSET + our_int16s[i]; 423 if (bb16[j]) { 424 warnx("Non-zero bits %04x in bytes %d..%d", 425 bb16[j], j * 2, j * 2 + 1); 426 bb16[j] = 0; 427 resum(params, bb, bb16); 428 } 429 } 430 /* 431 * Make alpha checksum <47:32> come out to the sun magic. 432 */ 433 bb16[BB_ADJUST_OFFSET + 2] = htons(SUN_DKMAGIC) - bb16[254]; 434 resum(params, bb, bb16); 435 sunsum = compute_sunsum(bb16); /* might be the final value */ 436 if (params->flags & IB_VERBOSE) 437 printf("target sun checksum is %04x\n", sunsum); 438 /* 439 * Arrange to have alpha 63:48 add up to the sparc checksum. 440 */ 441 chkdelta = sunsum - bb16[255]; 442 bb16[BB_ADJUST_OFFSET + 3] = chkdelta >> 1; 443 bb16[BB_ADJUST_OFFSET + 7] = chkdelta >> 1; 444 /* 445 * By placing half the correction in two different u_int64_t words at 446 * positions 63:48, the sparc sum will not change but the alpha sum 447 * will have the full correction, but only if the target adjustment 448 * was even. If it was odd, reverse propagate the carry one place. 449 */ 450 if (chkdelta & 1) { 451 if (params->flags & IB_VERBOSE) 452 printf("target adjustment %04x was odd, correcting\n", 453 chkdelta); 454 assert(bb16[BB_ADJUST_OFFSET + 6] == 0); 455 assert(bb16[BB_ADJUST_OFFSET + 012] == 0); 456 bb16[BB_ADJUST_OFFSET + 6] += 0x8000; 457 bb16[BB_ADJUST_OFFSET + 012] += 0x8000; 458 } 459 resum(params, bb, bb16); 460 if (params->flags & IB_VERBOSE) 461 printf("final harmonized checksum: %016llx\n", 462 (long long)bb->bb_cksum); 463 check_sparc(bb, "Final"); 464 } 465 466 static void 467 check_sparc(const struct alpha_boot_block * const bb, const char *when) 468 { 469 u_int16_t bb16[256]; 470 const char * const wmsg = 471 "%s sparc %s 0x%04x invalid, expected 0x%04x"; 472 473 memcpy(bb16, bb, sizeof(bb16)); 474 if (compute_sunsum(bb16) != bb16[255]) 475 warnx(wmsg, when, "checksum", bb16[255], compute_sunsum(bb16)); 476 if (bb16[254] != htons(SUN_DKMAGIC)) 477 warnx(wmsg, when, "magic number", bb16[254], 478 htons(SUN_DKMAGIC)); 479 } 480