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
38typedef unsigned char  u8;
39typedef unsigned short u16;
40typedef 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 */
51u8 buf[SETUP_SECT_MAX*512];
52int is_big_kernel;
53
54#define PECOFF_RELOC_RESERVE 0x20
55
56unsigned long efi32_stub_entry;
57unsigned long efi64_stub_entry;
58unsigned long efi_pe_entry;
59unsigned long startup_64;
60
61/*----------------------------------------------------------------------*/
62
63static 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
118static u32 partial_crc32_one(u8 c, u32 crc)
119{
120	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
121}
122
123static 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
130static 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
139static void usage(void)
140{
141	die("Usage: build setup system zoffset.h image");
142}
143
144#ifdef CONFIG_EFI_STUB
145
146static 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
182static 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
187static 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
204static 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
225static 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
241static 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
248static 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
259static 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
277static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
278static inline void update_pecoff_text(unsigned int text_start,
279				      unsigned int file_sz) {}
280static inline void update_pecoff_bss(unsigned int file_sz,
281				     unsigned int init_sz) {}
282static inline void efi_stub_defaults(void) {}
283static inline void efi_stub_entry_update(void) {}
284
285static 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
302static 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
331int 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