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