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