1 /* $NetBSD: alpha.c,v 1.15 2003/10/27 00:12:44 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 #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.15 2003/10/27 00:12:44 lukem 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 129 int 130 alpha_clearboot(ib_params *params) 131 { 132 struct alpha_boot_block bb; 133 uint64_t cksum; 134 ssize_t rv; 135 136 assert(params != NULL); 137 assert(params->fsfd != -1); 138 assert(params->filesystem != NULL); 139 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 140 141 if (params->flags & (IB_STAGE1START | IB_APPEND)) { 142 warnx("Can't use `-b bno' or `-o append' with `-c'"); 143 return (0); 144 } 145 146 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 147 if (rv == -1) { 148 warn("Reading `%s'", params->filesystem); 149 return (0); 150 } else if (rv != sizeof(bb)) { 151 warnx("Reading `%s': short read", params->filesystem); 152 return (0); 153 } 154 ALPHA_BOOT_BLOCK_CKSUM(&bb, &cksum); 155 if (cksum != bb.bb_cksum) { // XXX check bb_cksum endian? 156 warnx( 157 "Old boot block checksum invalid (was %#llx, calculated %#llx)", 158 (unsigned long long)bb.bb_cksum, 159 (unsigned long long)cksum); 160 warnx("Boot block invalid"); 161 return (0); 162 } 163 164 if (params->flags & IB_VERBOSE) { 165 printf("Old bootstrap start sector: %llu\n", 166 (unsigned long long)le64toh(bb.bb_secstart)); 167 printf("Old bootstrap size: %llu\n", 168 (unsigned long long)le64toh(bb.bb_secsize)); 169 printf("Old bootstrap checksum: %#llx\n", 170 (unsigned long long)bb.bb_cksum); 171 } 172 173 bb.bb_secstart = bb.bb_secsize = bb.bb_flags = 0; 174 175 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 176 if (params->flags & IB_SUNSUM) 177 sun_bootstrap(params, &bb); 178 179 printf("New bootstrap start sector: %llu\n", 180 (unsigned long long)le64toh(bb.bb_secstart)); 181 printf("New bootstrap size: %llu\n", 182 (unsigned long long)le64toh(bb.bb_secsize)); 183 printf("New bootstrap checksum: %#llx\n", 184 (unsigned long long)bb.bb_cksum); 185 186 if (params->flags & IB_VERBOSE) 187 printf("%slearing boot block\n", 188 (params->flags & IB_NOWRITE) ? "Not c" : "C"); 189 if (params->flags & IB_NOWRITE) 190 return (1); 191 192 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 193 if (rv == -1) { 194 warn("Writing `%s'", params->filesystem); 195 return (0); 196 } else if (rv != sizeof(bb)) { 197 warnx("Writing `%s': short write", params->filesystem); 198 return (0); 199 } 200 201 return (1); 202 } 203 204 int 205 alpha_setboot(ib_params *params) 206 { 207 struct alpha_boot_block bb; 208 uint64_t startblock; 209 int retval; 210 char *bootstrapbuf; 211 size_t bootstrapsize; 212 ssize_t rv; 213 214 assert(params != NULL); 215 assert(params->fsfd != -1); 216 assert(params->filesystem != NULL); 217 assert(params->s1fd != -1); 218 assert(params->stage1 != NULL); 219 assert(sizeof(struct alpha_boot_block) == ALPHA_BOOT_BLOCK_BLOCKSIZE); 220 221 retval = 0; 222 bootstrapbuf = NULL; 223 224 /* 225 * Allocate a buffer, with space to round up the input file 226 * to the next block size boundary, and with space for the boot 227 * block. 228 */ 229 bootstrapsize = roundup(params->s1stat.st_size, 230 ALPHA_BOOT_BLOCK_BLOCKSIZE); 231 232 bootstrapbuf = malloc(bootstrapsize); 233 if (bootstrapbuf == NULL) { 234 warn("Allocating %lu bytes", (unsigned long) bootstrapsize); 235 goto done; 236 } 237 memset(bootstrapbuf, 0, bootstrapsize); 238 239 /* read the file into the buffer */ 240 rv = pread(params->s1fd, bootstrapbuf, params->s1stat.st_size, 0); 241 if (rv == -1) { 242 warn("Reading `%s'", params->stage1); 243 return (0); 244 } else if (rv != params->s1stat.st_size) { 245 warnx("Reading `%s': short read", params->stage1); 246 return (0); 247 } 248 249 rv = pread(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 250 if (rv == -1) { 251 warn("Reading `%s'", params->filesystem); 252 goto done; 253 } else if (rv != sizeof(bb)) { 254 warnx("Reading `%s': short read", params->filesystem); 255 goto done; 256 } 257 258 if (params->flags & IB_SUNSUM) 259 check_sparc(&bb, "Initial"); 260 261 /* fill in the updated bootstrap fields */ 262 if (params->flags & IB_APPEND) { 263 struct stat filesyssb; 264 265 if (fstat(params->fsfd, &filesyssb) == -1) { 266 warn("Examining `%s'", params->filesystem); 267 goto done; 268 } 269 if (!S_ISREG(filesyssb.st_mode)) { 270 warnx( 271 "`%s' must be a regular file to append a bootstrap", 272 params->filesystem); 273 goto done; 274 } 275 startblock = howmany(filesyssb.st_size, 276 ALPHA_BOOT_BLOCK_BLOCKSIZE); 277 } else if (params->flags & IB_STAGE1START) { 278 startblock = params->s1start; 279 } else { 280 startblock = ALPHA_BOOT_BLOCK_OFFSET / 281 ALPHA_BOOT_BLOCK_BLOCKSIZE + 1; 282 } 283 284 bb.bb_secsize = 285 htole64(howmany(params->s1stat.st_size, 286 ALPHA_BOOT_BLOCK_BLOCKSIZE)); 287 bb.bb_secstart = htole64(startblock); 288 bb.bb_flags = 0; 289 290 ALPHA_BOOT_BLOCK_CKSUM(&bb, &bb.bb_cksum); 291 if (params->flags & IB_SUNSUM) 292 sun_bootstrap(params, &bb); 293 294 if (params->flags & IB_VERBOSE) { 295 printf("Bootstrap start sector: %llu\n", 296 (unsigned long long)startblock); 297 printf("Bootstrap sector count: %llu\n", 298 (unsigned long long)le64toh(bb.bb_secsize)); 299 printf("New boot block checksum: %#llx\n", 300 (unsigned long long)bb.bb_cksum); 301 printf("%sriting bootstrap\n", 302 (params->flags & IB_NOWRITE) ? "Not w" : "W"); 303 } 304 if (params->flags & IB_NOWRITE) { 305 retval = 1; 306 goto done; 307 } 308 rv = pwrite(params->fsfd, bootstrapbuf, bootstrapsize, 309 startblock * ALPHA_BOOT_BLOCK_BLOCKSIZE); 310 if (rv == -1) { 311 warn("Writing `%s'", params->filesystem); 312 goto done; 313 } else if (rv != bootstrapsize) { 314 warnx("Writing `%s': short write", params->filesystem); 315 goto done; 316 } 317 318 if (params->flags & IB_VERBOSE) 319 printf("Writing boot block\n"); 320 rv = pwrite(params->fsfd, &bb, sizeof(bb), ALPHA_BOOT_BLOCK_OFFSET); 321 if (rv == -1) { 322 warn("Writing `%s'", params->filesystem); 323 goto done; 324 } else if (rv != sizeof(bb)) { 325 warnx("Writing `%s': short write", params->filesystem); 326 goto done; 327 } else { 328 retval = 1; 329 } 330 331 done: 332 if (bootstrapbuf) 333 free(bootstrapbuf); 334 return (retval); 335 } 336 337 338 /* 339 * The Sun and alpha checksums overlay, and the Sun magic number also 340 * overlays the alpha checksum. If you think you are smart: stop here 341 * and do exercise one: figure out how to salt unimportant uint16_t 342 * words in mid-sector so that the alpha and sparc checksums match, 343 * and so the Sun magic number is embedded in the alpha checksum. 344 * 345 * The last uint64_t in the sector is the alpha arithmetic checksum. 346 * The last uint16_t in the sector is the sun xor checksum. 347 * The penultimate uint16_t in the sector is the sun magic number. 348 * 349 * A: 511 510 509 508 507 506 505 504 350 * S: 510 511 508 509 506 507 504 505 351 * 63 : : : 32:31 : : : 0 352 * | : : : \:| : : : | 353 * 7654321076543210765432107654321076543210765432107654321076543210 354 * |-- sparc --||-- sparc --| 355 * |-- checksum --||-- magic --| 356 * |----------------------- alpha checksum -----------------------| 357 * 1011111011011010 358 * b e d a 359 */ 360 361 static void 362 resum(ib_params *params, struct alpha_boot_block * const bb, uint16_t *bb16) 363 { 364 static uint64_t lastsum; 365 366 if (bb16 != NULL) 367 memcpy(bb, bb16, sizeof(*bb)); 368 ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum); 369 if (bb16 != NULL) 370 memcpy(bb16, bb, sizeof(*bb)); 371 if ((params->flags & IB_VERBOSE) && lastsum != bb->bb_cksum) 372 printf("alpha checksum now %016llx\n", (long long)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 (long long)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 const char * const wmsg = 444 "%s sparc %s 0x%04x invalid, expected 0x%04x"; 445 446 memcpy(bb16, bb, sizeof(bb16)); 447 if (compute_sunsum(bb16) != bb16[255]) 448 warnx(wmsg, when, "checksum", bb16[255], compute_sunsum(bb16)); 449 if (bb16[254] != htobe16(SUN_DKMAGIC)) 450 warnx(wmsg, when, "magic number", bb16[254], 451 htobe16(SUN_DKMAGIC)); 452 } 453