Linux 2.6.31-rc6
[linux-2.6] / arch / x86 / boot / tools / build.c
1 /*
2  *  Copyright (C) 1991, 1992  Linus Torvalds
3  *  Copyright (C) 1997 Martin Mares
4  *  Copyright (C) 2007 H. Peter Anvin
5  */
6
7 /*
8  * This file builds a disk-image from two different files:
9  *
10  * - setup: 8086 machine code, sets up system parm
11  * - system: 80386 code for actual system
12  *
13  * It does some checking that all files are of the correct type, and
14  * just writes the result to stdout, removing headers and padding to
15  * the right amount. It also writes some system data to stderr.
16  */
17
18 /*
19  * Changes by tytso to allow root device specification
20  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
21  * Cross compiling fixes by Gertjan van Wingerde, July 1996
22  * Rewritten by Martin Mares, April 1997
23  * Substantially overhauled by H. Peter Anvin, April 2007
24  */
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/sysmacros.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <asm/boot.h>
37
38 typedef unsigned char  u8;
39 typedef unsigned short u16;
40 typedef unsigned long  u32;
41
42 #define DEFAULT_MAJOR_ROOT 0
43 #define DEFAULT_MINOR_ROOT 0
44
45 /* Minimal number of setup sectors */
46 #define SETUP_SECT_MIN 5
47 #define SETUP_SECT_MAX 64
48
49 /* This must be large enough to hold the entire setup */
50 u8 buf[SETUP_SECT_MAX*512];
51 int is_big_kernel;
52
53 /*----------------------------------------------------------------------*/
54
55 static const u32 crctab32[] = {
56         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
57         0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
58         0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
59         0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
60         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
61         0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
62         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
63         0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
64         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
65         0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
66         0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
67         0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
68         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
69         0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
70         0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
71         0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
72         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
73         0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
74         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
75         0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
76         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
77         0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
78         0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
79         0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
80         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
81         0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
82         0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
83         0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
84         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
85         0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
86         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
87         0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
88         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
89         0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
90         0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
91         0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
92         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
93         0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
94         0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
95         0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
96         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
97         0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
98         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
99         0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
100         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
101         0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
102         0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
103         0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
104         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
105         0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
106         0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
107         0x2d02ef8d
108 };
109
110 static u32 partial_crc32_one(u8 c, u32 crc)
111 {
112         return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
113 }
114
115 static u32 partial_crc32(const u8 *s, int len, u32 crc)
116 {
117         while (len--)
118                 crc = partial_crc32_one(*s++, crc);
119         return crc;
120 }
121
122 static void die(const char * str, ...)
123 {
124         va_list args;
125         va_start(args, str);
126         vfprintf(stderr, str, args);
127         fputc('\n', stderr);
128         exit(1);
129 }
130
131 static void usage(void)
132 {
133         die("Usage: build setup system [rootdev] [> image]");
134 }
135
136 int main(int argc, char ** argv)
137 {
138         unsigned int i, sz, setup_sectors;
139         int c;
140         u32 sys_size;
141         u8 major_root, minor_root;
142         struct stat sb;
143         FILE *file;
144         int fd;
145         void *kernel;
146         u32 crc = 0xffffffffUL;
147
148         if ((argc < 3) || (argc > 4))
149                 usage();
150         if (argc > 3) {
151                 if (!strcmp(argv[3], "CURRENT")) {
152                         if (stat("/", &sb)) {
153                                 perror("/");
154                                 die("Couldn't stat /");
155                         }
156                         major_root = major(sb.st_dev);
157                         minor_root = minor(sb.st_dev);
158                 } else if (strcmp(argv[3], "FLOPPY")) {
159                         if (stat(argv[3], &sb)) {
160                                 perror(argv[3]);
161                                 die("Couldn't stat root device.");
162                         }
163                         major_root = major(sb.st_rdev);
164                         minor_root = minor(sb.st_rdev);
165                 } else {
166                         major_root = 0;
167                         minor_root = 0;
168                 }
169         } else {
170                 major_root = DEFAULT_MAJOR_ROOT;
171                 minor_root = DEFAULT_MINOR_ROOT;
172         }
173         fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
174
175         /* Copy the setup code */
176         file = fopen(argv[1], "r");
177         if (!file)
178                 die("Unable to open `%s': %m", argv[1]);
179         c = fread(buf, 1, sizeof(buf), file);
180         if (ferror(file))
181                 die("read-error on `setup'");
182         if (c < 1024)
183                 die("The setup must be at least 1024 bytes");
184         if (buf[510] != 0x55 || buf[511] != 0xaa)
185                 die("Boot block hasn't got boot flag (0xAA55)");
186         fclose(file);
187
188         /* Pad unused space with zeros */
189         setup_sectors = (c + 511) / 512;
190         if (setup_sectors < SETUP_SECT_MIN)
191                 setup_sectors = SETUP_SECT_MIN;
192         i = setup_sectors*512;
193         memset(buf+c, 0, i-c);
194
195         /* Set the default root device */
196         buf[508] = minor_root;
197         buf[509] = major_root;
198
199         fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
200
201         /* Open and stat the kernel file */
202         fd = open(argv[2], O_RDONLY);
203         if (fd < 0)
204                 die("Unable to open `%s': %m", argv[2]);
205         if (fstat(fd, &sb))
206                 die("Unable to stat `%s': %m", argv[2]);
207         sz = sb.st_size;
208         fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
209         kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
210         if (kernel == MAP_FAILED)
211                 die("Unable to mmap '%s': %m", argv[2]);
212         /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
213         sys_size = (sz + 15 + 4) / 16;
214
215         /* Patch the setup code with the appropriate size parameters */
216         buf[0x1f1] = setup_sectors-1;
217         buf[0x1f4] = sys_size;
218         buf[0x1f5] = sys_size >> 8;
219         buf[0x1f6] = sys_size >> 16;
220         buf[0x1f7] = sys_size >> 24;
221
222         crc = partial_crc32(buf, i, crc);
223         if (fwrite(buf, 1, i, stdout) != i)
224                 die("Writing setup failed");
225
226         /* Copy the kernel code */
227         crc = partial_crc32(kernel, sz, crc);
228         if (fwrite(kernel, 1, sz, stdout) != sz)
229                 die("Writing kernel failed");
230
231         /* Add padding leaving 4 bytes for the checksum */
232         while (sz++ < (sys_size*16) - 4) {
233                 crc = partial_crc32_one('\0', crc);
234                 if (fwrite("\0", 1, 1, stdout) != 1)
235                         die("Writing padding failed");
236         }
237
238         /* Write the CRC */
239         fprintf(stderr, "CRC %lx\n", crc);
240         if (fwrite(&crc, 1, 4, stdout) != 4)
241                 die("Writing CRC failed");
242
243         close(fd);
244
245         /* Everything is OK */
246         return 0;
247 }