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