x86, build: Dynamically find entry points in compressed startup code
[~shefty/rdma-dev.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         buf[c] = 0;
247
248         p = (char *)buf;
249
250         while (p && *p) {
251                 PARSE_ZOFS(p, efi_stub_entry);
252                 PARSE_ZOFS(p, efi_pe_entry);
253                 PARSE_ZOFS(p, startup_64);
254
255                 p = strchr(p, '\n');
256                 while (p && (*p == '\r' || *p == '\n'))
257                         p++;
258         }
259 }
260
261 int main(int argc, char ** argv)
262 {
263         unsigned int i, sz, setup_sectors;
264         int c;
265         u32 sys_size;
266         struct stat sb;
267         FILE *file;
268         int fd;
269         void *kernel;
270         u32 crc = 0xffffffffUL;
271
272         /* Defaults for old kernel */
273 #ifdef CONFIG_X86_32
274         efi_pe_entry = 0x10;
275         efi_stub_entry = 0x30;
276 #else
277         efi_pe_entry = 0x210;
278         efi_stub_entry = 0x230;
279         startup_64 = 0x200;
280 #endif
281
282         if (argc == 4)
283                 parse_zoffset(argv[3]);
284         else if (argc != 3)
285                 usage();
286
287         /* Copy the setup code */
288         file = fopen(argv[1], "r");
289         if (!file)
290                 die("Unable to open `%s': %m", argv[1]);
291         c = fread(buf, 1, sizeof(buf), file);
292         if (ferror(file))
293                 die("read-error on `setup'");
294         if (c < 1024)
295                 die("The setup must be at least 1024 bytes");
296         if (get_unaligned_le16(&buf[510]) != 0xAA55)
297                 die("Boot block hasn't got boot flag (0xAA55)");
298         fclose(file);
299
300 #ifdef CONFIG_EFI_STUB
301         /* Reserve 0x20 bytes for .reloc section */
302         memset(buf+c, 0, PECOFF_RELOC_RESERVE);
303         c += PECOFF_RELOC_RESERVE;
304 #endif
305
306         /* Pad unused space with zeros */
307         setup_sectors = (c + 511) / 512;
308         if (setup_sectors < SETUP_SECT_MIN)
309                 setup_sectors = SETUP_SECT_MIN;
310         i = setup_sectors*512;
311         memset(buf+c, 0, i-c);
312
313 #ifdef CONFIG_EFI_STUB
314         update_pecoff_setup_and_reloc(i);
315 #endif
316
317         /* Set the default root device */
318         put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
319
320         fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
321
322         /* Open and stat the kernel file */
323         fd = open(argv[2], O_RDONLY);
324         if (fd < 0)
325                 die("Unable to open `%s': %m", argv[2]);
326         if (fstat(fd, &sb))
327                 die("Unable to stat `%s': %m", argv[2]);
328         sz = sb.st_size;
329         fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
330         kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
331         if (kernel == MAP_FAILED)
332                 die("Unable to mmap '%s': %m", argv[2]);
333         /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
334         sys_size = (sz + 15 + 4) / 16;
335
336         /* Patch the setup code with the appropriate size parameters */
337         buf[0x1f1] = setup_sectors-1;
338         put_unaligned_le32(sys_size, &buf[0x1f4]);
339
340 #ifdef CONFIG_EFI_STUB
341         update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
342
343 #ifdef CONFIG_X86_64 /* Yes, this is really how we defined it :( */
344         efi_stub_entry -= 0x200;
345 #endif
346         put_unaligned_le32(efi_stub_entry, &buf[0x264]);
347 #endif
348
349         crc = partial_crc32(buf, i, crc);
350         if (fwrite(buf, 1, i, stdout) != i)
351                 die("Writing setup failed");
352
353         /* Copy the kernel code */
354         crc = partial_crc32(kernel, sz, crc);
355         if (fwrite(kernel, 1, sz, stdout) != sz)
356                 die("Writing kernel failed");
357
358         /* Add padding leaving 4 bytes for the checksum */
359         while (sz++ < (sys_size*16) - 4) {
360                 crc = partial_crc32_one('\0', crc);
361                 if (fwrite("\0", 1, 1, stdout) != 1)
362                         die("Writing padding failed");
363         }
364
365         /* Write the CRC */
366         fprintf(stderr, "CRC %x\n", crc);
367         put_unaligned_le32(crc, buf);
368         if (fwrite(buf, 1, 4, stdout) != 4)
369                 die("Writing CRC failed");
370
371         close(fd);
372
373         /* Everything is OK */
374         return 0;
375 }