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 | } |