xref: /linux/arch/x86/boot/tools/build.c (revision b8ff87a6158886771677e6dc8139bac6e3cba717)
119d8d79cSThomas Gleixner /*
219d8d79cSThomas Gleixner  *  Copyright (C) 1991, 1992  Linus Torvalds
319d8d79cSThomas Gleixner  *  Copyright (C) 1997 Martin Mares
419d8d79cSThomas Gleixner  *  Copyright (C) 2007 H. Peter Anvin
519d8d79cSThomas Gleixner  */
619d8d79cSThomas Gleixner 
719d8d79cSThomas Gleixner /*
8809373e2SKees Cook  * This file builds a disk-image from three different files:
919d8d79cSThomas Gleixner  *
1019d8d79cSThomas Gleixner  * - setup: 8086 machine code, sets up system parm
1119d8d79cSThomas Gleixner  * - system: 80386 code for actual system
12809373e2SKees Cook  * - zoffset.h: header with ZO_* defines
1319d8d79cSThomas Gleixner  *
14809373e2SKees Cook  * It does some checking that all files are of the correct type, and writes
15809373e2SKees Cook  * the result to the specified destination, removing headers and padding to
16809373e2SKees Cook  * the right amount. It also writes some system data to stdout.
1719d8d79cSThomas Gleixner  */
1819d8d79cSThomas Gleixner 
1919d8d79cSThomas Gleixner /*
2019d8d79cSThomas Gleixner  * Changes by tytso to allow root device specification
2119d8d79cSThomas Gleixner  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
2219d8d79cSThomas Gleixner  * Cross compiling fixes by Gertjan van Wingerde, July 1996
2319d8d79cSThomas Gleixner  * Rewritten by Martin Mares, April 1997
2419d8d79cSThomas Gleixner  * Substantially overhauled by H. Peter Anvin, April 2007
2519d8d79cSThomas Gleixner  */
2619d8d79cSThomas Gleixner 
2719d8d79cSThomas Gleixner #include <stdio.h>
2819d8d79cSThomas Gleixner #include <string.h>
2919d8d79cSThomas Gleixner #include <stdlib.h>
3019d8d79cSThomas Gleixner #include <stdarg.h>
3119d8d79cSThomas Gleixner #include <sys/types.h>
3219d8d79cSThomas Gleixner #include <sys/stat.h>
3319d8d79cSThomas Gleixner #include <unistd.h>
3419d8d79cSThomas Gleixner #include <fcntl.h>
3519d8d79cSThomas Gleixner #include <sys/mman.h>
3692f42c50SMatt Fleming #include <tools/le_byteshift.h>
3719d8d79cSThomas Gleixner 
3819d8d79cSThomas Gleixner typedef unsigned char  u8;
3919d8d79cSThomas Gleixner typedef unsigned short u16;
40a51f4047SH. Peter Anvin typedef unsigned int   u32;
4119d8d79cSThomas Gleixner 
4219d8d79cSThomas Gleixner #define DEFAULT_MAJOR_ROOT 0
4319d8d79cSThomas Gleixner #define DEFAULT_MINOR_ROOT 0
4492f42c50SMatt Fleming #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
4519d8d79cSThomas Gleixner 
4619d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4719d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4819d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
4919d8d79cSThomas Gleixner 
5019d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
5119d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
5219d8d79cSThomas Gleixner int is_big_kernel;
5319d8d79cSThomas Gleixner 
54743628e8SJordan Justen #define PECOFF_RELOC_RESERVE 0x20
55743628e8SJordan Justen 
56*b8ff87a6SMatt Fleming unsigned long efi32_stub_entry;
57*b8ff87a6SMatt Fleming unsigned long efi64_stub_entry;
5899f857dbSDavid Woodhouse unsigned long efi_pe_entry;
5999f857dbSDavid Woodhouse unsigned long startup_64;
6099f857dbSDavid Woodhouse 
617d6e737cSIan Campbell /*----------------------------------------------------------------------*/
627d6e737cSIan Campbell 
637d6e737cSIan Campbell static const u32 crctab32[] = {
647d6e737cSIan Campbell 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
657d6e737cSIan Campbell 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
667d6e737cSIan Campbell 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
677d6e737cSIan Campbell 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
687d6e737cSIan Campbell 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
697d6e737cSIan Campbell 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
707d6e737cSIan Campbell 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
717d6e737cSIan Campbell 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
727d6e737cSIan Campbell 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
737d6e737cSIan Campbell 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
747d6e737cSIan Campbell 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
757d6e737cSIan Campbell 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
767d6e737cSIan Campbell 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
777d6e737cSIan Campbell 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
787d6e737cSIan Campbell 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
797d6e737cSIan Campbell 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
807d6e737cSIan Campbell 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
817d6e737cSIan Campbell 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
827d6e737cSIan Campbell 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
837d6e737cSIan Campbell 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
847d6e737cSIan Campbell 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
857d6e737cSIan Campbell 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
867d6e737cSIan Campbell 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
877d6e737cSIan Campbell 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
887d6e737cSIan Campbell 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
897d6e737cSIan Campbell 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
907d6e737cSIan Campbell 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
917d6e737cSIan Campbell 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
927d6e737cSIan Campbell 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
937d6e737cSIan Campbell 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
947d6e737cSIan Campbell 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
957d6e737cSIan Campbell 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
967d6e737cSIan Campbell 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
977d6e737cSIan Campbell 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
987d6e737cSIan Campbell 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
997d6e737cSIan Campbell 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1007d6e737cSIan Campbell 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1017d6e737cSIan Campbell 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1027d6e737cSIan Campbell 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1037d6e737cSIan Campbell 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1047d6e737cSIan Campbell 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1057d6e737cSIan Campbell 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1067d6e737cSIan Campbell 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1077d6e737cSIan Campbell 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1087d6e737cSIan Campbell 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1097d6e737cSIan Campbell 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1107d6e737cSIan Campbell 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1117d6e737cSIan Campbell 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1127d6e737cSIan Campbell 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1137d6e737cSIan Campbell 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1147d6e737cSIan Campbell 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1157d6e737cSIan Campbell 	0x2d02ef8d
1167d6e737cSIan Campbell };
1177d6e737cSIan Campbell 
1187d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1197d6e737cSIan Campbell {
1207d6e737cSIan Campbell 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1217d6e737cSIan Campbell }
1227d6e737cSIan Campbell 
1237d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1247d6e737cSIan Campbell {
1257d6e737cSIan Campbell 	while (len--)
1267d6e737cSIan Campbell 		crc = partial_crc32_one(*s++, crc);
1277d6e737cSIan Campbell 	return crc;
1287d6e737cSIan Campbell }
1297d6e737cSIan Campbell 
13019d8d79cSThomas Gleixner static void die(const char * str, ...)
13119d8d79cSThomas Gleixner {
13219d8d79cSThomas Gleixner 	va_list args;
13319d8d79cSThomas Gleixner 	va_start(args, str);
13419d8d79cSThomas Gleixner 	vfprintf(stderr, str, args);
13519d8d79cSThomas Gleixner 	fputc('\n', stderr);
13619d8d79cSThomas Gleixner 	exit(1);
13719d8d79cSThomas Gleixner }
13819d8d79cSThomas Gleixner 
13919d8d79cSThomas Gleixner static void usage(void)
14019d8d79cSThomas Gleixner {
141809373e2SKees Cook 	die("Usage: build setup system zoffset.h image");
14219d8d79cSThomas Gleixner }
14319d8d79cSThomas Gleixner 
144743628e8SJordan Justen #ifdef CONFIG_EFI_STUB
145743628e8SJordan Justen 
146743628e8SJordan Justen static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
147743628e8SJordan Justen {
148743628e8SJordan Justen 	unsigned int pe_header;
149743628e8SJordan Justen 	unsigned short num_sections;
150743628e8SJordan Justen 	u8 *section;
151743628e8SJordan Justen 
152743628e8SJordan Justen 	pe_header = get_unaligned_le32(&buf[0x3c]);
153743628e8SJordan Justen 	num_sections = get_unaligned_le16(&buf[pe_header + 6]);
154743628e8SJordan Justen 
155743628e8SJordan Justen #ifdef CONFIG_X86_32
156743628e8SJordan Justen 	section = &buf[pe_header + 0xa8];
157743628e8SJordan Justen #else
158743628e8SJordan Justen 	section = &buf[pe_header + 0xb8];
159743628e8SJordan Justen #endif
160743628e8SJordan Justen 
161743628e8SJordan Justen 	while (num_sections > 0) {
162743628e8SJordan Justen 		if (strncmp((char*)section, section_name, 8) == 0) {
163743628e8SJordan Justen 			/* section header size field */
164743628e8SJordan Justen 			put_unaligned_le32(size, section + 0x8);
165743628e8SJordan Justen 
166743628e8SJordan Justen 			/* section header vma field */
167743628e8SJordan Justen 			put_unaligned_le32(offset, section + 0xc);
168743628e8SJordan Justen 
169743628e8SJordan Justen 			/* section header 'size of initialised data' field */
170743628e8SJordan Justen 			put_unaligned_le32(size, section + 0x10);
171743628e8SJordan Justen 
172743628e8SJordan Justen 			/* section header 'file offset' field */
173743628e8SJordan Justen 			put_unaligned_le32(offset, section + 0x14);
174743628e8SJordan Justen 
175743628e8SJordan Justen 			break;
176743628e8SJordan Justen 		}
177743628e8SJordan Justen 		section += 0x28;
178743628e8SJordan Justen 		num_sections--;
179743628e8SJordan Justen 	}
180743628e8SJordan Justen }
181743628e8SJordan Justen 
182743628e8SJordan Justen static void update_pecoff_setup_and_reloc(unsigned int size)
183743628e8SJordan Justen {
184743628e8SJordan Justen 	u32 setup_offset = 0x200;
185743628e8SJordan Justen 	u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
186743628e8SJordan Justen 	u32 setup_size = reloc_offset - setup_offset;
187743628e8SJordan Justen 
188743628e8SJordan Justen 	update_pecoff_section_header(".setup", setup_offset, setup_size);
189743628e8SJordan Justen 	update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
190743628e8SJordan Justen 
191743628e8SJordan Justen 	/*
192743628e8SJordan Justen 	 * Modify .reloc section contents with a single entry. The
193743628e8SJordan Justen 	 * relocation is applied to offset 10 of the relocation section.
194743628e8SJordan Justen 	 */
195743628e8SJordan Justen 	put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
196743628e8SJordan Justen 	put_unaligned_le32(10, &buf[reloc_offset + 4]);
197743628e8SJordan Justen }
198743628e8SJordan Justen 
199743628e8SJordan Justen static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
200743628e8SJordan Justen {
201743628e8SJordan Justen 	unsigned int pe_header;
202743628e8SJordan Justen 	unsigned int text_sz = file_sz - text_start;
203743628e8SJordan Justen 
204743628e8SJordan Justen 	pe_header = get_unaligned_le32(&buf[0x3c]);
205743628e8SJordan Justen 
206743628e8SJordan Justen 	/* Size of image */
207743628e8SJordan Justen 	put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
208743628e8SJordan Justen 
209743628e8SJordan Justen 	/*
210743628e8SJordan Justen 	 * Size of code: Subtract the size of the first sector (512 bytes)
211743628e8SJordan Justen 	 * which includes the header.
212743628e8SJordan Justen 	 */
213743628e8SJordan Justen 	put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
214743628e8SJordan Justen 
215743628e8SJordan Justen 	/*
21699f857dbSDavid Woodhouse 	 * Address of entry point for PE/COFF executable
217743628e8SJordan Justen 	 */
21899f857dbSDavid Woodhouse 	put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
219743628e8SJordan Justen 
220743628e8SJordan Justen 	update_pecoff_section_header(".text", text_start, text_sz);
221743628e8SJordan Justen }
222743628e8SJordan Justen 
223993c30a0SMatt Fleming static int reserve_pecoff_reloc_section(int c)
224993c30a0SMatt Fleming {
225993c30a0SMatt Fleming 	/* Reserve 0x20 bytes for .reloc section */
226993c30a0SMatt Fleming 	memset(buf+c, 0, PECOFF_RELOC_RESERVE);
227993c30a0SMatt Fleming 	return PECOFF_RELOC_RESERVE;
228993c30a0SMatt Fleming }
229993c30a0SMatt Fleming 
230993c30a0SMatt Fleming static void efi_stub_defaults(void)
231993c30a0SMatt Fleming {
232993c30a0SMatt Fleming 	/* Defaults for old kernel */
233993c30a0SMatt Fleming #ifdef CONFIG_X86_32
234993c30a0SMatt Fleming 	efi_pe_entry = 0x10;
235993c30a0SMatt Fleming #else
236993c30a0SMatt Fleming 	efi_pe_entry = 0x210;
237993c30a0SMatt Fleming 	startup_64 = 0x200;
238993c30a0SMatt Fleming #endif
239993c30a0SMatt Fleming }
240993c30a0SMatt Fleming 
241993c30a0SMatt Fleming static void efi_stub_entry_update(void)
242993c30a0SMatt Fleming {
243*b8ff87a6SMatt Fleming 	unsigned long addr = efi32_stub_entry;
244*b8ff87a6SMatt Fleming 
245*b8ff87a6SMatt Fleming #ifdef CONFIG_X86_64
246*b8ff87a6SMatt Fleming 	/* Yes, this is really how we defined it :( */
247*b8ff87a6SMatt Fleming 	addr = efi64_stub_entry - 0x200;
248993c30a0SMatt Fleming #endif
249*b8ff87a6SMatt Fleming 
250*b8ff87a6SMatt Fleming #ifdef CONFIG_EFI_MIXED
251*b8ff87a6SMatt Fleming 	if (efi32_stub_entry != addr)
252*b8ff87a6SMatt Fleming 		die("32-bit and 64-bit EFI entry points do not match\n");
253*b8ff87a6SMatt Fleming #endif
254*b8ff87a6SMatt Fleming 	put_unaligned_le32(addr, &buf[0x264]);
255993c30a0SMatt Fleming }
256993c30a0SMatt Fleming 
257993c30a0SMatt Fleming #else
258993c30a0SMatt Fleming 
259993c30a0SMatt Fleming static inline void update_pecoff_setup_and_reloc(unsigned int) {}
260993c30a0SMatt Fleming static inline void update_pecoff_text(unsigned int, unsigned int) {}
261993c30a0SMatt Fleming static inline void efi_stub_defaults(void) {}
262993c30a0SMatt Fleming static inline void efi_stup_entry_update(void) {}
263993c30a0SMatt Fleming 
264993c30a0SMatt Fleming static inline int reserve_pecoff_reloc_section(int c)
265993c30a0SMatt Fleming {
266993c30a0SMatt Fleming 	return 0;
267993c30a0SMatt Fleming }
268743628e8SJordan Justen #endif /* CONFIG_EFI_STUB */
269743628e8SJordan Justen 
27099f857dbSDavid Woodhouse 
27199f857dbSDavid Woodhouse /*
27299f857dbSDavid Woodhouse  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
27399f857dbSDavid Woodhouse  * but that would mean tools/build would have to be rebuilt every time. It's
27499f857dbSDavid Woodhouse  * not as if parsing it is hard...
27599f857dbSDavid Woodhouse  */
27699f857dbSDavid Woodhouse #define PARSE_ZOFS(p, sym) do { \
27799f857dbSDavid Woodhouse 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
27899f857dbSDavid Woodhouse 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
27999f857dbSDavid Woodhouse } while (0)
28099f857dbSDavid Woodhouse 
28199f857dbSDavid Woodhouse static void parse_zoffset(char *fname)
28299f857dbSDavid Woodhouse {
28399f857dbSDavid Woodhouse 	FILE *file;
28499f857dbSDavid Woodhouse 	char *p;
28599f857dbSDavid Woodhouse 	int c;
28699f857dbSDavid Woodhouse 
28799f857dbSDavid Woodhouse 	file = fopen(fname, "r");
28899f857dbSDavid Woodhouse 	if (!file)
28999f857dbSDavid Woodhouse 		die("Unable to open `%s': %m", fname);
29099f857dbSDavid Woodhouse 	c = fread(buf, 1, sizeof(buf) - 1, file);
29199f857dbSDavid Woodhouse 	if (ferror(file))
29299f857dbSDavid Woodhouse 		die("read-error on `zoffset.h'");
293062f4871SJiri Slaby 	fclose(file);
29499f857dbSDavid Woodhouse 	buf[c] = 0;
29599f857dbSDavid Woodhouse 
29699f857dbSDavid Woodhouse 	p = (char *)buf;
29799f857dbSDavid Woodhouse 
29899f857dbSDavid Woodhouse 	while (p && *p) {
299*b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi32_stub_entry);
300*b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi64_stub_entry);
30199f857dbSDavid Woodhouse 		PARSE_ZOFS(p, efi_pe_entry);
30299f857dbSDavid Woodhouse 		PARSE_ZOFS(p, startup_64);
30399f857dbSDavid Woodhouse 
30499f857dbSDavid Woodhouse 		p = strchr(p, '\n');
30599f857dbSDavid Woodhouse 		while (p && (*p == '\r' || *p == '\n'))
30699f857dbSDavid Woodhouse 			p++;
30799f857dbSDavid Woodhouse 	}
30899f857dbSDavid Woodhouse }
30999f857dbSDavid Woodhouse 
31019d8d79cSThomas Gleixner int main(int argc, char ** argv)
31119d8d79cSThomas Gleixner {
31219d8d79cSThomas Gleixner 	unsigned int i, sz, setup_sectors;
31319d8d79cSThomas Gleixner 	int c;
31419d8d79cSThomas Gleixner 	u32 sys_size;
31519d8d79cSThomas Gleixner 	struct stat sb;
316809373e2SKees Cook 	FILE *file, *dest;
31719d8d79cSThomas Gleixner 	int fd;
31819d8d79cSThomas Gleixner 	void *kernel;
3197d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
32019d8d79cSThomas Gleixner 
321993c30a0SMatt Fleming 	efi_stub_defaults();
32299f857dbSDavid Woodhouse 
323809373e2SKees Cook 	if (argc != 5)
32419d8d79cSThomas Gleixner 		usage();
325809373e2SKees Cook 	parse_zoffset(argv[3]);
326809373e2SKees Cook 
327809373e2SKees Cook 	dest = fopen(argv[4], "w");
328809373e2SKees Cook 	if (!dest)
329809373e2SKees Cook 		die("Unable to write `%s': %m", argv[4]);
33019d8d79cSThomas Gleixner 
33119d8d79cSThomas Gleixner 	/* Copy the setup code */
33219d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
33319d8d79cSThomas Gleixner 	if (!file)
33419d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
33519d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
33619d8d79cSThomas Gleixner 	if (ferror(file))
33719d8d79cSThomas Gleixner 		die("read-error on `setup'");
33819d8d79cSThomas Gleixner 	if (c < 1024)
33919d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
34092f42c50SMatt Fleming 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
34119d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
34219d8d79cSThomas Gleixner 	fclose(file);
34319d8d79cSThomas Gleixner 
344993c30a0SMatt Fleming 	c += reserve_pecoff_reloc_section(c);
345743628e8SJordan Justen 
34619d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
34719d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
34819d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
34919d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
35019d8d79cSThomas Gleixner 	i = setup_sectors*512;
35119d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
35219d8d79cSThomas Gleixner 
353743628e8SJordan Justen 	update_pecoff_setup_and_reloc(i);
354743628e8SJordan Justen 
35519d8d79cSThomas Gleixner 	/* Set the default root device */
35692f42c50SMatt Fleming 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
35719d8d79cSThomas Gleixner 
358809373e2SKees Cook 	printf("Setup is %d bytes (padded to %d bytes).\n", c, i);
35919d8d79cSThomas Gleixner 
36019d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
36119d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
36219d8d79cSThomas Gleixner 	if (fd < 0)
36319d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
36419d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
36519d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
36619d8d79cSThomas Gleixner 	sz = sb.st_size;
367809373e2SKees Cook 	printf("System is %d kB\n", (sz+1023)/1024);
36819d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
36919d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
37019d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
3717d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
3727d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
37319d8d79cSThomas Gleixner 
37419d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
37519d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
37692f42c50SMatt Fleming 	put_unaligned_le32(sys_size, &buf[0x1f4]);
37719d8d79cSThomas Gleixner 
378743628e8SJordan Justen 	update_pecoff_text(setup_sectors * 512, sz + i + ((sys_size * 16) - sz));
37999f857dbSDavid Woodhouse 
380993c30a0SMatt Fleming 	efi_stub_entry_update();
381291f3632SMatt Fleming 
3827d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
383809373e2SKees Cook 	if (fwrite(buf, 1, i, dest) != i)
38419d8d79cSThomas Gleixner 		die("Writing setup failed");
38519d8d79cSThomas Gleixner 
38619d8d79cSThomas Gleixner 	/* Copy the kernel code */
3877d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
388809373e2SKees Cook 	if (fwrite(kernel, 1, sz, dest) != sz)
38919d8d79cSThomas Gleixner 		die("Writing kernel failed");
3907d6e737cSIan Campbell 
3917d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
3927d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
3937d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
394809373e2SKees Cook 		if (fwrite("\0", 1, 1, dest) != 1)
3957d6e737cSIan Campbell 			die("Writing padding failed");
3967d6e737cSIan Campbell 	}
3977d6e737cSIan Campbell 
3987d6e737cSIan Campbell 	/* Write the CRC */
399809373e2SKees Cook 	printf("CRC %x\n", crc);
400a51f4047SH. Peter Anvin 	put_unaligned_le32(crc, buf);
401809373e2SKees Cook 	if (fwrite(buf, 1, 4, dest) != 4)
4027d6e737cSIan Campbell 		die("Writing CRC failed");
4037d6e737cSIan Campbell 
404809373e2SKees Cook 	/* Catch any delayed write failures */
405809373e2SKees Cook 	if (fclose(dest))
406809373e2SKees Cook 		die("Writing image failed");
407809373e2SKees Cook 
40819d8d79cSThomas Gleixner 	close(fd);
40919d8d79cSThomas Gleixner 
41019d8d79cSThomas Gleixner 	/* Everything is OK */
41119d8d79cSThomas Gleixner 	return 0;
41219d8d79cSThomas Gleixner }
413