xref: /openbmc/linux/arch/x86/boot/tools/build.c (revision 80ebec68)
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 
53 #define PECOFF_RELOC_RESERVE 0x20
54 
55 unsigned long efi32_stub_entry;
56 unsigned long efi64_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_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
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(vma, section + 0xc);
167 
168 			/* section header 'size of initialised data' field */
169 			put_unaligned_le32(datasz, 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_section_header(char *section_name, u32 offset, u32 size)
182 {
183 	update_pecoff_section_header_fields(section_name, offset, size, size, offset);
184 }
185 
186 static void update_pecoff_setup_and_reloc(unsigned int size)
187 {
188 	u32 setup_offset = 0x200;
189 	u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
190 	u32 setup_size = reloc_offset - setup_offset;
191 
192 	update_pecoff_section_header(".setup", setup_offset, setup_size);
193 	update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
194 
195 	/*
196 	 * Modify .reloc section contents with a single entry. The
197 	 * relocation is applied to offset 10 of the relocation section.
198 	 */
199 	put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
200 	put_unaligned_le32(10, &buf[reloc_offset + 4]);
201 }
202 
203 static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
204 {
205 	unsigned int pe_header;
206 	unsigned int text_sz = file_sz - text_start;
207 
208 	pe_header = get_unaligned_le32(&buf[0x3c]);
209 
210 	/*
211 	 * Size of code: Subtract the size of the first sector (512 bytes)
212 	 * which includes the header.
213 	 */
214 	put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
215 
216 	/*
217 	 * Address of entry point for PE/COFF executable
218 	 */
219 	put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
220 
221 	update_pecoff_section_header(".text", text_start, text_sz);
222 }
223 
224 static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz)
225 {
226 	unsigned int pe_header;
227 	unsigned int bss_sz = init_sz - file_sz;
228 
229 	pe_header = get_unaligned_le32(&buf[0x3c]);
230 
231 	/* Size of uninitialized data */
232 	put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]);
233 
234 	/* Size of image */
235 	put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
236 
237 	update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0);
238 }
239 
240 static int reserve_pecoff_reloc_section(int c)
241 {
242 	/* Reserve 0x20 bytes for .reloc section */
243 	memset(buf+c, 0, PECOFF_RELOC_RESERVE);
244 	return PECOFF_RELOC_RESERVE;
245 }
246 
247 static void efi_stub_defaults(void)
248 {
249 	/* Defaults for old kernel */
250 #ifdef CONFIG_X86_32
251 	efi_pe_entry = 0x10;
252 #else
253 	efi_pe_entry = 0x210;
254 	startup_64 = 0x200;
255 #endif
256 }
257 
258 static void efi_stub_entry_update(void)
259 {
260 	unsigned long addr = efi32_stub_entry;
261 
262 #ifdef CONFIG_X86_64
263 	/* Yes, this is really how we defined it :( */
264 	addr = efi64_stub_entry - 0x200;
265 #endif
266 
267 #ifdef CONFIG_EFI_MIXED
268 	if (efi32_stub_entry != addr)
269 		die("32-bit and 64-bit EFI entry points do not match\n");
270 #endif
271 	put_unaligned_le32(addr, &buf[0x264]);
272 }
273 
274 #else
275 
276 static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
277 static inline void update_pecoff_text(unsigned int text_start,
278 				      unsigned int file_sz) {}
279 static inline void update_pecoff_bss(unsigned int file_sz,
280 				     unsigned int init_sz) {}
281 static inline void efi_stub_defaults(void) {}
282 static inline void efi_stub_entry_update(void) {}
283 
284 static inline int reserve_pecoff_reloc_section(int c)
285 {
286 	return 0;
287 }
288 #endif /* CONFIG_EFI_STUB */
289 
290 
291 /*
292  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
293  * but that would mean tools/build would have to be rebuilt every time. It's
294  * not as if parsing it is hard...
295  */
296 #define PARSE_ZOFS(p, sym) do { \
297 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
298 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
299 } while (0)
300 
301 static void parse_zoffset(char *fname)
302 {
303 	FILE *file;
304 	char *p;
305 	int c;
306 
307 	file = fopen(fname, "r");
308 	if (!file)
309 		die("Unable to open `%s': %m", fname);
310 	c = fread(buf, 1, sizeof(buf) - 1, file);
311 	if (ferror(file))
312 		die("read-error on `zoffset.h'");
313 	fclose(file);
314 	buf[c] = 0;
315 
316 	p = (char *)buf;
317 
318 	while (p && *p) {
319 		PARSE_ZOFS(p, efi32_stub_entry);
320 		PARSE_ZOFS(p, efi64_stub_entry);
321 		PARSE_ZOFS(p, efi_pe_entry);
322 		PARSE_ZOFS(p, startup_64);
323 
324 		p = strchr(p, '\n');
325 		while (p && (*p == '\r' || *p == '\n'))
326 			p++;
327 	}
328 }
329 
330 int main(int argc, char ** argv)
331 {
332 	unsigned int i, sz, setup_sectors, init_sz;
333 	int c;
334 	u32 sys_size;
335 	struct stat sb;
336 	FILE *file, *dest;
337 	int fd;
338 	void *kernel;
339 	u32 crc = 0xffffffffUL;
340 
341 	efi_stub_defaults();
342 
343 	if (argc != 5)
344 		usage();
345 	parse_zoffset(argv[3]);
346 
347 	dest = fopen(argv[4], "w");
348 	if (!dest)
349 		die("Unable to write `%s': %m", argv[4]);
350 
351 	/* Copy the setup code */
352 	file = fopen(argv[1], "r");
353 	if (!file)
354 		die("Unable to open `%s': %m", argv[1]);
355 	c = fread(buf, 1, sizeof(buf), file);
356 	if (ferror(file))
357 		die("read-error on `setup'");
358 	if (c < 1024)
359 		die("The setup must be at least 1024 bytes");
360 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
361 		die("Boot block hasn't got boot flag (0xAA55)");
362 	fclose(file);
363 
364 	c += reserve_pecoff_reloc_section(c);
365 
366 	/* Pad unused space with zeros */
367 	setup_sectors = (c + 511) / 512;
368 	if (setup_sectors < SETUP_SECT_MIN)
369 		setup_sectors = SETUP_SECT_MIN;
370 	i = setup_sectors*512;
371 	memset(buf+c, 0, i-c);
372 
373 	update_pecoff_setup_and_reloc(i);
374 
375 	/* Set the default root device */
376 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
377 
378 	printf("Setup is %d bytes (padded to %d bytes).\n", c, i);
379 
380 	/* Open and stat the kernel file */
381 	fd = open(argv[2], O_RDONLY);
382 	if (fd < 0)
383 		die("Unable to open `%s': %m", argv[2]);
384 	if (fstat(fd, &sb))
385 		die("Unable to stat `%s': %m", argv[2]);
386 	sz = sb.st_size;
387 	printf("System is %d kB\n", (sz+1023)/1024);
388 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
389 	if (kernel == MAP_FAILED)
390 		die("Unable to mmap '%s': %m", argv[2]);
391 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
392 	sys_size = (sz + 15 + 4) / 16;
393 
394 	/* Patch the setup code with the appropriate size parameters */
395 	buf[0x1f1] = setup_sectors-1;
396 	put_unaligned_le32(sys_size, &buf[0x1f4]);
397 
398 	update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
399 	init_sz = get_unaligned_le32(&buf[0x260]);
400 	update_pecoff_bss(i + (sys_size * 16), init_sz);
401 
402 	efi_stub_entry_update();
403 
404 	crc = partial_crc32(buf, i, crc);
405 	if (fwrite(buf, 1, i, dest) != i)
406 		die("Writing setup failed");
407 
408 	/* Copy the kernel code */
409 	crc = partial_crc32(kernel, sz, crc);
410 	if (fwrite(kernel, 1, sz, dest) != sz)
411 		die("Writing kernel failed");
412 
413 	/* Add padding leaving 4 bytes for the checksum */
414 	while (sz++ < (sys_size*16) - 4) {
415 		crc = partial_crc32_one('\0', crc);
416 		if (fwrite("\0", 1, 1, dest) != 1)
417 			die("Writing padding failed");
418 	}
419 
420 	/* Write the CRC */
421 	printf("CRC %x\n", crc);
422 	put_unaligned_le32(crc, buf);
423 	if (fwrite(buf, 1, 4, dest) != 4)
424 		die("Writing CRC failed");
425 
426 	/* Catch any delayed write failures */
427 	if (fclose(dest))
428 		die("Writing image failed");
429 
430 	close(fd);
431 
432 	/* Everything is OK */
433 	return 0;
434 }
435