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