blob: 192bb397126fac25f5eae2901316252dc19803e6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 Torvalds1da177e2005-04-16 15:20:36 -070018#include <stdio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <string.h>
Al Viroc32527a2006-09-23 01:37:41 +010020#include <stdlib.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22/* size of read buffer */
23#define SIZE 0x1000
24
Linus Torvalds1da177e2005-04-16 15:20:36 -070025/*
26 * Partition table entry
27 * - from the PReP spec
28 */
29typedef struct partition_entry {
Al Viroc32527a2006-09-23 01:37:41 +010030 unsigned char boot_indicator;
31 unsigned char starting_head;
32 unsigned char starting_sector;
33 unsigned char starting_cylinder;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Al Viroc32527a2006-09-23 01:37:41 +010035 unsigned char system_indicator;
36 unsigned char ending_head;
37 unsigned char ending_sector;
38 unsigned char ending_cylinder;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Al Viroc32527a2006-09-23 01:37:41 +010040 unsigned char beginning_sector[4];
41 unsigned char number_of_sectors[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -070042} partition_entry_t;
43
44#define BootActive 0x80
45#define SystemPrep 0x41
46
Al Viroc32527a2006-09-23 01:37:41 +010047void copy_image(FILE *, FILE *);
48void write_prep_partition(FILE *, FILE *);
49void write_asm_data(FILE *, FILE *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51unsigned int elfhdr_size = 65536;
52
53int main(int argc, char *argv[])
54{
Al Viroc32527a2006-09-23 01:37:41 +010055 FILE *in, *out;
56 int argptr = 1;
57 int prep = 0;
58 int asmoutput = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Al Viroc32527a2006-09-23 01:37:41 +010060 if (argc < 3 || argc > 4) {
61 fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
62 argv[0]);
63 exit(-1);
64 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Al Viroc32527a2006-09-23 01:37:41 +010066/* needs to handle args more elegantly -- but this is a small/simple program */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Al Viroc32527a2006-09-23 01:37:41 +010068 /* check for -pbp */
69 if (!strcmp(argv[argptr], "-pbp")) {
70 prep = 1;
71 argptr++;
72 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Al Viroc32527a2006-09-23 01:37:41 +010074 /* check for -asm */
75 if (!strcmp(argv[argptr], "-asm")) {
76 asmoutput = 1;
77 argptr++;
78 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Al Viroc32527a2006-09-23 01:37:41 +010080 /* input file */
81 if (!strcmp(argv[argptr], "-"))
82 in = stdin;
83 else if (!(in = fopen(argv[argptr], "r")))
84 exit(-1);
85 argptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Al Viroc32527a2006-09-23 01:37:41 +010087 /* output file */
88 if (!strcmp(argv[argptr], "-"))
89 out = stdout;
90 else if (!(out = fopen(argv[argptr], "w")))
91 exit(-1);
92 argptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Al Viroc32527a2006-09-23 01:37:41 +010094 /* skip elf header in input file */
95 /*if ( !prep )*/
96 fseek(in, elfhdr_size, SEEK_SET);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Al Viroc32527a2006-09-23 01:37:41 +010098 /* write prep partition if necessary */
99 if (prep)
100 write_prep_partition(in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Al Viroc32527a2006-09-23 01:37:41 +0100102 /* write input image to bootimage */
103 if (asmoutput)
104 write_asm_data(in, out);
105 else
106 copy_image(in, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Al Viroc32527a2006-09-23 01:37:41 +0100108 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
Al Viroc32527a2006-09-23 01:37:41 +0100111void store_le32(unsigned int v, unsigned char *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Al Viroc32527a2006-09-23 01:37:41 +0100113 p[0] = v;
114 p[1] = v >>= 8;
115 p[2] = v >>= 8;
116 p[3] = v >> 8;
117}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Al Viroc32527a2006-09-23 01:37:41 +0100119void 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 Torvalds1da177e2005-04-16 15:20:36 -0700126
Al Viroc32527a2006-09-23 01:37:41 +0100127 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 Torvalds1da177e2005-04-16 15:20:36 -0700136
Al Viroc32527a2006-09-23 01:37:41 +0100137 memset(block, '\0', sizeof(block));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Al Viroc32527a2006-09-23 01:37:41 +0100139 /* 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 Torvalds1da177e2005-04-16 15:20:36 -0700142
Al Viroc32527a2006-09-23 01:37:41 +0100143 /* sets magic number for msdos partition (used by linux) */
144 block[510] = 0x55;
145 block[511] = 0xAA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Al Viroc32527a2006-09-23 01:37:41 +0100147 /*
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 Torvalds1da177e2005-04-16 15:20:36 -0700174#if 0
Al Viroc32527a2006-09-23 01:37:41 +0100175 store_le32(1, pe.beginning_sector);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#else
Al Viroc32527a2006-09-23 01:37:41 +0100177 /* This has to be 0 on the PowerStack? */
178 store_le32(0, pe.beginning_sector);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179#endif
180
Al Viroc32527a2006-09-23 01:37:41 +0100181 store_le32(2*18*80-1, pe.number_of_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Al Viroc32527a2006-09-23 01:37:41 +0100183 memcpy(&block[0x1BE], &pe, sizeof(pe));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Al Viroc32527a2006-09-23 01:37:41 +0100185 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 Torvalds1da177e2005-04-16 15:20:36 -0700190}
191
192
193
Al Viroc32527a2006-09-23 01:37:41 +0100194void copy_image(FILE *in, FILE *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
Al Viroc32527a2006-09-23 01:37:41 +0100196 char buf[SIZE];
197 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Al Viroc32527a2006-09-23 01:37:41 +0100199 while ( (n = fread(buf, 1, SIZE, in)) > 0 )
200 fwrite(buf, 1, n, out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201}
202
203
204void
Al Viroc32527a2006-09-23 01:37:41 +0100205write_asm_data(FILE *in, FILE *out)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
Al Viroc32527a2006-09-23 01:37:41 +0100207 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 Torvalds1da177e2005-04-16 15:20:36 -0700212
Al Viroc32527a2006-09-23 01:37:41 +0100213 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 Torvalds1da177e2005-04-16 15:20:36 -0700241}