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