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