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