| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Makes a prep bootable image which can be dd'd onto | 
|  | 3 | * a disk device to make a bootdisk.  Will take | 
|  | 4 | * as input a elf executable, strip off the header | 
|  | 5 | * and write out a boot image as: | 
|  | 6 | * 1) default - strips elf header | 
|  | 7 | *      suitable as a network boot image | 
|  | 8 | * 2) -pbp - strips elf header and writes out prep boot partition image | 
|  | 9 | *      cat or dd onto disk for booting | 
|  | 10 | * 3) -asm - strips elf header and writes out as asm data | 
|  | 11 | *      useful for generating data for a compressed image | 
|  | 12 | *                  -- Cort | 
|  | 13 | * | 
|  | 14 | * Modified for x86 hosted builds by Matt Porter <porter@neta.com> | 
|  | 15 | * Modified for Sparc hosted builds by Peter Wahl <PeterWahl@web.de> | 
|  | 16 | */ | 
|  | 17 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 18 | #include <stdio.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 19 | #include <string.h> | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 20 | #include <stdlib.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  | 
|  | 22 | /* size of read buffer */ | 
|  | 23 | #define SIZE 0x1000 | 
|  | 24 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | /* | 
|  | 26 | * Partition table entry | 
|  | 27 | *  - from the PReP spec | 
|  | 28 | */ | 
|  | 29 | typedef struct partition_entry { | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 30 | unsigned char boot_indicator; | 
|  | 31 | unsigned char starting_head; | 
|  | 32 | unsigned char starting_sector; | 
|  | 33 | unsigned char starting_cylinder; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 34 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 35 | unsigned char system_indicator; | 
|  | 36 | unsigned char ending_head; | 
|  | 37 | unsigned char ending_sector; | 
|  | 38 | unsigned char ending_cylinder; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 40 | unsigned char beginning_sector[4]; | 
|  | 41 | unsigned char number_of_sectors[4]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | } partition_entry_t; | 
|  | 43 |  | 
|  | 44 | #define BootActive	0x80 | 
|  | 45 | #define SystemPrep	0x41 | 
|  | 46 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 47 | void copy_image(FILE *, FILE *); | 
|  | 48 | void write_prep_partition(FILE *, FILE *); | 
|  | 49 | void write_asm_data(FILE *, FILE *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 |  | 
|  | 51 | unsigned int elfhdr_size = 65536; | 
|  | 52 |  | 
|  | 53 | int main(int argc, char *argv[]) | 
|  | 54 | { | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 55 | FILE *in, *out; | 
|  | 56 | int argptr = 1; | 
|  | 57 | int prep = 0; | 
|  | 58 | int asmoutput = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 59 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 60 | if (argc < 3 || argc > 4) { | 
|  | 61 | fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n", | 
|  | 62 | argv[0]); | 
|  | 63 | exit(-1); | 
|  | 64 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 66 | /* needs to handle args more elegantly -- but this is a small/simple program */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 68 | /* check for -pbp */ | 
|  | 69 | if (!strcmp(argv[argptr], "-pbp")) { | 
|  | 70 | prep = 1; | 
|  | 71 | argptr++; | 
|  | 72 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 74 | /* check for -asm */ | 
|  | 75 | if (!strcmp(argv[argptr], "-asm")) { | 
|  | 76 | asmoutput = 1; | 
|  | 77 | argptr++; | 
|  | 78 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 80 | /* input file */ | 
|  | 81 | if (!strcmp(argv[argptr], "-")) | 
|  | 82 | in = stdin; | 
|  | 83 | else if (!(in = fopen(argv[argptr], "r"))) | 
|  | 84 | exit(-1); | 
|  | 85 | argptr++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 87 | /* output file */ | 
|  | 88 | if (!strcmp(argv[argptr], "-")) | 
|  | 89 | out = stdout; | 
|  | 90 | else if (!(out = fopen(argv[argptr], "w"))) | 
|  | 91 | exit(-1); | 
|  | 92 | argptr++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 94 | /* skip elf header in input file */ | 
|  | 95 | /*if ( !prep )*/ | 
|  | 96 | fseek(in, elfhdr_size, SEEK_SET); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 98 | /* write prep partition if necessary */ | 
|  | 99 | if (prep) | 
|  | 100 | write_prep_partition(in, out); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 102 | /* write input image to bootimage */ | 
|  | 103 | if (asmoutput) | 
|  | 104 | write_asm_data(in, out); | 
|  | 105 | else | 
|  | 106 | copy_image(in, out); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 107 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 108 | return 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | } | 
|  | 110 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 111 | void store_le32(unsigned int v, unsigned char *p) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 | { | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 113 | p[0] = v; | 
|  | 114 | p[1] = v >>= 8; | 
|  | 115 | p[2] = v >>= 8; | 
|  | 116 | p[3] = v >> 8; | 
|  | 117 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 119 | void write_prep_partition(FILE *in, FILE *out) | 
|  | 120 | { | 
|  | 121 | unsigned char block[512]; | 
|  | 122 | partition_entry_t pe; | 
|  | 123 | unsigned char *entry  = block; | 
|  | 124 | unsigned char *length = block + 4; | 
|  | 125 | long pos = ftell(in), size; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 127 | if (fseek(in, 0, SEEK_END) < 0) { | 
|  | 128 | fprintf(stderr,"info failed\n"); | 
|  | 129 | exit(-1); | 
|  | 130 | } | 
|  | 131 | size = ftell(in); | 
|  | 132 | if (fseek(in, pos, SEEK_SET) < 0) { | 
|  | 133 | fprintf(stderr,"info failed\n"); | 
|  | 134 | exit(-1); | 
|  | 135 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 136 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 137 | memset(block, '\0', sizeof(block)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 139 | /* set entry point and boot image size skipping over elf header */ | 
|  | 140 | store_le32(0x400/*+65536*/, entry); | 
|  | 141 | store_le32(size-elfhdr_size+0x400, length); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 143 | /* sets magic number for msdos partition (used by linux) */ | 
|  | 144 | block[510] = 0x55; | 
|  | 145 | block[511] = 0xAA; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 147 | /* | 
|  | 148 | * Build a "PReP" partition table entry in the boot record | 
|  | 149 | *  - "PReP" may only look at the system_indicator | 
|  | 150 | */ | 
|  | 151 | pe.boot_indicator   = BootActive; | 
|  | 152 | pe.system_indicator = SystemPrep; | 
|  | 153 | /* | 
|  | 154 | * The first block of the diskette is used by this "boot record" which | 
|  | 155 | * actually contains the partition table. (The first block of the | 
|  | 156 | * partition contains the boot image, but I digress...)  We'll set up | 
|  | 157 | * one partition on the diskette and it shall contain the rest of the | 
|  | 158 | * diskette. | 
|  | 159 | */ | 
|  | 160 | pe.starting_head     = 0;	/* zero-based			     */ | 
|  | 161 | pe.starting_sector   = 2;	/* one-based			     */ | 
|  | 162 | pe.starting_cylinder = 0;	/* zero-based			     */ | 
|  | 163 | pe.ending_head       = 1;	/* assumes two heads		     */ | 
|  | 164 | pe.ending_sector     = 18;	/* assumes 18 sectors/track	     */ | 
|  | 165 | pe.ending_cylinder   = 79;	/* assumes 80 cylinders/diskette     */ | 
|  | 166 |  | 
|  | 167 | /* | 
|  | 168 | * The "PReP" software ignores the above fields and just looks at | 
|  | 169 | * the next two. | 
|  | 170 | *   - size of the diskette is (assumed to be) | 
|  | 171 | *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette) | 
|  | 172 | *   - unlike the above sector numbers, the beginning sector is zero-based! | 
|  | 173 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | #if 0 | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 175 | store_le32(1, pe.beginning_sector); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | #else | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 177 | /* This has to be 0 on the PowerStack? */ | 
|  | 178 | store_le32(0, pe.beginning_sector); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 179 | #endif | 
|  | 180 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 181 | store_le32(2*18*80-1, pe.number_of_sectors); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 183 | memcpy(&block[0x1BE], &pe, sizeof(pe)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 184 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 185 | fwrite(block, sizeof(block), 1, out); | 
|  | 186 | fwrite(entry, 4, 1, out); | 
|  | 187 | fwrite(length, 4, 1, out); | 
|  | 188 | /* set file position to 2nd sector where image will be written */ | 
|  | 189 | fseek( out, 0x400, SEEK_SET ); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 | } | 
|  | 191 |  | 
|  | 192 |  | 
|  | 193 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 194 | void copy_image(FILE *in, FILE *out) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 | { | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 196 | char buf[SIZE]; | 
|  | 197 | int n; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 199 | while ( (n = fread(buf, 1, SIZE, in)) > 0 ) | 
|  | 200 | fwrite(buf, 1, n, out); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | } | 
|  | 202 |  | 
|  | 203 |  | 
|  | 204 | void | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 205 | write_asm_data(FILE *in, FILE *out) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 | { | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 207 | int i, cnt, pos = 0; | 
|  | 208 | unsigned int cksum = 0, val; | 
|  | 209 | unsigned char *lp; | 
|  | 210 | unsigned char buf[SIZE]; | 
|  | 211 | size_t len; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 212 |  | 
| Al Viro | c32527a | 2006-09-23 01:37:41 +0100 | [diff] [blame] | 213 | fputs("\t.data\n\t.globl input_data\ninput_data:\n", out); | 
|  | 214 | while ((len = fread(buf, 1, sizeof(buf), in)) > 0) { | 
|  | 215 | cnt = 0; | 
|  | 216 | lp = buf; | 
|  | 217 | /* Round up to longwords */ | 
|  | 218 | while (len & 3) | 
|  | 219 | buf[len++] = '\0'; | 
|  | 220 | for (i = 0;  i < len;  i += 4) { | 
|  | 221 | if (cnt == 0) | 
|  | 222 | fputs("\t.long\t", out); | 
|  | 223 | fprintf(out, "0x%02X%02X%02X%02X", | 
|  | 224 | lp[0], lp[1], lp[2], lp[3]); | 
|  | 225 | val = *(unsigned long *)lp; | 
|  | 226 | cksum ^= val; | 
|  | 227 | lp += 4; | 
|  | 228 | if (++cnt == 4) { | 
|  | 229 | cnt = 0; | 
|  | 230 | fprintf(out, " # %x \n", pos+i-12); | 
|  | 231 | } else { | 
|  | 232 | fputs(",", out); | 
|  | 233 | } | 
|  | 234 | } | 
|  | 235 | if (cnt) | 
|  | 236 | fputs("0\n", out); | 
|  | 237 | pos += len; | 
|  | 238 | } | 
|  | 239 | fprintf(out, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos); | 
|  | 240 | fprintf(stderr, "cksum = %x\n", cksum); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 241 | } |