1 /* $NetBSD: alpha.c,v 1.19 2009/04/05 11:55:39 lukem Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn of Wasabi Systems.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 1999 Ross Harvey. All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
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
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.
63 * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved.
65 * Redistribution and use in source and binary forms, with or without
66 * modification, are permitted provided that the following conditions
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
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.
92 #if HAVE_NBTOOL_CONFIG_H
93 #include "nbtool_config.h"
96 #include <sys/cdefs.h>
98 __RCSID("$NetBSD: alpha.c,v 1.19 2009/04/05 11:55:39 lukem Exp $");
101 #include <sys/param.h>
111 #include "installboot.h"
113 #define SUN_DKMAGIC 55998 /* XXX: from <dev/sun/disklabel.h> */
115 static void resum(ib_params
*, struct alpha_boot_block
* const bb
,
117 static void sun_bootstrap(ib_params
*, struct alpha_boot_block
* const);
118 static void check_sparc(const struct alpha_boot_block
* const,
121 static int alpha_clearboot(ib_params
*);
122 static int alpha_setboot(ib_params
*);
124 struct ib_mach ib_mach_alpha
=
125 { "alpha", alpha_setboot
, alpha_clearboot
, no_editboot
,
126 IB_STAGE1START
| IB_ALPHASUM
| IB_APPEND
| IB_SUNSUM
};
129 alpha_clearboot(ib_params
*params
)
131 struct alpha_boot_block bb
;
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
);
140 if (params
->flags
& (IB_STAGE1START
| IB_APPEND
)) {
141 warnx("Can't use `-b bno' or `-o append' with `-c'");
145 rv
= pread(params
->fsfd
, &bb
, sizeof(bb
), ALPHA_BOOT_BLOCK_OFFSET
);
147 warn("Reading `%s'", params
->filesystem
);
149 } else if (rv
!= sizeof(bb
)) {
150 warnx("Reading `%s': short read", params
->filesystem
);
153 ALPHA_BOOT_BLOCK_CKSUM(&bb
, &cksum
);
154 if (cksum
!= bb
.bb_cksum
) { // XXX check bb_cksum endian?
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");
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
));
172 bb
.bb_secstart
= bb
.bb_secsize
= bb
.bb_flags
= 0;
174 ALPHA_BOOT_BLOCK_CKSUM(&bb
, &bb
.bb_cksum
);
175 if (params
->flags
& IB_SUNSUM
)
176 sun_bootstrap(params
, &bb
);
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
));
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
)
191 rv
= pwrite(params
->fsfd
, &bb
, sizeof(bb
), ALPHA_BOOT_BLOCK_OFFSET
);
193 warn("Writing `%s'", params
->filesystem
);
195 } else if (rv
!= sizeof(bb
)) {
196 warnx("Writing `%s': short write", params
->filesystem
);
204 alpha_setboot(ib_params
*params
)
206 struct alpha_boot_block bb
;
210 size_t bootstrapsize
;
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
);
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
228 bootstrapsize
= roundup(params
->s1stat
.st_size
,
229 ALPHA_BOOT_BLOCK_BLOCKSIZE
);
231 bootstrapbuf
= malloc(bootstrapsize
);
232 if (bootstrapbuf
== NULL
) {
233 warn("Allocating %lu bytes", (unsigned long) bootstrapsize
);
236 memset(bootstrapbuf
, 0, bootstrapsize
);
238 /* read the file into the buffer */
239 rv
= pread(params
->s1fd
, bootstrapbuf
, params
->s1stat
.st_size
, 0);
241 warn("Reading `%s'", params
->stage1
);
243 } else if (rv
!= params
->s1stat
.st_size
) {
244 warnx("Reading `%s': short read", params
->stage1
);
248 rv
= pread(params
->fsfd
, &bb
, sizeof(bb
), ALPHA_BOOT_BLOCK_OFFSET
);
250 warn("Reading `%s'", params
->filesystem
);
252 } else if (rv
!= sizeof(bb
)) {
253 warnx("Reading `%s': short read", params
->filesystem
);
257 if (params
->flags
& IB_SUNSUM
)
258 check_sparc(&bb
, "Initial");
260 /* fill in the updated bootstrap fields */
261 if (params
->flags
& IB_APPEND
) {
262 struct stat filesyssb
;
264 if (fstat(params
->fsfd
, &filesyssb
) == -1) {
265 warn("Examining `%s'", params
->filesystem
);
268 if (!S_ISREG(filesyssb
.st_mode
)) {
270 "`%s' must be a regular file to append a bootstrap",
274 startblock
= howmany(filesyssb
.st_size
,
275 ALPHA_BOOT_BLOCK_BLOCKSIZE
);
276 } else if (params
->flags
& IB_STAGE1START
) {
277 startblock
= params
->s1start
;
279 startblock
= ALPHA_BOOT_BLOCK_OFFSET
/
280 ALPHA_BOOT_BLOCK_BLOCKSIZE
+ 1;
284 htole64(howmany(params
->s1stat
.st_size
,
285 ALPHA_BOOT_BLOCK_BLOCKSIZE
));
286 bb
.bb_secstart
= htole64(startblock
);
289 ALPHA_BOOT_BLOCK_CKSUM(&bb
, &bb
.bb_cksum
);
290 if (params
->flags
& IB_SUNSUM
)
291 sun_bootstrap(params
, &bb
);
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");
303 if (params
->flags
& IB_NOWRITE
) {
307 rv
= pwrite(params
->fsfd
, bootstrapbuf
, bootstrapsize
,
308 startblock
* ALPHA_BOOT_BLOCK_BLOCKSIZE
);
310 warn("Writing `%s'", params
->filesystem
);
312 } else if ((size_t)rv
!= bootstrapsize
) {
313 warnx("Writing `%s': short write", params
->filesystem
);
317 if (params
->flags
& IB_VERBOSE
)
318 printf("Writing boot block\n");
319 rv
= pwrite(params
->fsfd
, &bb
, sizeof(bb
), ALPHA_BOOT_BLOCK_OFFSET
);
321 warn("Writing `%s'", params
->filesystem
);
323 } else if (rv
!= sizeof(bb
)) {
324 warnx("Writing `%s': short write", params
->filesystem
);
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.
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.
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 -----------------------|
361 resum(ib_params
*params
, struct alpha_boot_block
* const bb
, uint16_t *bb16
)
363 static uint64_t lastsum
;
366 memcpy(bb
, bb16
, sizeof(*bb
));
367 ALPHA_BOOT_BLOCK_CKSUM(bb
, &bb
->bb_cksum
);
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
;
377 sun_bootstrap(ib_params
*params
, struct alpha_boot_block
* const bb
)
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];
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.
389 * Note: using memcpy(3) instead of a union as a strict c89/c9x
390 * conformance experiment and to avoid a public interface delta.
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
];
397 warnx("Non-zero bits %04x in bytes %d..%d",
398 bb16
[j
], j
* 2, j
* 2 + 1);
400 resum(params
, bb
, bb16
);
404 * Make alpha checksum <47:32> come out to the sun magic.
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
);
412 * Arrange to have alpha 63:48 add up to the sparc checksum.
414 chkdelta
= sunsum
- bb16
[255];
415 bb16
[BB_ADJUST_OFFSET
+ 3] = chkdelta
>> 1;
416 bb16
[BB_ADJUST_OFFSET
+ 7] = chkdelta
>> 1;
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.
424 if (params
->flags
& IB_VERBOSE
)
425 printf("target adjustment %04x was odd, correcting\n",
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;
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");
440 check_sparc(const struct alpha_boot_block
* const bb
, const char *when
)
443 const char * const wmsg
=
444 "%s sparc %s 0x%04x invalid, expected 0x%04x";
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
));