xref: /linux/arch/x86/boot/tools/build.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
219d8d79cSThomas Gleixner /*
319d8d79cSThomas Gleixner  *  Copyright (C) 1991, 1992  Linus Torvalds
419d8d79cSThomas Gleixner  *  Copyright (C) 1997 Martin Mares
519d8d79cSThomas Gleixner  *  Copyright (C) 2007 H. Peter Anvin
619d8d79cSThomas Gleixner  */
719d8d79cSThomas Gleixner 
819d8d79cSThomas Gleixner /*
9809373e2SKees Cook  * This file builds a disk-image from three different files:
1019d8d79cSThomas Gleixner  *
1119d8d79cSThomas Gleixner  * - setup: 8086 machine code, sets up system parm
1219d8d79cSThomas Gleixner  * - system: 80386 code for actual system
13809373e2SKees Cook  * - zoffset.h: header with ZO_* defines
1419d8d79cSThomas Gleixner  *
15809373e2SKees Cook  * It does some checking that all files are of the correct type, and writes
16809373e2SKees Cook  * the result to the specified destination, removing headers and padding to
17809373e2SKees Cook  * the right amount. It also writes some system data to stdout.
1819d8d79cSThomas Gleixner  */
1919d8d79cSThomas Gleixner 
2019d8d79cSThomas Gleixner /*
2119d8d79cSThomas Gleixner  * Changes by tytso to allow root device specification
2219d8d79cSThomas Gleixner  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
2319d8d79cSThomas Gleixner  * Cross compiling fixes by Gertjan van Wingerde, July 1996
2419d8d79cSThomas Gleixner  * Rewritten by Martin Mares, April 1997
2519d8d79cSThomas Gleixner  * Substantially overhauled by H. Peter Anvin, April 2007
2619d8d79cSThomas Gleixner  */
2719d8d79cSThomas Gleixner 
2819d8d79cSThomas Gleixner #include <stdio.h>
2919d8d79cSThomas Gleixner #include <string.h>
3019d8d79cSThomas Gleixner #include <stdlib.h>
3119d8d79cSThomas Gleixner #include <stdarg.h>
3219d8d79cSThomas Gleixner #include <sys/types.h>
3319d8d79cSThomas Gleixner #include <sys/stat.h>
3419d8d79cSThomas Gleixner #include <unistd.h>
3519d8d79cSThomas Gleixner #include <fcntl.h>
3619d8d79cSThomas Gleixner #include <sys/mman.h>
3792f42c50SMatt Fleming #include <tools/le_byteshift.h>
3819d8d79cSThomas Gleixner 
3919d8d79cSThomas Gleixner typedef unsigned char  u8;
4019d8d79cSThomas Gleixner typedef unsigned short u16;
41a51f4047SH. Peter Anvin typedef unsigned int   u32;
4219d8d79cSThomas Gleixner 
4319d8d79cSThomas Gleixner #define DEFAULT_MAJOR_ROOT 0
4419d8d79cSThomas Gleixner #define DEFAULT_MINOR_ROOT 0
4592f42c50SMatt Fleming #define DEFAULT_ROOT_DEV (DEFAULT_MAJOR_ROOT << 8 | DEFAULT_MINOR_ROOT)
4619d8d79cSThomas Gleixner 
4719d8d79cSThomas Gleixner /* Minimal number of setup sectors */
4819d8d79cSThomas Gleixner #define SETUP_SECT_MIN 5
4919d8d79cSThomas Gleixner #define SETUP_SECT_MAX 64
5019d8d79cSThomas Gleixner 
5119d8d79cSThomas Gleixner /* This must be large enough to hold the entire setup */
5219d8d79cSThomas Gleixner u8 buf[SETUP_SECT_MAX*512];
5319d8d79cSThomas Gleixner 
54743628e8SJordan Justen #define PECOFF_RELOC_RESERVE 0x20
55743628e8SJordan Justen 
56b8ff87a6SMatt Fleming unsigned long efi32_stub_entry;
57b8ff87a6SMatt 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 
146c7fb93ecSMichael Brown static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
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 */
167c7fb93ecSMichael Brown 			put_unaligned_le32(vma, section + 0xc);
168743628e8SJordan Justen 
169743628e8SJordan Justen 			/* section header 'size of initialised data' field */
170c7fb93ecSMichael Brown 			put_unaligned_le32(datasz, 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 
182c7fb93ecSMichael Brown static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
183c7fb93ecSMichael Brown {
184c7fb93ecSMichael Brown 	update_pecoff_section_header_fields(section_name, offset, size, size, offset);
185c7fb93ecSMichael Brown }
186c7fb93ecSMichael Brown 
187743628e8SJordan Justen static void update_pecoff_setup_and_reloc(unsigned int size)
188743628e8SJordan Justen {
189743628e8SJordan Justen 	u32 setup_offset = 0x200;
190743628e8SJordan Justen 	u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
191743628e8SJordan Justen 	u32 setup_size = reloc_offset - setup_offset;
192743628e8SJordan Justen 
193743628e8SJordan Justen 	update_pecoff_section_header(".setup", setup_offset, setup_size);
194743628e8SJordan Justen 	update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
195743628e8SJordan Justen 
196743628e8SJordan Justen 	/*
197743628e8SJordan Justen 	 * Modify .reloc section contents with a single entry. The
198743628e8SJordan Justen 	 * relocation is applied to offset 10 of the relocation section.
199743628e8SJordan Justen 	 */
200743628e8SJordan Justen 	put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
201743628e8SJordan Justen 	put_unaligned_le32(10, &buf[reloc_offset + 4]);
202743628e8SJordan Justen }
203743628e8SJordan Justen 
204743628e8SJordan Justen static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
205743628e8SJordan Justen {
206743628e8SJordan Justen 	unsigned int pe_header;
207743628e8SJordan Justen 	unsigned int text_sz = file_sz - text_start;
208743628e8SJordan Justen 
209743628e8SJordan Justen 	pe_header = get_unaligned_le32(&buf[0x3c]);
210743628e8SJordan Justen 
211743628e8SJordan Justen 	/*
212743628e8SJordan Justen 	 * Size of code: Subtract the size of the first sector (512 bytes)
213743628e8SJordan Justen 	 * which includes the header.
214743628e8SJordan Justen 	 */
215743628e8SJordan Justen 	put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
216743628e8SJordan Justen 
217743628e8SJordan Justen 	/*
21899f857dbSDavid Woodhouse 	 * Address of entry point for PE/COFF executable
219743628e8SJordan Justen 	 */
22099f857dbSDavid Woodhouse 	put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
221743628e8SJordan Justen 
222743628e8SJordan Justen 	update_pecoff_section_header(".text", text_start, text_sz);
223743628e8SJordan Justen }
224743628e8SJordan Justen 
225c7fb93ecSMichael Brown static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz)
226c7fb93ecSMichael Brown {
227c7fb93ecSMichael Brown 	unsigned int pe_header;
228c7fb93ecSMichael Brown 	unsigned int bss_sz = init_sz - file_sz;
229c7fb93ecSMichael Brown 
230c7fb93ecSMichael Brown 	pe_header = get_unaligned_le32(&buf[0x3c]);
231c7fb93ecSMichael Brown 
232c7fb93ecSMichael Brown 	/* Size of uninitialized data */
233c7fb93ecSMichael Brown 	put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]);
234c7fb93ecSMichael Brown 
235c7fb93ecSMichael Brown 	/* Size of image */
236c7fb93ecSMichael Brown 	put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
237c7fb93ecSMichael Brown 
238c7fb93ecSMichael Brown 	update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0);
239c7fb93ecSMichael Brown }
240c7fb93ecSMichael Brown 
241993c30a0SMatt Fleming static int reserve_pecoff_reloc_section(int c)
242993c30a0SMatt Fleming {
243993c30a0SMatt Fleming 	/* Reserve 0x20 bytes for .reloc section */
244993c30a0SMatt Fleming 	memset(buf+c, 0, PECOFF_RELOC_RESERVE);
245993c30a0SMatt Fleming 	return PECOFF_RELOC_RESERVE;
246993c30a0SMatt Fleming }
247993c30a0SMatt Fleming 
248993c30a0SMatt Fleming static void efi_stub_defaults(void)
249993c30a0SMatt Fleming {
250993c30a0SMatt Fleming 	/* Defaults for old kernel */
251993c30a0SMatt Fleming #ifdef CONFIG_X86_32
252993c30a0SMatt Fleming 	efi_pe_entry = 0x10;
253993c30a0SMatt Fleming #else
254993c30a0SMatt Fleming 	efi_pe_entry = 0x210;
255993c30a0SMatt Fleming 	startup_64 = 0x200;
256993c30a0SMatt Fleming #endif
257993c30a0SMatt Fleming }
258993c30a0SMatt Fleming 
259993c30a0SMatt Fleming static void efi_stub_entry_update(void)
260993c30a0SMatt Fleming {
261b8ff87a6SMatt Fleming 	unsigned long addr = efi32_stub_entry;
262b8ff87a6SMatt Fleming 
263b8ff87a6SMatt Fleming #ifdef CONFIG_X86_64
264b8ff87a6SMatt Fleming 	/* Yes, this is really how we defined it :( */
265b8ff87a6SMatt Fleming 	addr = efi64_stub_entry - 0x200;
266993c30a0SMatt Fleming #endif
267b8ff87a6SMatt Fleming 
268b8ff87a6SMatt Fleming #ifdef CONFIG_EFI_MIXED
269b8ff87a6SMatt Fleming 	if (efi32_stub_entry != addr)
270b8ff87a6SMatt Fleming 		die("32-bit and 64-bit EFI entry points do not match\n");
271b8ff87a6SMatt Fleming #endif
272b8ff87a6SMatt Fleming 	put_unaligned_le32(addr, &buf[0x264]);
273993c30a0SMatt Fleming }
274993c30a0SMatt Fleming 
275993c30a0SMatt Fleming #else
276993c30a0SMatt Fleming 
277b663a685SMatt Fleming static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
278b663a685SMatt Fleming static inline void update_pecoff_text(unsigned int text_start,
279b663a685SMatt Fleming 				      unsigned int file_sz) {}
280c7fb93ecSMichael Brown static inline void update_pecoff_bss(unsigned int file_sz,
281c7fb93ecSMichael Brown 				     unsigned int init_sz) {}
282993c30a0SMatt Fleming static inline void efi_stub_defaults(void) {}
283b663a685SMatt Fleming static inline void efi_stub_entry_update(void) {}
284993c30a0SMatt Fleming 
285993c30a0SMatt Fleming static inline int reserve_pecoff_reloc_section(int c)
286993c30a0SMatt Fleming {
287993c30a0SMatt Fleming 	return 0;
288993c30a0SMatt Fleming }
289743628e8SJordan Justen #endif /* CONFIG_EFI_STUB */
290743628e8SJordan Justen 
29199f857dbSDavid Woodhouse 
29299f857dbSDavid Woodhouse /*
29399f857dbSDavid Woodhouse  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
29499f857dbSDavid Woodhouse  * but that would mean tools/build would have to be rebuilt every time. It's
29599f857dbSDavid Woodhouse  * not as if parsing it is hard...
29699f857dbSDavid Woodhouse  */
29799f857dbSDavid Woodhouse #define PARSE_ZOFS(p, sym) do { \
29899f857dbSDavid Woodhouse 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
29999f857dbSDavid Woodhouse 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
30099f857dbSDavid Woodhouse } while (0)
30199f857dbSDavid Woodhouse 
30299f857dbSDavid Woodhouse static void parse_zoffset(char *fname)
30399f857dbSDavid Woodhouse {
30499f857dbSDavid Woodhouse 	FILE *file;
30599f857dbSDavid Woodhouse 	char *p;
30699f857dbSDavid Woodhouse 	int c;
30799f857dbSDavid Woodhouse 
30899f857dbSDavid Woodhouse 	file = fopen(fname, "r");
30999f857dbSDavid Woodhouse 	if (!file)
31099f857dbSDavid Woodhouse 		die("Unable to open `%s': %m", fname);
31199f857dbSDavid Woodhouse 	c = fread(buf, 1, sizeof(buf) - 1, file);
31299f857dbSDavid Woodhouse 	if (ferror(file))
31399f857dbSDavid Woodhouse 		die("read-error on `zoffset.h'");
314062f4871SJiri Slaby 	fclose(file);
31599f857dbSDavid Woodhouse 	buf[c] = 0;
31699f857dbSDavid Woodhouse 
31799f857dbSDavid Woodhouse 	p = (char *)buf;
31899f857dbSDavid Woodhouse 
31999f857dbSDavid Woodhouse 	while (p && *p) {
320b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi32_stub_entry);
321b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi64_stub_entry);
32299f857dbSDavid Woodhouse 		PARSE_ZOFS(p, efi_pe_entry);
32399f857dbSDavid Woodhouse 		PARSE_ZOFS(p, startup_64);
32499f857dbSDavid Woodhouse 
32599f857dbSDavid Woodhouse 		p = strchr(p, '\n');
32699f857dbSDavid Woodhouse 		while (p && (*p == '\r' || *p == '\n'))
32799f857dbSDavid Woodhouse 			p++;
32899f857dbSDavid Woodhouse 	}
32999f857dbSDavid Woodhouse }
33099f857dbSDavid Woodhouse 
33119d8d79cSThomas Gleixner int main(int argc, char ** argv)
33219d8d79cSThomas Gleixner {
333c7fb93ecSMichael Brown 	unsigned int i, sz, setup_sectors, init_sz;
33419d8d79cSThomas Gleixner 	int c;
33519d8d79cSThomas Gleixner 	u32 sys_size;
33619d8d79cSThomas Gleixner 	struct stat sb;
337809373e2SKees Cook 	FILE *file, *dest;
33819d8d79cSThomas Gleixner 	int fd;
33919d8d79cSThomas Gleixner 	void *kernel;
3407d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
34119d8d79cSThomas Gleixner 
342993c30a0SMatt Fleming 	efi_stub_defaults();
34399f857dbSDavid Woodhouse 
344809373e2SKees Cook 	if (argc != 5)
34519d8d79cSThomas Gleixner 		usage();
346809373e2SKees Cook 	parse_zoffset(argv[3]);
347809373e2SKees Cook 
348809373e2SKees Cook 	dest = fopen(argv[4], "w");
349809373e2SKees Cook 	if (!dest)
350809373e2SKees Cook 		die("Unable to write `%s': %m", argv[4]);
35119d8d79cSThomas Gleixner 
35219d8d79cSThomas Gleixner 	/* Copy the setup code */
35319d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
35419d8d79cSThomas Gleixner 	if (!file)
35519d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
35619d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
35719d8d79cSThomas Gleixner 	if (ferror(file))
35819d8d79cSThomas Gleixner 		die("read-error on `setup'");
35919d8d79cSThomas Gleixner 	if (c < 1024)
36019d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
36192f42c50SMatt Fleming 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
36219d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
36319d8d79cSThomas Gleixner 	fclose(file);
36419d8d79cSThomas Gleixner 
365993c30a0SMatt Fleming 	c += reserve_pecoff_reloc_section(c);
366743628e8SJordan Justen 
36719d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
36819d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
36919d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
37019d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
37119d8d79cSThomas Gleixner 	i = setup_sectors*512;
37219d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
37319d8d79cSThomas Gleixner 
374743628e8SJordan Justen 	update_pecoff_setup_and_reloc(i);
375743628e8SJordan Justen 
37619d8d79cSThomas Gleixner 	/* Set the default root device */
37792f42c50SMatt Fleming 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
37819d8d79cSThomas Gleixner 
379809373e2SKees Cook 	printf("Setup is %d bytes (padded to %d bytes).\n", c, i);
38019d8d79cSThomas Gleixner 
38119d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
38219d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
38319d8d79cSThomas Gleixner 	if (fd < 0)
38419d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
38519d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
38619d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
38719d8d79cSThomas Gleixner 	sz = sb.st_size;
388809373e2SKees Cook 	printf("System is %d kB\n", (sz+1023)/1024);
38919d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
39019d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
39119d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
3927d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
3937d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
39419d8d79cSThomas Gleixner 
39519d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
39619d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
39792f42c50SMatt Fleming 	put_unaligned_le32(sys_size, &buf[0x1f4]);
39819d8d79cSThomas Gleixner 
399c7fb93ecSMichael Brown 	update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
400c7fb93ecSMichael Brown 	init_sz = get_unaligned_le32(&buf[0x260]);
401c7fb93ecSMichael Brown 	update_pecoff_bss(i + (sys_size * 16), init_sz);
40299f857dbSDavid Woodhouse 
403993c30a0SMatt Fleming 	efi_stub_entry_update();
404291f3632SMatt Fleming 
4057d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
406809373e2SKees Cook 	if (fwrite(buf, 1, i, dest) != i)
40719d8d79cSThomas Gleixner 		die("Writing setup failed");
40819d8d79cSThomas Gleixner 
40919d8d79cSThomas Gleixner 	/* Copy the kernel code */
4107d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
411809373e2SKees Cook 	if (fwrite(kernel, 1, sz, dest) != sz)
41219d8d79cSThomas Gleixner 		die("Writing kernel failed");
4137d6e737cSIan Campbell 
4147d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
4157d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
4167d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
417809373e2SKees Cook 		if (fwrite("\0", 1, 1, dest) != 1)
4187d6e737cSIan Campbell 			die("Writing padding failed");
4197d6e737cSIan Campbell 	}
4207d6e737cSIan Campbell 
4217d6e737cSIan Campbell 	/* Write the CRC */
422809373e2SKees Cook 	printf("CRC %x\n", crc);
423a51f4047SH. Peter Anvin 	put_unaligned_le32(crc, buf);
424809373e2SKees Cook 	if (fwrite(buf, 1, 4, dest) != 4)
4257d6e737cSIan Campbell 		die("Writing CRC failed");
4267d6e737cSIan Campbell 
427809373e2SKees Cook 	/* Catch any delayed write failures */
428809373e2SKees Cook 	if (fclose(dest))
429809373e2SKees Cook 		die("Writing image failed");
430809373e2SKees Cook 
43119d8d79cSThomas Gleixner 	close(fd);
43219d8d79cSThomas Gleixner 
43319d8d79cSThomas Gleixner 	/* Everything is OK */
43419d8d79cSThomas Gleixner 	return 0;
43519d8d79cSThomas Gleixner }
436