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