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