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