xref: /netbsd-src/sys/arch/atari/stand/installboot/installboot.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: installboot.c,v 1.7 1997/07/09 14:31:13 leo Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Waldi Ravens
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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
20  *
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.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 #include <sys/ioctl.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <paths.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <err.h>
45 #include <limits.h>
46 #include <nlist.h>
47 #include <kvm.h>
48 
49 #define	DKTYPENAMES
50 #include <sys/disklabel.h>
51 #include <machine/ahdilabel.h>
52 
53 #include "installboot.h"
54 
55 static void	usage __P((void));
56 static void	oscheck __P((void));
57 static u_int	abcksum __P((void *));
58 static void	setNVpref __P((void));
59 static void	setIDEpar __P((u_int8_t *, size_t));
60 static void	mkahdiboot __P((struct ahdi_root *, char *,
61 						char *, daddr_t));
62 static void	mkbootblock __P((struct bootblock *, char *,
63 				char *, struct disklabel *, u_int));
64 static void	install_fd __P((char *, struct disklabel *));
65 static void	install_sd __P((char *, struct disklabel *));
66 static void	install_wd __P((char *, struct disklabel *));
67 
68 static struct bootblock	bootarea;
69 static struct ahdi_root ahdiboot;
70 static const char	mdecpath[] = PATH_MDEC;
71 static int		nowrite = 0;
72 static int		verbose = 0;
73 static int		trackpercyl = 0;
74 static int		secpertrack = 0;
75 
76 static void
77 usage ()
78 {
79 	fprintf(stderr,
80 		"usage: installboot [options] device\n"
81 		"where options are:\n"
82 		"\t-N  do not actually write anything on the disk\n"
83 		"\t-t  number of tracks per cylinder (IDE disk)\n"
84 		"\t-u  number of sectors per track (IDE disk)\n"
85 		"\t-v  verbose mode\n");
86 	exit(EXIT_FAILURE);
87 }
88 
89 int
90 main (argc, argv)
91 	int	argc;
92 	char	*argv[];
93 {
94 	struct disklabel dl;
95 	char		 *dn;
96 	int		 fd, c;
97 
98 	/* check OS bootversion */
99 	oscheck();
100 
101 	/* parse options */
102 	while ((c = getopt(argc, argv, "Nt:u:v")) != -1) {
103 		switch (c) {
104 		  case 'N':
105 			nowrite = 1;
106 			break;
107 		  case 't':
108 			trackpercyl = atoi(optarg);
109 			break;
110 		  case 'u':
111 			secpertrack = atoi(optarg);
112 			break;
113 		  case 'v':
114 			verbose = 1;
115 			break;
116 		  default:
117 			usage();
118 		}
119 	}
120 	argv += optind;
121 	argc -= optind;
122 	if (argc != 1)
123 		usage();
124 
125 	/* get disk label */
126 	dn = alloca(sizeof(_PATH_DEV) + strlen(argv[0]) + 8);
127 	if (!strchr(argv[0], '/')) {
128 		sprintf(dn, "%sr%s%c", _PATH_DEV, argv[0], RAW_PART + 'a');
129 		fd = open(dn, O_RDONLY);
130 		if (fd < 0 && errno == ENOENT) {
131 			sprintf(dn, "%sr%s", _PATH_DEV, argv[0]);
132 			fd = open(dn, O_RDONLY);
133 		}
134 	} else {
135 		sprintf(dn, "%s", argv[0]);
136 		fd = open(dn, O_RDONLY);
137 	}
138 	if (fd < 0)
139 		err(EXIT_FAILURE, "%s", dn);
140 	if (ioctl(fd, DIOCGDINFO, &dl))
141 		err(EXIT_FAILURE, "%s: DIOCGDINFO", dn);
142 	if (close(fd))
143 		err(EXIT_FAILURE, "%s", dn);
144 
145 	switch (dl.d_type) {
146 		case DTYPE_FLOPPY:
147 			install_fd(dn, &dl);
148 			break;
149 		case DTYPE_ST506:
150 		case DTYPE_ESDI:
151 			install_wd(dn, &dl);
152 			setNVpref();
153 			break;
154 		case DTYPE_SCSI:
155 			install_sd(dn, &dl);
156 			setNVpref();
157 			break;
158 		default:
159 			errx(EXIT_FAILURE,
160 			     "%s: %s: Device type not supported.",
161 			     dn, dktypenames[dl.d_type]);
162 	}
163 
164 	return(EXIT_SUCCESS);
165 }
166 
167 static void
168 oscheck ()
169 {
170 	struct nlist	kbv[] = { { "_bootversion" }, { NULL } };
171 	kvm_t		*kd_kern;
172 	char		errbuf[_POSIX2_LINE_MAX];
173 	u_short		kvers;
174 
175 	kd_kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
176 	if (kd_kern == NULL)
177 		errx(EXIT_FAILURE, "kvm_openfiles: %s", errbuf);
178 	if (kvm_nlist(kd_kern, kbv) == -1)
179 		errx(EXIT_FAILURE, "kvm_nlist: %s", kvm_geterr(kd_kern));
180 	if (kbv[0].n_value == 0)
181 		errx(EXIT_FAILURE, "%s not in namelist", kbv[0].n_name);
182 	if (kvm_read(kd_kern, kbv[0].n_value, (char *)&kvers,
183 						sizeof(kvers)) == -1)
184 		errx(EXIT_FAILURE, "kvm_read: %s", kvm_geterr(kd_kern));
185 	kvm_close(kd_kern);
186 	if (kvers != BOOTVERSION)
187 		errx(EXIT_FAILURE, "Kern bootversion: %d, expected: %d\n",
188 					kvers, BOOTVERSION);
189 }
190 
191 static void
192 install_fd (devnm, label)
193 	char		 *devnm;
194 	struct disklabel *label;
195 {
196 	char		 *xxboot, *bootxx;
197 	struct partition *rootpart;
198 
199 	if (label->d_secsize != 512)
200 		errx(EXIT_FAILURE,
201 		     "%s: %u: Block size not supported.", devnm,
202 							  label->d_secsize);
203 	if (label->d_ntracks != 2)
204 		errx(EXIT_FAILURE,
205 		     "%s: Single sided floppy not supported.", devnm);
206 
207 	xxboot = alloca(strlen(mdecpath) + 8);
208 	sprintf(xxboot, "%sfdboot", mdecpath);
209 	bootxx = alloca(strlen(mdecpath) + 8);
210 	sprintf(bootxx, "%sbootxx", mdecpath);
211 
212 	/* first used partition (a, b or c) */		/* XXX */
213 	for (rootpart = label->d_partitions; ; ++rootpart) {
214 		if (rootpart->p_size)
215 			break;
216 	}
217 	if (rootpart != label->d_partitions) {		/* XXX */
218 		*(label->d_partitions) = *rootpart;
219 		memset(rootpart, 0, sizeof(*rootpart));
220 	}
221 	label->d_partitions->p_fstype = FS_BSDFFS;	/* XXX */
222 	label->d_npartitions = 1;
223 	label->d_checksum = 0;
224 	label->d_checksum = dkcksum(label);
225 
226 	trackpercyl = secpertrack = 0;
227 	mkbootblock(&bootarea, xxboot, bootxx, label, 0);
228 
229 	if (!nowrite) {
230 		int	fd;
231 		if ((fd = open(devnm, O_WRONLY)) < 0)
232 			err(EXIT_FAILURE, "%s", devnm);
233 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
234 			err(EXIT_FAILURE, "%s", devnm);
235 		if (close(fd))
236 			err(EXIT_FAILURE, "%s", devnm);
237 		if (verbose)
238 			printf("Boot block installed on %s\n", devnm);
239 	}
240 }
241 
242 static void
243 install_sd (devnm, label)
244 	char		 *devnm;
245 	struct disklabel *label;
246 {
247 	char		 *xxb00t, *xxboot, *bootxx;
248 	struct disklabel rawlabel;
249 	daddr_t		 bbsec;
250 	u_int		 magic;
251 
252 	if (label->d_partitions[0].p_size == 0)
253 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
254 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
255 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
256 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
257 
258 	bbsec = readdisklabel(devnm, &rawlabel);
259 	if (bbsec == NO_BOOT_BLOCK)
260 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
261 	if (memcmp(label, &rawlabel, sizeof(*label)))
262 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
263 
264 	if (bbsec) {
265 		xxb00t = alloca(strlen(mdecpath) + 14);
266 		sprintf(xxb00t, "%ssdb00t.ahdi", mdecpath);
267 		xxboot = alloca(strlen(mdecpath) + 14);
268 		sprintf(xxboot, "%sxxboot.ahdi", mdecpath);
269 		magic = AHDIMAGIC;
270 	} else {
271 		xxb00t = NULL;
272 		xxboot = alloca(strlen(mdecpath) + 8);
273 		sprintf(xxboot, "%ssdboot", mdecpath);
274 		magic = NBDAMAGIC;
275 	}
276 	bootxx = alloca(strlen(mdecpath) + 8);
277 	sprintf(bootxx, "%sbootxx", mdecpath);
278 
279 	trackpercyl = secpertrack = 0;
280 	if (xxb00t)
281 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
282 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
283 
284 	if (!nowrite) {
285 		off_t	bbo = bbsec * AHDI_BSIZE;
286 		int	fd;
287 
288 		if ((fd = open(devnm, O_WRONLY)) < 0)
289 			err(EXIT_FAILURE, "%s", devnm);
290 		if (lseek(fd, bbo, SEEK_SET) != bbo)
291 			err(EXIT_FAILURE, "%s", devnm);
292 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
293 			err(EXIT_FAILURE, "%s", devnm);
294 		if (verbose)
295 			printf("Boot block installed on %s (%u)\n", devnm,
296 								    bbsec);
297 		if (xxb00t) {
298 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
299 				err(EXIT_FAILURE, "%s", devnm);
300 			if (write(fd, &ahdiboot, sizeof(ahdiboot)) != sizeof(ahdiboot))
301 				err(EXIT_FAILURE, "%s", devnm);
302 			if (verbose)
303 				printf("AHDI root  installed on %s (0)\n",
304 								devnm);
305 		}
306 		if (close(fd))
307 			err(EXIT_FAILURE, "%s", devnm);
308 	}
309 }
310 
311 static void
312 install_wd (devnm, label)
313 	char		 *devnm;
314 	struct disklabel *label;
315 {
316 	char		 *xxb00t, *xxboot, *bootxx;
317 	struct disklabel rawlabel;
318 	daddr_t		 bbsec;
319 	u_int		 magic;
320 
321 	if (label->d_partitions[0].p_size == 0)
322 		errx(EXIT_FAILURE, "%s: No root-filesystem.", devnm);
323 	if (label->d_partitions[0].p_fstype != FS_BSDFFS)
324 		errx(EXIT_FAILURE, "%s: %s: Illegal root-filesystem type.",
325 		     devnm, fstypenames[label->d_partitions[0].p_fstype]);
326 
327 	bbsec = readdisklabel(devnm, &rawlabel);
328 	if (bbsec == NO_BOOT_BLOCK)
329 		errx(EXIT_FAILURE, "%s: No NetBSD boot block.", devnm);
330 	if (memcmp(label, &rawlabel, sizeof(*label)))
331 		errx(EXIT_FAILURE, "%s: Invalid NetBSD boot block.", devnm);
332 
333 	if (bbsec) {
334 		xxb00t = alloca(strlen(mdecpath) + 14);
335 		sprintf(xxb00t, "%swdb00t.ahdi", mdecpath);
336 		xxboot = alloca(strlen(mdecpath) + 14);
337 		sprintf(xxboot, "%sxxboot.ahdi", mdecpath);
338 		magic = AHDIMAGIC;
339 	} else {
340 		xxb00t = NULL;
341 		xxboot = alloca(strlen(mdecpath) + 8);
342 		sprintf(xxboot, "%swdboot", mdecpath);
343 		magic = NBDAMAGIC;
344 	}
345 	bootxx = alloca(strlen(mdecpath) + 8);
346 	sprintf(bootxx, "%sbootxx", mdecpath);
347 
348 	if (xxb00t)
349 		mkahdiboot(&ahdiboot, xxb00t, devnm, bbsec);
350 	mkbootblock(&bootarea, xxboot, bootxx, label, magic);
351 
352 	if (!nowrite) {
353 		int	fd;
354 		off_t	bbo;
355 
356 		bbo = bbsec * AHDI_BSIZE;
357 		if ((fd = open(devnm, O_WRONLY)) < 0)
358 			err(EXIT_FAILURE, "%s", devnm);
359 		if (lseek(fd, bbo, SEEK_SET) != bbo)
360 			err(EXIT_FAILURE, "%s", devnm);
361 		if (write(fd, &bootarea, sizeof(bootarea)) != sizeof(bootarea))
362 			err(EXIT_FAILURE, "%s", devnm);
363 		if (verbose)
364 			printf("Boot block installed on %s (%u)\n", devnm,
365 								    bbsec);
366 		if (xxb00t) {
367 			if (lseek(fd, (off_t)0, SEEK_SET) != 0)
368 				err(EXIT_FAILURE, "%s", devnm);
369 			if (write(fd, &ahdiboot, sizeof(ahdiboot))
370 							!= sizeof(ahdiboot))
371 				err(EXIT_FAILURE, "%s", devnm);
372 			if (verbose)
373 				printf("AHDI root  installed on %s (0)\n",
374 									devnm);
375 		}
376 		if (close(fd))
377 			err(EXIT_FAILURE, "%s", devnm);
378 	}
379 }
380 
381 static void
382 mkahdiboot (newroot, xxb00t, devnm, bbsec)
383 	struct ahdi_root *newroot;
384 	char		 *xxb00t,
385 			 *devnm;
386 	daddr_t		 bbsec;
387 {
388 	struct ahdi_root tmproot;
389 	struct ahdi_part *pd;
390 	int		 fd;
391 
392 	/* read prototype root-sector */
393 	if ((fd = open(xxb00t, O_RDONLY)) < 0)
394 		err(EXIT_FAILURE, "%s", xxb00t);
395 	if (read(fd, &tmproot, sizeof(tmproot)) != sizeof(tmproot))
396 		err(EXIT_FAILURE, "%s", xxb00t);
397 	if (close(fd))
398 		err(EXIT_FAILURE, "%s", xxb00t);
399 
400 	/* set tracks/cylinder and sectors/track */
401 	setIDEpar(tmproot.ar_fill, sizeof(tmproot.ar_fill));
402 
403 	/* read current root-sector */
404 	if ((fd = open(devnm, O_RDONLY)) < 0)
405 		err(EXIT_FAILURE, "%s", devnm);
406 	if (read(fd, newroot, sizeof(*newroot)) != sizeof(*newroot))
407 		err(EXIT_FAILURE, "%s", devnm);
408 	if (close(fd))
409 		err(EXIT_FAILURE, "%s", devnm);
410 
411 	/* set bootflags */
412 	for (pd = newroot->ar_parts; pd-newroot->ar_parts < AHDI_MAXRPD; ++pd) {
413 		if (pd->ap_st == bbsec) {
414 			pd->ap_flg = 0x21;	/* bootable, pref = NetBSD */
415 			goto gotit;
416 		}
417 	}
418 	errx(EXIT_FAILURE,
419 	     "%s: NetBSD boot block not on primary AHDI partition.", devnm);
420 
421 gotit:	/* copy code from prototype and set new checksum */
422 	memcpy(newroot->ar_fill, tmproot.ar_fill, sizeof(tmproot.ar_fill));
423 	newroot->ar_checksum = 0;
424 	newroot->ar_checksum = 0x1234 - abcksum(newroot);
425 
426 	if (verbose)
427 		printf("AHDI      boot loader: %s\n", xxb00t);
428 }
429 
430 static void
431 mkbootblock (bb, xxb, bxx, label, magic)
432 	struct bootblock *bb;
433 	char		 *xxb,
434 			 *bxx;
435 	u_int		 magic;
436 	struct disklabel *label;
437 {
438 	int		 fd;
439 
440 	memset(bb, 0, sizeof(*bb));
441 
442 	/* set boot block magic */
443 	bb->bb_magic = magic;
444 
445 	/* set disk pack label */
446 	BBSETLABEL(bb, label);
447 
448 	/* set second-stage boot loader */
449 	if ((fd = open(bxx, O_RDONLY)) < 0)
450 		err(EXIT_FAILURE, "%s", bxx);
451 	if (read(fd, bb->bb_bootxx, sizeof(bb->bb_bootxx))
452 					!= sizeof(bb->bb_bootxx))
453 		err(EXIT_FAILURE, "%s", bxx);
454 	if (close(fd))
455 		err(EXIT_FAILURE, "%s", bxx);
456 
457 	/* set first-stage bootloader */
458 	if ((fd = open(xxb, O_RDONLY)) < 0)
459 		err(EXIT_FAILURE, "%s", xxb);
460 	if (read(fd, bb->bb_xxboot, sizeof(bb->bb_xxboot))
461 					!= sizeof(bb->bb_xxboot))
462 		err(EXIT_FAILURE, "%s", xxb);
463 	if (close(fd))
464 		err(EXIT_FAILURE, "%s", xxb);
465 
466 	/* set tracks/cylinder and sectors/track */
467 	setIDEpar(bb->bb_xxboot, sizeof(bb->bb_xxboot));
468 
469 	/* set AHDI checksum */
470 	*((u_int16_t *)bb->bb_xxboot + 255) = 0;
471 	*((u_int16_t *)bb->bb_xxboot + 255) = 0x1234 - abcksum(bb->bb_xxboot);
472 
473 	if (verbose) {
474 		printf("Primary   boot loader: %s\n", xxb);
475 		printf("Secondary boot loader: %s\n", bxx);
476 	}
477 }
478 
479 static void
480 setIDEpar (start, size)
481 	u_int8_t	*start;
482 	size_t		size;
483 {
484 	static const u_int8_t	mark[] = { 'N', 'e', 't', 'B', 'S', 'D' };
485 
486 	if ((u_int)trackpercyl > 255)
487 		errx(EXIT_FAILURE,
488 		     "%d: Illegal tracks/cylinder value (1..255)", trackpercyl);
489 	if ((u_int)secpertrack > 255)
490 		errx(EXIT_FAILURE,
491 		     "%d: Illegal sectors/track value (1..255)", secpertrack);
492 
493 	if (trackpercyl || secpertrack) {
494 		u_int8_t *p;
495 
496 		if (!trackpercyl)
497 			errx(EXIT_FAILURE, "Need tracks/cylinder too.");
498 		if (!secpertrack)
499 			errx(EXIT_FAILURE, "Need sectors/track too.");
500 
501 		start += 2;
502 		size  -= sizeof(mark) + 2;
503 		for (p = start + size; p >= start; --p) {
504 			if (*p != *mark)
505 				continue;
506 			if (!memcmp(p, mark, sizeof(mark)))
507 				break;
508 		}
509 		if (p < start)
510 			errx(EXIT_FAILURE,
511 			     "Malformatted xxboot prototype.");
512 
513 		*--p = secpertrack;
514 		*--p = trackpercyl;
515 
516 		if (verbose) {
517 			printf("sectors/track  : %d\n", secpertrack);
518 			printf("tracks/cylinder: %d\n", trackpercyl);
519 		}
520 	}
521 }
522 
523 static void
524 setNVpref ()
525 {
526 	static const u_char	bootpref = BOOTPREF_NETBSD;
527 	static const char	nvrdev[] = PATH_NVRAM;
528 
529 	if (!nowrite) {
530 		int	fd;
531 
532 		if ((fd = open(nvrdev, O_RDWR)) < 0)
533 			err(EXIT_FAILURE, "%s", nvrdev);
534 		if (lseek(fd, (off_t)1, SEEK_SET) != 1)
535 			err(EXIT_FAILURE, "%s", nvrdev);
536 		if (write(fd, &bootpref, (size_t)1) != 1)
537 			err(EXIT_FAILURE, "%s", nvrdev);
538 		if (close(fd))
539 			err(EXIT_FAILURE, "%s", nvrdev);
540 		if (verbose)
541 			printf("Boot preference set to NetBSD.\n");
542 	}
543 }
544 
545 static u_int
546 abcksum (bs)
547 	void	*bs;
548 {
549 	u_int16_t sum  = 0,
550 		  *st  = (u_int16_t *)bs,
551 		  *end = (u_int16_t *)bs + 256;
552 
553 	while (st < end)
554 		sum += *st++;
555 	return(sum);
556 }
557