1 /* $NetBSD: installboot.c,v 1.23 2009/03/14 14:45:57 dsl Exp $ */
4 * Copyright (c) 1995 Waldi Ravens
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Waldi Ravens.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <sys/ioctl.h>
51 #include <sys/disklabel.h>
52 #include <machine/ahdilabel.h>
54 #include "installboot.h"
56 static void usage(void);
57 static void oscheck(void);
58 static u_int
abcksum(void *);
59 static void setNVpref(void);
60 static void setIDEpar(u_int8_t
*, size_t);
61 static void mkahdiboot(struct ahdi_root
*, char *,
63 static void mkbootblock(struct bootblock
*, char *,
64 char *, struct disklabel
*, u_int
);
65 static void install_fd(char *, struct disklabel
*);
66 static void install_sd(char *, struct disklabel
*);
67 static void install_wd(char *, struct disklabel
*);
69 static struct bootblock bootarea
;
70 static struct ahdi_root ahdiboot
;
71 static const char mdecpath
[] = PATH_MDEC
;
72 static const char stdpath
[] = PATH_STD
;
73 static const char milanpath
[] = PATH_MILAN
;
74 static int nowrite
= 0;
75 static int verbose
= 0;
76 static int trackpercyl
= 0;
77 static int secpertrack
= 0;
84 "usage: installboot [options] device\n"
85 "where options are:\n"
86 "\t-N do not actually write anything on the disk\n"
87 "\t-m use Milan boot blocks\n"
88 "\t-t number of tracks per cylinder (IDE disk)\n"
89 "\t-u number of sectors per track (IDE disk)\n"
90 "\t-v verbose mode\n");
95 main (int argc
, char *argv
[])
102 /* check OS bootversion */
106 while ((c
= getopt(argc
, argv
, "Nmt:u:v")) != -1) {
115 trackpercyl
= atoi(optarg
);
118 secpertrack
= atoi(optarg
);
133 dn
= alloca(sizeof(_PATH_DEV
) + strlen(argv
[0]) + 8);
134 if (!strchr(argv
[0], '/')) {
135 sprintf(dn
, "%sr%s%c", _PATH_DEV
, argv
[0], RAW_PART
+ 'a');
136 fd
= open(dn
, O_RDONLY
);
137 if (fd
< 0 && errno
== ENOENT
) {
138 sprintf(dn
, "%sr%s", _PATH_DEV
, argv
[0]);
139 fd
= open(dn
, O_RDONLY
);
142 sprintf(dn
, "%s", argv
[0]);
143 fd
= open(dn
, O_RDONLY
);
146 err(EXIT_FAILURE
, "%s", dn
);
147 if (ioctl(fd
, DIOCGDINFO
, &dl
))
148 err(EXIT_FAILURE
, "%s: DIOCGDINFO", dn
);
150 err(EXIT_FAILURE
, "%s", dn
);
152 /* Eg: in /dev/fd0c, set devchr to point to the 'f' */
153 devchr
= strrchr(dn
, '/') + 1;
171 "%s: '%c': Device type not supported.",
175 return(EXIT_SUCCESS
);
181 struct nlist kbv
[] = { { "_bootversion" },
184 char errbuf
[_POSIX2_LINE_MAX
];
188 if (stat(_PATH_UNIX
, &sb
) < 0) {
189 warnx("Cannot stat %s, no bootversion check done", _PATH_UNIX
);
193 kd_kern
= kvm_openfiles(NULL
, NULL
, NULL
, O_RDONLY
, errbuf
);
195 errx(EXIT_FAILURE
, "kvm_openfiles: %s", errbuf
);
196 if (kvm_nlist(kd_kern
, kbv
) == -1)
197 errx(EXIT_FAILURE
, "kvm_nlist: %s", kvm_geterr(kd_kern
));
198 if (kbv
[0].n_value
== 0)
199 errx(EXIT_FAILURE
, "%s not in namelist", kbv
[0].n_name
);
200 if (kvm_read(kd_kern
, kbv
[0].n_value
, (char *)&kvers
,
201 sizeof(kvers
)) == -1)
202 errx(EXIT_FAILURE
, "kvm_read: %s", kvm_geterr(kd_kern
));
204 if (kvers
!= BOOTVERSION
)
205 errx(EXIT_FAILURE
, "Kern bootversion: %d, expected: %d",
210 install_fd (char *devnm
, struct disklabel
*label
)
212 const char *machpath
;
213 char *xxboot
, *bootxx
;
214 struct partition
*rootpart
;
216 if (label
->d_secsize
!= 512)
218 "%s: %u: Block size not supported.", devnm
,
220 if (label
->d_ntracks
!= 2)
222 "%s: Single sided floppy not supported.", devnm
);
225 machpath
= milanpath
;
228 xxboot
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
229 sprintf(xxboot
, "%s%sfdboot", mdecpath
, machpath
);
230 bootxx
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
231 sprintf(bootxx
, "%s%sbootxx", mdecpath
, machpath
);
233 /* first used partition (a, b or c) */ /* XXX */
234 for (rootpart
= label
->d_partitions
; ; ++rootpart
) {
235 if (rootpart
->p_size
)
238 if (rootpart
!= label
->d_partitions
) { /* XXX */
239 *(label
->d_partitions
) = *rootpart
;
240 memset(rootpart
, 0, sizeof(*rootpart
));
242 label
->d_partitions
->p_fstype
= FS_BSDFFS
; /* XXX */
243 label
->d_npartitions
= 1;
244 label
->d_checksum
= 0;
245 label
->d_checksum
= dkcksum(label
);
247 trackpercyl
= secpertrack
= 0;
248 mkbootblock(&bootarea
, xxboot
, bootxx
, label
, 0);
252 if ((fd
= open(devnm
, O_WRONLY
)) < 0)
253 err(EXIT_FAILURE
, "%s", devnm
);
254 if (write(fd
, &bootarea
, sizeof(bootarea
)) != sizeof(bootarea
))
255 err(EXIT_FAILURE
, "%s", devnm
);
257 err(EXIT_FAILURE
, "%s", devnm
);
259 printf("Boot block installed on %s\n", devnm
);
264 install_sd (char *devnm
, struct disklabel
*label
)
266 const char *machpath
;
267 char *xxb00t
, *xxboot
, *bootxx
;
268 struct disklabel rawlabel
;
272 if (label
->d_partitions
[0].p_size
== 0)
273 errx(EXIT_FAILURE
, "%s: No root-filesystem.", devnm
);
274 if (label
->d_partitions
[0].p_fstype
!= FS_BSDFFS
)
275 errx(EXIT_FAILURE
, "%s: %s: Illegal root-filesystem type.",
276 devnm
, fstypenames
[label
->d_partitions
[0].p_fstype
]);
278 bbsec
= readdisklabel(devnm
, &rawlabel
);
279 if (bbsec
== NO_BOOT_BLOCK
)
280 errx(EXIT_FAILURE
, "%s: No NetBSD boot block.", devnm
);
281 if (memcmp(label
, &rawlabel
, sizeof(*label
)))
282 errx(EXIT_FAILURE
, "%s: Invalid NetBSD boot block.", devnm
);
285 machpath
= milanpath
;
289 xxb00t
= alloca(strlen(mdecpath
) + strlen(machpath
) + 14);
290 sprintf(xxb00t
, "%s%ssdb00t.ahdi", mdecpath
, machpath
);
291 xxboot
= alloca(strlen(mdecpath
) + strlen(machpath
) + 14);
292 sprintf(xxboot
, "%s%sxxboot.ahdi", mdecpath
, machpath
);
296 xxboot
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
297 sprintf(xxboot
, "%s%ssdboot", mdecpath
, machpath
);
300 bootxx
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
301 sprintf(bootxx
, "%s%sbootxx", mdecpath
, machpath
);
303 trackpercyl
= secpertrack
= 0;
305 mkahdiboot(&ahdiboot
, xxb00t
, devnm
, bbsec
);
306 mkbootblock(&bootarea
, xxboot
, bootxx
, label
, magic
);
309 off_t bbo
= (off_t
)bbsec
* AHDI_BSIZE
;
312 if ((fd
= open(devnm
, O_WRONLY
)) < 0)
313 err(EXIT_FAILURE
, "%s", devnm
);
314 if (lseek(fd
, bbo
, SEEK_SET
) != bbo
)
315 err(EXIT_FAILURE
, "%s", devnm
);
316 if (write(fd
, &bootarea
, sizeof(bootarea
)) != sizeof(bootarea
))
317 err(EXIT_FAILURE
, "%s", devnm
);
319 printf("Boot block installed on %s (sector %d)\n", devnm
,
322 if (lseek(fd
, (off_t
)0, SEEK_SET
) != 0)
323 err(EXIT_FAILURE
, "%s", devnm
);
324 if (write(fd
, &ahdiboot
, sizeof(ahdiboot
)) != sizeof(ahdiboot
))
325 err(EXIT_FAILURE
, "%s", devnm
);
327 printf("AHDI root installed on %s (0)\n",
331 err(EXIT_FAILURE
, "%s", devnm
);
336 install_wd (char *devnm
, struct disklabel
*label
)
338 const char *machpath
;
339 char *xxb00t
, *xxboot
, *bootxx
;
340 struct disklabel rawlabel
;
344 if (label
->d_partitions
[0].p_size
== 0)
345 errx(EXIT_FAILURE
, "%s: No root-filesystem.", devnm
);
346 if (label
->d_partitions
[0].p_fstype
!= FS_BSDFFS
)
347 errx(EXIT_FAILURE
, "%s: %s: Illegal root-filesystem type.",
348 devnm
, fstypenames
[label
->d_partitions
[0].p_fstype
]);
350 bbsec
= readdisklabel(devnm
, &rawlabel
);
351 if (bbsec
== NO_BOOT_BLOCK
)
352 errx(EXIT_FAILURE
, "%s: No NetBSD boot block.", devnm
);
353 if (memcmp(label
, &rawlabel
, sizeof(*label
)))
354 errx(EXIT_FAILURE
, "%s: Invalid NetBSD boot block.", devnm
);
357 machpath
= milanpath
;
361 xxb00t
= alloca(strlen(mdecpath
) + strlen(machpath
) + 14);
362 sprintf(xxb00t
, "%s%swdb00t.ahdi", mdecpath
, machpath
);
363 xxboot
= alloca(strlen(mdecpath
) + strlen(machpath
) + 14);
364 sprintf(xxboot
, "%s%sxxboot.ahdi", mdecpath
, machpath
);
368 xxboot
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
369 sprintf(xxboot
, "%s%swdboot", mdecpath
, machpath
);
372 bootxx
= alloca(strlen(mdecpath
) + strlen(machpath
) + 8);
373 sprintf(bootxx
, "%s%sbootxx", mdecpath
, machpath
);
376 mkahdiboot(&ahdiboot
, xxb00t
, devnm
, bbsec
);
377 mkbootblock(&bootarea
, xxboot
, bootxx
, label
, magic
);
383 bbo
= (off_t
)bbsec
* AHDI_BSIZE
;
384 if ((fd
= open(devnm
, O_WRONLY
)) < 0)
385 err(EXIT_FAILURE
, "%s", devnm
);
386 if (lseek(fd
, bbo
, SEEK_SET
) != bbo
)
387 err(EXIT_FAILURE
, "%s", devnm
);
388 if (write(fd
, &bootarea
, sizeof(bootarea
)) != sizeof(bootarea
))
389 err(EXIT_FAILURE
, "%s", devnm
);
391 printf("Boot block installed on %s (sector %d)\n", devnm
,
394 if (lseek(fd
, (off_t
)0, SEEK_SET
) != 0)
395 err(EXIT_FAILURE
, "%s", devnm
);
396 if (write(fd
, &ahdiboot
, sizeof(ahdiboot
))
398 err(EXIT_FAILURE
, "%s", devnm
);
400 printf("AHDI root installed on %s (sector 0)\n",
404 err(EXIT_FAILURE
, "%s", devnm
);
409 mkahdiboot (newroot
, xxb00t
, devnm
, bbsec
)
410 struct ahdi_root
*newroot
;
415 struct ahdi_root tmproot
;
416 struct ahdi_part
*pd
;
419 /* read prototype root-sector */
420 if ((fd
= open(xxb00t
, O_RDONLY
)) < 0)
421 err(EXIT_FAILURE
, "%s", xxb00t
);
422 if (read(fd
, &tmproot
, sizeof(tmproot
)) != sizeof(tmproot
))
423 err(EXIT_FAILURE
, "%s", xxb00t
);
425 err(EXIT_FAILURE
, "%s", xxb00t
);
427 /* set tracks/cylinder and sectors/track */
428 setIDEpar(tmproot
.ar_fill
, sizeof(tmproot
.ar_fill
));
430 /* read current root-sector */
431 if ((fd
= open(devnm
, O_RDONLY
)) < 0)
432 err(EXIT_FAILURE
, "%s", devnm
);
433 if (read(fd
, newroot
, sizeof(*newroot
)) != sizeof(*newroot
))
434 err(EXIT_FAILURE
, "%s", devnm
);
436 err(EXIT_FAILURE
, "%s", devnm
);
439 for (pd
= newroot
->ar_parts
; pd
-newroot
->ar_parts
< AHDI_MAXRPD
; ++pd
) {
440 if (pd
->ap_st
== bbsec
) {
441 pd
->ap_flg
= 0x21; /* bootable, pref = NetBSD */
446 "%s: NetBSD boot block not on primary AHDI partition.", devnm
);
448 gotit
: /* copy code from prototype and set new checksum */
449 memcpy(newroot
->ar_fill
, tmproot
.ar_fill
, sizeof(tmproot
.ar_fill
));
450 newroot
->ar_checksum
= 0;
451 newroot
->ar_checksum
= 0x1234 - abcksum(newroot
);
454 printf("AHDI boot loader: %s\n", xxb00t
);
458 mkbootblock (bb
, xxb
, bxx
, label
, magic
)
459 struct bootblock
*bb
;
463 struct disklabel
*label
;
467 memset(bb
, 0, sizeof(*bb
));
469 /* set boot block magic */
470 bb
->bb_magic
= magic
;
472 /* set disk pack label */
473 BBSETLABEL(bb
, label
);
475 /* set second-stage boot loader */
476 if ((fd
= open(bxx
, O_RDONLY
)) < 0)
477 err(EXIT_FAILURE
, "%s", bxx
);
478 if (read(fd
, bb
->bb_bootxx
, sizeof(bb
->bb_bootxx
))
479 != sizeof(bb
->bb_bootxx
))
480 err(EXIT_FAILURE
, "%s", bxx
);
482 err(EXIT_FAILURE
, "%s", bxx
);
484 /* set first-stage bootloader */
485 if ((fd
= open(xxb
, O_RDONLY
)) < 0)
486 err(EXIT_FAILURE
, "%s", xxb
);
487 if (read(fd
, bb
->bb_xxboot
, sizeof(bb
->bb_xxboot
))
488 != sizeof(bb
->bb_xxboot
))
489 err(EXIT_FAILURE
, "%s", xxb
);
491 err(EXIT_FAILURE
, "%s", xxb
);
493 /* set tracks/cylinder and sectors/track */
494 setIDEpar(bb
->bb_xxboot
, sizeof(bb
->bb_xxboot
));
496 /* set AHDI checksum */
497 *((u_int16_t
*)bb
->bb_xxboot
+ 255) = 0;
498 *((u_int16_t
*)bb
->bb_xxboot
+ 255) = 0x1234 - abcksum(bb
->bb_xxboot
);
501 printf("Primary boot loader: %s\n", xxb
);
502 printf("Secondary boot loader: %s\n", bxx
);
507 setIDEpar (u_int8_t
*start
, size_t size
)
509 static const u_int8_t mark
[] = { 'N', 'e', 't', 'B', 'S', 'D' };
511 if ((u_int
)trackpercyl
> 255)
513 "%d: Illegal tracks/cylinder value (1..255)", trackpercyl
);
514 if ((u_int
)secpertrack
> 255)
516 "%d: Illegal sectors/track value (1..255)", secpertrack
);
518 if (trackpercyl
|| secpertrack
) {
522 errx(EXIT_FAILURE
, "Need tracks/cylinder too.");
524 errx(EXIT_FAILURE
, "Need sectors/track too.");
527 size
-= sizeof(mark
) + 2;
528 for (p
= start
+ size
; p
>= start
; --p
) {
531 if (!memcmp(p
, mark
, sizeof(mark
)))
536 "Malformatted xxboot prototype.");
542 printf("sectors/track : %d\n", secpertrack
);
543 printf("tracks/cylinder: %d\n", trackpercyl
);
551 static const u_char bootpref
= BOOTPREF_NETBSD
;
552 static const char nvrdev
[] = PATH_NVRAM
;
557 if ((fd
= open(nvrdev
, O_RDWR
)) < 0)
558 err(EXIT_FAILURE
, "%s", nvrdev
);
559 if (lseek(fd
, (off_t
)1, SEEK_SET
) != 1)
560 err(EXIT_FAILURE
, "%s", nvrdev
);
561 if (write(fd
, &bootpref
, (size_t)1) != 1)
562 err(EXIT_FAILURE
, "%s", nvrdev
);
564 err(EXIT_FAILURE
, "%s", nvrdev
);
566 printf("Boot preference set to NetBSD.\n");
574 *st
= (u_int16_t
*)bs
,
575 *end
= (u_int16_t
*)bs
+ 256;