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.7 (Berkeley) 03/08/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 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 206 usage() 207 { 208 (void)fprintf(stderr, 209 "usage: %s [-b] tapedev vmunix minirootdev size\n", __progname); 210 exit(1); 211 } 212