Commit | Line | Data |
---|---|---|
5a9c4166 KB |
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 | * | |
5548a02f | 10 | * @(#)mkboottape.c 7.5 (Berkeley) %G% |
5a9c4166 KB |
11 | */ |
12 | ||
5a9c4166 | 13 | #include <sys/param.h> |
69c1fa90 | 14 | #include <sys/stat.h> |
5a9c4166 | 15 | #include <sys/exec.h> |
5548a02f | 16 | |
69c1fa90 KB |
17 | #include <errno.h> |
18 | #include <stdio.h> | |
19 | #include <stdlib.h> | |
20 | #include <unistd.h> | |
21 | #include <fcntl.h> | |
22 | #include <string.h> | |
b8e366da | 23 | |
5548a02f | 24 | #include <pmax/stand/dec_boot.h> |
5a9c4166 | 25 | |
69c1fa90 KB |
26 | void err __P((const char *, ...)); |
27 | void usage __P((void)); | |
5a9c4166 | 28 | |
b8e366da RC |
29 | struct Dec_DiskBoot decBootInfo; |
30 | ||
5a9c4166 KB |
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 | */ | |
69c1fa90 | 39 | int |
5a9c4166 KB |
40 | main(argc, argv) |
41 | int argc; | |
42 | char *argv[]; | |
43 | { | |
44 | register int i, n; | |
5a9c4166 KB |
45 | ProcSectionHeader shdr; |
46 | struct exec aout; | |
5a9c4166 KB |
47 | long loadAddr; |
48 | long execAddr; | |
49 | long textoff; | |
50 | long length; | |
51 | long rootsize; | |
69c1fa90 KB |
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; | |
5a9c4166 | 69 | |
65a02c33 | 70 | if (argc != 4) |
5a9c4166 | 71 | usage(); |
69c1fa90 | 72 | |
5a9c4166 | 73 | if (makebootfile) |
b8e366da | 74 | ofd = open(argv[0], O_CREAT|O_TRUNC|O_WRONLY, DEFFILEMODE); |
5a9c4166 | 75 | else |
b8e366da | 76 | ofd = open(argv[0], O_RDWR, 0); |
69c1fa90 | 77 | if (ofd < 0) |
b8e366da | 78 | deverr: err("%s: %s", argv[0], strerror(errno)); |
69c1fa90 | 79 | |
b8e366da RC |
80 | if ((ifd = open(argv[1], O_RDONLY, 0)) < 0) |
81 | bootferr: err("%s: %s", argv[1], strerror(errno)); | |
69c1fa90 | 82 | |
b8e366da RC |
83 | if ((rfd = open(argv[2], O_RDONLY, 0)) < 0) |
84 | rooterr: err("%s: %s", argv[2], strerror(errno)); | |
69c1fa90 | 85 | |
b8e366da | 86 | rootsize = atoi(argv[3]); |
5a9c4166 KB |
87 | |
88 | /* | |
89 | * Check for exec header and skip to code segment. | |
90 | */ | |
69c1fa90 KB |
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 | ||
5a9c4166 KB |
95 | loadAddr = aout.ex_aout.codeStart; |
96 | execAddr = aout.a_entry; | |
97 | length = aout.a_text + aout.a_data; | |
98 | textoff = N_TXTOFF(aout); | |
69c1fa90 KB |
99 | (void)printf("Input file is COFF format\n"); |
100 | (void)printf("load %x, start %x, len %d\n", loadAddr, execAddr, length); | |
5a9c4166 KB |
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)) >> | |
b8e366da | 106 | DEV_BSHIFT) + rootsize; |
5a9c4166 KB |
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 */ | |
69c1fa90 | 152 | if (lseek(ifd, textoff, SEEK_SET) < 0) |
5a9c4166 KB |
153 | goto bootferr; |
154 | ||
155 | /* | |
156 | * Write the remaining code to the correct place on the tape. | |
157 | */ | |
69c1fa90 | 158 | for (i = length; i > 0; i -= n) { |
5a9c4166 KB |
159 | n = DEV_BSIZE; |
160 | if (n > i) | |
161 | n = i; | |
162 | if (read(ifd, block, n) != n) | |
163 | goto bootferr; | |
b8e366da | 164 | if (write(ofd, block, DEV_BSIZE) != DEV_BSIZE) |
5a9c4166 | 165 | goto deverr; |
5a9c4166 KB |
166 | } |
167 | ||
168 | /* | |
169 | * Pad the boot file with zeros to the start of the mini-root. | |
170 | */ | |
171 | bzero(block, DEV_BSIZE); | |
b8e366da RC |
172 | i = ((nsectors - rootsize) << DEV_BSHIFT) - |
173 | ((length + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1)); | |
174 | n = DEV_BSIZE; | |
175 | for (; i > 0; i -= n) { | |
5a9c4166 KB |
176 | if (write(ofd, block, n) != n) |
177 | goto deverr; | |
5a9c4166 KB |
178 | } |
179 | ||
180 | /* | |
181 | * Write the mini-root to tape. | |
182 | */ | |
69c1fa90 KB |
183 | for (i = rootsize; i > 0; i--) { |
184 | if (read(rfd, block, DEV_BSIZE) != DEV_BSIZE) | |
185 | goto rooterr; | |
5a9c4166 KB |
186 | if (write(ofd, block, DEV_BSIZE) != DEV_BSIZE) |
187 | goto deverr; | |
5a9c4166 KB |
188 | } |
189 | ||
69c1fa90 | 190 | (void)printf("mkboottape: wrote %d sectors\n", nsectors); |
5a9c4166 KB |
191 | exit(0); |
192 | } | |
193 | ||
69c1fa90 | 194 | void |
5a9c4166 KB |
195 | usage() |
196 | { | |
69c1fa90 KB |
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"); | |
5a9c4166 | 227 | exit(1); |
69c1fa90 | 228 | /* NOTREACHED */ |
5a9c4166 | 229 | } |