xref: /original-bsd/sys/pmax/stand/mkboottape.c (revision a7108741)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)mkboottape.c	7.7 (Berkeley) 03/08/93
11  */
12 
13 #include <sys/param.h>
14 #include <sys/stat.h>
15 #include <sys/exec.h>
16 
17 #include <errno.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <err.h>
24 
25 #include <pmax/stand/dec_boot.h>
26 #include <pmax/stand/dec_exec.h>
27 
28 void usage __P((void));
29 
30 struct	Dec_DiskBoot decBootInfo;
31 struct	coff_exec dec_exec;
32 extern char *__progname;		/* Program name, from crt0. */
33 
34 /*
35  * This program takes a kernel and the name of the special device file that
36  * has the mini-root file system stored on it and creates a boot tape.
37  * The -b option makes a bootfile that can load the kernel and mini-root
38  * over the network using the 'boot 6/tftp/filename -m' PROM command.
39  *
40  * usage: mkboottape [-b] tapedev vmunix minirootdev size
41  */
42 int
43 main(argc, argv)
44 	int argc;
45 	char *argv[];
46 {
47 	register int i, n;
48 	ProcSectionHeader shdr;
49 	struct exec aout;
50 	long loadAddr;
51 	long execAddr;
52 	off_t textoff;
53 	long length;
54 	long rootsize;
55 	int ifd, ofd, rfd;
56 	int makebootfile;
57 	int nsectors;
58 	char block[DEV_BSIZE];
59 
60 	makebootfile = 0;
61 	while ((i = getopt(argc, argv, "b")) != EOF)
62 		switch(i) {
63 		case 'b':
64 			makebootfile = 1;
65 			break;
66 		case '?':
67 		default:
68 			usage();
69 		}
70 	argc -= optind;
71 	argv += optind;
72 
73 	if (argc != 4)
74 		usage();
75 
76 	if (makebootfile)
77 		ofd = open(argv[0], O_CREAT|O_TRUNC|O_WRONLY, DEFFILEMODE);
78 	else
79 		ofd = open(argv[0], O_RDWR, 0);
80 	if (ofd < 0)
81 deverr:		err(1, "%s", argv[0]);
82 
83 	if ((ifd = open(argv[1], O_RDONLY, 0)) < 0)
84 bootferr:	err(1, "%s", argv[1]);
85 
86 	if ((rfd = open(argv[2], O_RDONLY, 0)) < 0)
87 rooterr:	err(1, "%s", argv[2]);
88 
89 	rootsize = atoi(argv[3]);
90 
91 	/*
92 	 * Check for exec header and skip to code segment.
93 	 */
94 	if (read(ifd, &aout, sizeof(aout)) != sizeof(aout) ||
95 	    aout.a_magic != OMAGIC) {
96 		fprintf(stderr, "%s: %s: need old text format (OMAGIC) file\n",
97 			__progname, argv[1]);
98 		exit(1);
99 	}
100 
101 	loadAddr = aout.a_entry;
102 	execAddr = aout.a_entry;
103 	length = aout.a_text + aout.a_data;
104 	textoff = N_TXTOFF(aout);
105 	(void)printf("Input file is a.out format\n");
106 	(void)printf("load %x, start %x, len %d\n", loadAddr, execAddr, length);
107 
108 	/*
109 	 * Compute size of boot program rounded to page size + mini-root size.
110 	 */
111 	nsectors = (((length + aout.a_bss + NBPG - 1) & ~(NBPG - 1)) >>
112 		DEV_BSHIFT) + rootsize;
113 
114 	if (makebootfile) {
115 		/*
116 		 * Write the ECOFF header.
117 		 */
118 		dec_exec.magic = COFF_MAGIC;
119 		dec_exec.numSections = 1;
120 		dec_exec.optHeader = 56;
121 		dec_exec.flags = 7;
122 		dec_exec.aout_magic = OMAGIC;
123 		dec_exec.verStamp = 512;
124 		dec_exec.codeSize = nsectors << DEV_BSHIFT;
125 		dec_exec.entry = execAddr;
126 		dec_exec.codeStart = loadAddr;
127 		dec_exec.heapStart = dec_exec.bssStart =
128 			dec_exec.codeStart + aout.a_text;
129 		if (write(ofd, (char *)&dec_exec, sizeof(dec_exec)) !=
130 		    sizeof(dec_exec))
131 			goto deverr;
132 		strncpy(shdr.name, ".text", sizeof(shdr.name));
133 		shdr.physAddr = shdr.virtAddr = loadAddr;
134 		shdr.size = dec_exec.codeSize;
135 		shdr.sectionPtr = n =
136 			(sizeof(dec_exec) + sizeof(shdr) + 15) & ~15;
137 		shdr.relocPtr = 0;
138 		shdr.lnnoPtr = 0;
139 		shdr.numReloc = 0;
140 		shdr.numLnno = 0;
141 		shdr.flags = 0x20;
142 		if (write(ofd, (char *)&shdr, sizeof(shdr)) != sizeof(shdr))
143 			goto deverr;
144 		n -= sizeof(dec_exec) + sizeof(shdr);
145 		if (write(ofd, block, n) != n)
146 			goto deverr;
147 	} else {
148 		/*
149 		 * Write the boot information block.
150 		 */
151 		decBootInfo.magic = DEC_BOOT_MAGIC;
152 		decBootInfo.mode = 0;
153 		decBootInfo.loadAddr = loadAddr;
154 		decBootInfo.execAddr = execAddr;
155 		decBootInfo.map[0].numBlocks = nsectors;
156 		decBootInfo.map[0].startBlock = 1;
157 		decBootInfo.map[1].numBlocks = 0;
158 		if (write(ofd, (char *)&decBootInfo, sizeof(decBootInfo)) !=
159 		    sizeof(decBootInfo))
160 			goto deverr;
161 	}
162 	/* seek to start of text */
163 	if (lseek(ifd, textoff, SEEK_SET) < 0)
164 		goto bootferr;
165 
166 	/*
167 	 * Write the remaining code to the correct place on the tape.
168 	 */
169 	for (i = length; i > 0; i -= n) {
170 		n = DEV_BSIZE;
171 		if (n > i)
172 			n = i;
173 		if (read(ifd, block, n) != n)
174 			goto bootferr;
175 		if (write(ofd, block, DEV_BSIZE) != DEV_BSIZE)
176 			goto deverr;
177 	}
178 
179 	/*
180 	 * Pad the boot file with zeros to the start of the mini-root.
181 	 */
182 	bzero(block, DEV_BSIZE);
183 	i = ((nsectors - rootsize) << DEV_BSHIFT) -
184 		((length + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1));
185 	n = DEV_BSIZE;
186 	for (; i > 0; i -= n) {
187 		if (write(ofd, block, n) != n)
188 			goto deverr;
189 	}
190 
191 	/*
192 	 * Write the mini-root to tape.
193 	 */
194 	for (i = rootsize; i > 0; i--) {
195 		if (read(rfd, block, DEV_BSIZE) != DEV_BSIZE)
196 			goto rooterr;
197 		if (write(ofd, block, DEV_BSIZE) != DEV_BSIZE)
198 			goto deverr;
199 	}
200 
201 	(void)printf("%s: wrote %d sectors\n", __progname, nsectors);
202 	exit(0);
203 }
204 
205 void
206 usage()
207 {
208 	(void)fprintf(stderr,
209 	    "usage: %s [-b] tapedev vmunix minirootdev size\n", __progname);
210 	exit(1);
211 }
212