spelling fixes: arch/alpha/
[linux-2.6.git] / arch / ppc / boot / utils / mkprep.c
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
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21
22 /* size of read buffer */
23 #define SIZE 0x1000
24
25 /*
26  * Partition table entry
27  *  - from the PReP spec
28  */
29 typedef struct partition_entry {
30         unsigned char boot_indicator;
31         unsigned char starting_head;
32         unsigned char starting_sector;
33         unsigned char starting_cylinder;
34
35         unsigned char system_indicator;
36         unsigned char ending_head;
37         unsigned char ending_sector;
38         unsigned char ending_cylinder;
39
40         unsigned char beginning_sector[4];
41         unsigned char number_of_sectors[4];
42 } partition_entry_t;
43
44 #define BootActive      0x80
45 #define SystemPrep      0x41
46
47 void copy_image(FILE *, FILE *);
48 void write_prep_partition(FILE *, FILE *);
49 void write_asm_data(FILE *, FILE *);
50
51 unsigned int elfhdr_size = 65536;
52
53 int main(int argc, char *argv[])
54 {
55         FILE *in, *out;
56         int argptr = 1;
57         int prep = 0;
58         int asmoutput = 0;
59
60         if (argc < 3 || argc > 4) {
61                 fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
62                         argv[0]);
63                 exit(-1);
64         }
65
66 /* needs to handle args more elegantly -- but this is a small/simple program */
67
68         /* check for -pbp */
69         if (!strcmp(argv[argptr], "-pbp")) {
70                 prep = 1;
71                 argptr++;
72         }
73
74         /* check for -asm */
75         if (!strcmp(argv[argptr], "-asm")) {
76                 asmoutput = 1;
77                 argptr++;
78         }
79
80         /* input file */
81         if (!strcmp(argv[argptr], "-"))
82                 in = stdin;
83         else if (!(in = fopen(argv[argptr], "r")))
84                 exit(-1);
85         argptr++;
86
87         /* output file */
88         if (!strcmp(argv[argptr], "-"))
89                 out = stdout;
90         else if (!(out = fopen(argv[argptr], "w")))
91                 exit(-1);
92         argptr++;
93
94         /* skip elf header in input file */
95         /*if ( !prep )*/
96         fseek(in, elfhdr_size, SEEK_SET);
97
98         /* write prep partition if necessary */
99         if (prep)
100                 write_prep_partition(in, out);
101
102         /* write input image to bootimage */
103         if (asmoutput)
104                 write_asm_data(in, out);
105         else
106                 copy_image(in, out);
107
108         return 0;
109 }
110
111 void store_le32(unsigned int v, unsigned char *p)
112 {
113         p[0] = v;
114         p[1] = v >>= 8;
115         p[2] = v >>= 8;
116         p[3] = v >> 8;
117 }
118
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;
126
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         }
136
137         memset(block, '\0', sizeof(block));
138
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);
142
143         /* sets magic number for msdos partition (used by linux) */
144         block[510] = 0x55;
145         block[511] = 0xAA;
146
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         */
174 #if 0
175         store_le32(1, pe.beginning_sector);
176 #else
177         /* This has to be 0 on the PowerStack? */
178         store_le32(0, pe.beginning_sector);
179 #endif
180
181         store_le32(2*18*80-1, pe.number_of_sectors);
182
183         memcpy(&block[0x1BE], &pe, sizeof(pe));
184
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 );
190 }
191
192
193
194 void copy_image(FILE *in, FILE *out)
195 {
196         char buf[SIZE];
197         int n;
198
199         while ( (n = fread(buf, 1, SIZE, in)) > 0 )
200                 fwrite(buf, 1, n, out);
201 }
202
203
204 void
205 write_asm_data(FILE *in, FILE *out)
206 {
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;
212
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);
241 }