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