1 /*-
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. 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 8.1 (Berkeley) 06/10/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
main(argc,argv)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
usage()206 usage()
207 {
208 (void)fprintf(stderr,
209 "usage: %s [-b] tapedev vmunix minirootdev size\n", __progname);
210 exit(1);
211 }
212