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