]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/x86/boot/tools/build.c
Merge branch 'x86/uv'
[karo-tx-linux.git] / 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 three different files:
9  *
10  * - setup: 8086 machine code, sets up system parm
11  * - system: 80386 code for actual system
12  * - zoffset.h: header with ZO_* defines
13  *
14  * It does some checking that all files are of the correct type, and writes
15  * the result to the specified destination, removing headers and padding to
16  * the right amount. It also writes some system data to stdout.
17  */
18
19 /*
20  * Changes by tytso to allow root device specification
21  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
22  * Cross compiling fixes by Gertjan van Wingerde, July 1996
23  * Rewritten by Martin Mares, April 1997
24  * Substantially overhauled by H. Peter Anvin, April 2007
25  */
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/mman.h>
36 #include <tools/le_byteshift.h>
37
38 typedef unsigned char  u8;
39 typedef unsigned short u16;
40 typedef unsigned int   u32;
41
42 #define DEFAULT_MAJOR_ROOT 0
43 #define DEFAULT_MINOR_ROOT 0
44 #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
45
46 /* Minimal number of setup sectors */
47 #define SETUP_SECT_MIN 5
48 #define SETUP_SECT_MAX 64
49
50 /* This must be large enough to hold the entire setup */
51 u8 buf[SETUP_SECT_MAX*512];
52 int is_big_kernel;
53
54 #define PECOFF_RELOC_RESERVE 0x20
55
56 unsigned long efi_stub_entry;
57 unsigned long efi_pe_entry;
58 unsigned long startup_64;
59
60 /*----------------------------------------------------------------------*/
61
62 static const u32 crctab32[] = {
63         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
64         0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
65         0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
66         0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
67         0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
68         0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
69         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
70         0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
71         0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
72         0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
73         0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
74         0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
75         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
76         0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
77         0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
78         0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
79         0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
80         0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
81         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
82         0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
83         0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
84         0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
85         0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
86         0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
87         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
88         0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
89         0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
90         0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
91         0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
92         0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
93         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
94         0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
95         0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
96         0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
97         0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
98         0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
99         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
100         0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
101         0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
102         0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
103         0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
104         0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
105         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
106         0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
107         0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
108         0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
109         0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
110         0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
111         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
112         0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
113         0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
114         0x2d02ef8d
115 };
116
117 static u32 partial_crc32_one(u8 c, u32 crc)
118 {
119         return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
120 }
121
122 static u32 partial_crc32(const u8 *s, int len, u32 crc)
123 {
124         while (len--)
125                 crc = partial_crc32_one(*s++, crc);
126         return crc;
127 }
128
129 static void die(const char * str, ...)
130 {
131         va_list args;
132         va_start(args, str);
133         vfprintf(stderr, str, args);
134         fputc('\n', stderr);
135         exit(1);
136 }
137
138 static void usage(void)
139 {
140         die("Usage: build setup system zoffset.h image");
141 }
142
143 #ifdef CONFIG_EFI_STUB
144
145 static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
146 {
147         unsigned int pe_header;
148         unsigned short num_sections;
149         u8 *section;
150
151         pe_header = get_unaligned_le32(&buf[0x3c]);
152         num_sections = get_unaligned_le16(&buf[pe_header + 6]);
153
154 #ifdef CONFIG_X86_32
155         section = &buf[pe_header + 0xa8];
156 #else
157         section = &buf[pe_header + 0xb8];
158 #endif
159
160         while (num_sections > 0) {
161                 if (strncmp((char*)section, section_name, 8) == 0) {
162                         /* section header size field */
163                         put_unaligned_le32(size, section + 0x8);
164
165                         /* section header vma field */
166                         put_unaligned_le32(offset, section + 0xc);
167
168                         /* section header 'size of initialised data' field */
169                         put_unaligned_le32(size, section + 0x10);
170
171                         /* section header 'file offset' field */
172                         put_unaligned_le32(offset, section + 0x14);
173
174                         break;
175                 }
176                 section += 0x28;
177                 num_sections--;
178         }
179 }
180
181 static void update_pecoff_setup_and_reloc(unsigned int size)
182 {
183         u32 setup_offset = 0x200;
184         u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
185         u32 setup_size = reloc_offset - setup_offset;
186
187         update_pecoff_section_header(".setup", setup_offset, setup_size);
188         update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
189
190         /*
191          * Modify .reloc section contents with a single entry. The
192          * relocation is applied to offset 10 of the relocation section.
193          */
194         put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
195         put_unaligned_le32(10, &buf[reloc_offset + 4]);
196 }
197
198 static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
199 {
200         unsigned int pe_header;
201         unsigned int text_sz = file_sz - text_start;
202
203         pe_header = get_unaligned_le32(&buf[0x3c]);
204
205         /* Size of image */
206         put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
207
208         /*
209          * Size of code: Subtract the size of the first sector (512 bytes)
210          * which includes the header.
211          */
212         put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
213
214         /*
215          * Address of entry point for PE/COFF executable
216          */
217         put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
218
219         update_pecoff_section_header(".text", text_start, text_sz);
220 }
221
222 #endif /* CONFIG_EFI_STUB */
223
224
225 /*
226  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
227  * but that would mean tools/build would have to be rebuilt every time. It's
228  * not as if parsing it is hard...
229  */
230 #define PARSE_ZOFS(p, sym) do { \
231         if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))       \
232                 sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);         \
233 } while (0)
234
235 static void parse_zoffset(char *fname)
236 {
237         FILE *file;
238         char *p;
239         int c;
240
241         file = fopen(fname, "r");
242         if (!file)
243                 die("Unable to open `%s': %m", fname);
244         c = fread(buf, 1, sizeof(buf) - 1, file);
245         if (ferror(file))
246                 die("read-error on `zoffset.h'");
247         fclose(file);
248         buf[c] = 0;
249
250         p = (char *)buf;
251
252         while (p && *p) {
253                 PARSE_ZOFS(p, efi_stub_entry);
254                 PARSE_ZOFS(p, efi_pe_entry);
255                 PARSE_ZOFS(p, startup_64);
256
257                 p = strchr(p, '\n');
258                 while (p && (*p == '\r' || *p == '\n'))
259                         p++;
260         }
261 }
262
263 int main(int argc, char ** argv)
264 {
265         unsigned int i, sz, setup_sectors;
266         int c;
267         u32 sys_size;
268         struct stat sb;
269         FILE *file, *dest;
270         int fd;
271         void *kernel;
272         u32 crc = 0xffffffffUL;
273
274         /* Defaults for old kernel */
275 #ifdef CONFIG_X86_32
276         efi_pe_entry = 0x10;
277         efi_stub_entry = 0x30;
278 #else
279         efi_pe_entry = 0x210;
280         efi_stub_entry = 0x230;
281         startup_64 = 0x200;
282 #endif
283
284         if (argc != 5)
285                 usage();
286         parse_zoffset(argv[3]);
287
288         dest = fopen(argv[4], "w");
289         if (!dest)
290                 die("Unable to write `%s': %m", argv[4]);
291
292         /* Copy the setup code */
293         file = fopen(argv[1], "r");
294         if (!file)
295                 die("Unable to open `%s': %m", argv[1]);
296         c = fread(buf, 1, sizeof(buf), file);
297         if (ferror(file))
298                 die("read-error on `setup'");
299         if (c < 1024)
300                 die("The setup must be at least 1024 bytes");
301         if (get_unaligned_le16(&buf[510]) != 0xAA55)
302                 die("Boot block hasn't got boot flag (0xAA55)");
303         fclose(file);
304
305 #ifdef CONFIG_EFI_STUB
306         /* Reserve 0x20 bytes for .reloc section */
307         memset(buf+c, 0, PECOFF_RELOC_RESERVE);
308         c += PECOFF_RELOC_RESERVE;
309 #endif
310
311         /* Pad unused space with zeros */
312         setup_sectors = (c + 511) / 512;
313         if (setup_sectors < SETUP_SECT_MIN)
314                 setup_sectors = SETUP_SECT_MIN;
315         i = setup_sectors*512;
316         memset(buf+c, 0, i-c);
317
318 #ifdef CONFIG_EFI_STUB
319         update_pecoff_setup_and_reloc(i);
320 #endif
321
322         /* Set the default root device */
323         put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
324
325         printf("Setup is %d bytes (padded to %d bytes).\n", c, i);
326
327         /* Open and stat the kernel file */
328         fd = open(argv[2], O_RDONLY);
329         if (fd < 0)
330                 die("Unable to open `%s': %m", argv[2]);
331         if (fstat(fd, &sb))
332                 die("Unable to stat `%s': %m", argv[2]);
333         sz = sb.st_size;
334         printf("System is %d kB\n", (sz+1023)/1024);
335         kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
336         if (kernel == MAP_FAILED)
337                 die("Unable to mmap '%s': %m", argv[2]);
338         /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
339         sys_size = (sz + 15 + 4) / 16;
340
341         /* Patch the setup code with the appropriate size parameters */
342         buf[0x1f1] = setup_sectors-1;
343         put_unaligned_le32(sys_size, &buf[0x1f4]);
344
345 #ifdef CONFIG_EFI_STUB
346         update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
347
348 #ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
349         efi_stub_entry -= 0x200;
350 #endif
351         put_unaligned_le32(efi_stub_entry, &buf[0x264]);
352 #endif
353
354         crc = partial_crc32(buf, i, crc);
355         if (fwrite(buf, 1, i, dest) != i)
356                 die("Writing setup failed");
357
358         /* Copy the kernel code */
359         crc = partial_crc32(kernel, sz, crc);
360         if (fwrite(kernel, 1, sz, dest) != sz)
361                 die("Writing kernel failed");
362
363         /* Add padding leaving 4 bytes for the checksum */
364         while (sz++ < (sys_size*16) - 4) {
365                 crc = partial_crc32_one('\0', crc);
366                 if (fwrite("\0", 1, 1, dest) != 1)
367                         die("Writing padding failed");
368         }
369
370         /* Write the CRC */
371         printf("CRC %x\n", crc);
372         put_unaligned_le32(crc, buf);
373         if (fwrite(buf, 1, 4, dest) != 4)
374                 die("Writing CRC failed");
375
376         /* Catch any delayed write failures */
377         if (fclose(dest))
378                 die("Writing image failed");
379
380         close(fd);
381
382         /* Everything is OK */
383         return 0;
384 }