xref: /linux/arch/x86/boot/tools/build.c (revision 8eace5b3555606e684739bef5bcdfcfe68235257)
1b2441318SGreg 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 
5697aa2765SArd Biesheuvel #ifdef CONFIG_EFI_MIXED
5797aa2765SArd Biesheuvel #define PECOFF_COMPAT_RESERVE 0x20
5897aa2765SArd Biesheuvel #else
5997aa2765SArd Biesheuvel #define PECOFF_COMPAT_RESERVE 0x0
6097aa2765SArd Biesheuvel #endif
6197aa2765SArd Biesheuvel 
62e78d334aSArvind Sankar static unsigned long efi32_stub_entry;
63e78d334aSArvind Sankar static unsigned long efi64_stub_entry;
64e78d334aSArvind Sankar static unsigned long efi_pe_entry;
65e78d334aSArvind Sankar static unsigned long efi32_pe_entry;
66e78d334aSArvind Sankar static unsigned long kernel_info;
67e78d334aSArvind Sankar static unsigned long startup_64;
68e78d334aSArvind Sankar static unsigned long _end;
6999f857dbSDavid Woodhouse 
707d6e737cSIan Campbell /*----------------------------------------------------------------------*/
717d6e737cSIan Campbell 
727d6e737cSIan Campbell static const u32 crctab32[] = {
737d6e737cSIan Campbell 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
747d6e737cSIan Campbell 	0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
757d6e737cSIan Campbell 	0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
767d6e737cSIan Campbell 	0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
777d6e737cSIan Campbell 	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
787d6e737cSIan Campbell 	0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
797d6e737cSIan Campbell 	0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
807d6e737cSIan Campbell 	0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
817d6e737cSIan Campbell 	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
827d6e737cSIan Campbell 	0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
837d6e737cSIan Campbell 	0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
847d6e737cSIan Campbell 	0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
857d6e737cSIan Campbell 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
867d6e737cSIan Campbell 	0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
877d6e737cSIan Campbell 	0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
887d6e737cSIan Campbell 	0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
897d6e737cSIan Campbell 	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
907d6e737cSIan Campbell 	0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
917d6e737cSIan Campbell 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
927d6e737cSIan Campbell 	0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
937d6e737cSIan Campbell 	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
947d6e737cSIan Campbell 	0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
957d6e737cSIan Campbell 	0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
967d6e737cSIan Campbell 	0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
977d6e737cSIan Campbell 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
987d6e737cSIan Campbell 	0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
997d6e737cSIan Campbell 	0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
1007d6e737cSIan Campbell 	0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
1017d6e737cSIan Campbell 	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
1027d6e737cSIan Campbell 	0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
1037d6e737cSIan Campbell 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
1047d6e737cSIan Campbell 	0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
1057d6e737cSIan Campbell 	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
1067d6e737cSIan Campbell 	0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
1077d6e737cSIan Campbell 	0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
1087d6e737cSIan Campbell 	0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
1097d6e737cSIan Campbell 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
1107d6e737cSIan Campbell 	0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
1117d6e737cSIan Campbell 	0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
1127d6e737cSIan Campbell 	0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
1137d6e737cSIan Campbell 	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
1147d6e737cSIan Campbell 	0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
1157d6e737cSIan Campbell 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
1167d6e737cSIan Campbell 	0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
1177d6e737cSIan Campbell 	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
1187d6e737cSIan Campbell 	0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
1197d6e737cSIan Campbell 	0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
1207d6e737cSIan Campbell 	0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
1217d6e737cSIan Campbell 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
1227d6e737cSIan Campbell 	0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
1237d6e737cSIan Campbell 	0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
1247d6e737cSIan Campbell 	0x2d02ef8d
1257d6e737cSIan Campbell };
1267d6e737cSIan Campbell 
1277d6e737cSIan Campbell static u32 partial_crc32_one(u8 c, u32 crc)
1287d6e737cSIan Campbell {
1297d6e737cSIan Campbell 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1307d6e737cSIan Campbell }
1317d6e737cSIan Campbell 
1327d6e737cSIan Campbell static u32 partial_crc32(const u8 *s, int len, u32 crc)
1337d6e737cSIan Campbell {
1347d6e737cSIan Campbell 	while (len--)
1357d6e737cSIan Campbell 		crc = partial_crc32_one(*s++, crc);
1367d6e737cSIan Campbell 	return crc;
1377d6e737cSIan Campbell }
1387d6e737cSIan Campbell 
13919d8d79cSThomas Gleixner static void die(const char * str, ...)
14019d8d79cSThomas Gleixner {
14119d8d79cSThomas Gleixner 	va_list args;
14219d8d79cSThomas Gleixner 	va_start(args, str);
14319d8d79cSThomas Gleixner 	vfprintf(stderr, str, args);
14469be4efeSMattias Jacobsson 	va_end(args);
14519d8d79cSThomas Gleixner 	fputc('\n', stderr);
14619d8d79cSThomas Gleixner 	exit(1);
14719d8d79cSThomas Gleixner }
14819d8d79cSThomas Gleixner 
14919d8d79cSThomas Gleixner static void usage(void)
15019d8d79cSThomas Gleixner {
151809373e2SKees Cook 	die("Usage: build setup system zoffset.h image");
15219d8d79cSThomas Gleixner }
15319d8d79cSThomas Gleixner 
154743628e8SJordan Justen #ifdef CONFIG_EFI_STUB
155743628e8SJordan Justen 
156c7fb93ecSMichael Brown static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
157743628e8SJordan Justen {
158743628e8SJordan Justen 	unsigned int pe_header;
159743628e8SJordan Justen 	unsigned short num_sections;
160743628e8SJordan Justen 	u8 *section;
161743628e8SJordan Justen 
162743628e8SJordan Justen 	pe_header = get_unaligned_le32(&buf[0x3c]);
163743628e8SJordan Justen 	num_sections = get_unaligned_le16(&buf[pe_header + 6]);
164743628e8SJordan Justen 
165743628e8SJordan Justen #ifdef CONFIG_X86_32
166743628e8SJordan Justen 	section = &buf[pe_header + 0xa8];
167743628e8SJordan Justen #else
168743628e8SJordan Justen 	section = &buf[pe_header + 0xb8];
169743628e8SJordan Justen #endif
170743628e8SJordan Justen 
171743628e8SJordan Justen 	while (num_sections > 0) {
172743628e8SJordan Justen 		if (strncmp((char*)section, section_name, 8) == 0) {
173743628e8SJordan Justen 			/* section header size field */
174743628e8SJordan Justen 			put_unaligned_le32(size, section + 0x8);
175743628e8SJordan Justen 
176743628e8SJordan Justen 			/* section header vma field */
177c7fb93ecSMichael Brown 			put_unaligned_le32(vma, section + 0xc);
178743628e8SJordan Justen 
179743628e8SJordan Justen 			/* section header 'size of initialised data' field */
180c7fb93ecSMichael Brown 			put_unaligned_le32(datasz, section + 0x10);
181743628e8SJordan Justen 
182743628e8SJordan Justen 			/* section header 'file offset' field */
183743628e8SJordan Justen 			put_unaligned_le32(offset, section + 0x14);
184743628e8SJordan Justen 
185743628e8SJordan Justen 			break;
186743628e8SJordan Justen 		}
187743628e8SJordan Justen 		section += 0x28;
188743628e8SJordan Justen 		num_sections--;
189743628e8SJordan Justen 	}
190743628e8SJordan Justen }
191743628e8SJordan Justen 
192c7fb93ecSMichael Brown static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
193c7fb93ecSMichael Brown {
194c7fb93ecSMichael Brown 	update_pecoff_section_header_fields(section_name, offset, size, size, offset);
195c7fb93ecSMichael Brown }
196c7fb93ecSMichael Brown 
197743628e8SJordan Justen static void update_pecoff_setup_and_reloc(unsigned int size)
198743628e8SJordan Justen {
199743628e8SJordan Justen 	u32 setup_offset = 0x200;
20097aa2765SArd Biesheuvel 	u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
20197aa2765SArd Biesheuvel #ifdef CONFIG_EFI_MIXED
20297aa2765SArd Biesheuvel 	u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
20397aa2765SArd Biesheuvel #endif
204743628e8SJordan Justen 	u32 setup_size = reloc_offset - setup_offset;
205743628e8SJordan Justen 
206743628e8SJordan Justen 	update_pecoff_section_header(".setup", setup_offset, setup_size);
207743628e8SJordan Justen 	update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
208743628e8SJordan Justen 
209743628e8SJordan Justen 	/*
210743628e8SJordan Justen 	 * Modify .reloc section contents with a single entry. The
211743628e8SJordan Justen 	 * relocation is applied to offset 10 of the relocation section.
212743628e8SJordan Justen 	 */
213743628e8SJordan Justen 	put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
214743628e8SJordan Justen 	put_unaligned_le32(10, &buf[reloc_offset + 4]);
21597aa2765SArd Biesheuvel 
21697aa2765SArd Biesheuvel #ifdef CONFIG_EFI_MIXED
21797aa2765SArd Biesheuvel 	update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
21897aa2765SArd Biesheuvel 
21997aa2765SArd Biesheuvel 	/*
22097aa2765SArd Biesheuvel 	 * Put the IA-32 machine type (0x14c) and the associated entry point
22197aa2765SArd Biesheuvel 	 * address in the .compat section, so loaders can figure out which other
22297aa2765SArd Biesheuvel 	 * execution modes this image supports.
22397aa2765SArd Biesheuvel 	 */
22497aa2765SArd Biesheuvel 	buf[compat_offset] = 0x1;
22597aa2765SArd Biesheuvel 	buf[compat_offset + 1] = 0x8;
22697aa2765SArd Biesheuvel 	put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
22797aa2765SArd Biesheuvel 	put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
22897aa2765SArd Biesheuvel #endif
229743628e8SJordan Justen }
230743628e8SJordan Justen 
231*8eace5b3SArd Biesheuvel static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
232743628e8SJordan Justen {
233743628e8SJordan Justen 	unsigned int pe_header;
234743628e8SJordan Justen 	unsigned int text_sz = file_sz - text_start;
235*8eace5b3SArd Biesheuvel 	unsigned int bss_sz = _end - text_sz;
236743628e8SJordan Justen 
237743628e8SJordan Justen 	pe_header = get_unaligned_le32(&buf[0x3c]);
238743628e8SJordan Justen 
23997aa2765SArd Biesheuvel 	/*
240743628e8SJordan Justen 	 * Size of code: Subtract the size of the first sector (512 bytes)
241743628e8SJordan Justen 	 * which includes the header.
242743628e8SJordan Justen 	 */
243832187f0SArd Biesheuvel 	put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
244832187f0SArd Biesheuvel 
245832187f0SArd Biesheuvel 	/* Size of image */
246*8eace5b3SArd Biesheuvel 	put_unaligned_le32(file_sz + bss_sz, &buf[pe_header + 0x50]);
247743628e8SJordan Justen 
248743628e8SJordan Justen 	/*
24999f857dbSDavid Woodhouse 	 * Address of entry point for PE/COFF executable
250743628e8SJordan Justen 	 */
25199f857dbSDavid Woodhouse 	put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
252743628e8SJordan Justen 
253832187f0SArd Biesheuvel 	update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
254832187f0SArd Biesheuvel 					    text_sz, text_start);
255c7fb93ecSMichael Brown }
256c7fb93ecSMichael Brown 
257993c30a0SMatt Fleming static int reserve_pecoff_reloc_section(int c)
258993c30a0SMatt Fleming {
259993c30a0SMatt Fleming 	/* Reserve 0x20 bytes for .reloc section */
260993c30a0SMatt Fleming 	memset(buf+c, 0, PECOFF_RELOC_RESERVE);
261993c30a0SMatt Fleming 	return PECOFF_RELOC_RESERVE;
262993c30a0SMatt Fleming }
263993c30a0SMatt Fleming 
264993c30a0SMatt Fleming static void efi_stub_defaults(void)
265993c30a0SMatt Fleming {
266993c30a0SMatt Fleming 	/* Defaults for old kernel */
267993c30a0SMatt Fleming #ifdef CONFIG_X86_32
268993c30a0SMatt Fleming 	efi_pe_entry = 0x10;
269993c30a0SMatt Fleming #else
270993c30a0SMatt Fleming 	efi_pe_entry = 0x210;
271993c30a0SMatt Fleming 	startup_64 = 0x200;
272993c30a0SMatt Fleming #endif
273993c30a0SMatt Fleming }
274993c30a0SMatt Fleming 
275993c30a0SMatt Fleming static void efi_stub_entry_update(void)
276993c30a0SMatt Fleming {
277b8ff87a6SMatt Fleming 	unsigned long addr = efi32_stub_entry;
278b8ff87a6SMatt Fleming 
279cc3fdda2SArd Biesheuvel #ifdef CONFIG_EFI_HANDOVER_PROTOCOL
280b8ff87a6SMatt Fleming #ifdef CONFIG_X86_64
281b8ff87a6SMatt Fleming 	/* Yes, this is really how we defined it :( */
282b8ff87a6SMatt Fleming 	addr = efi64_stub_entry - 0x200;
283993c30a0SMatt Fleming #endif
284b8ff87a6SMatt Fleming 
285b8ff87a6SMatt Fleming #ifdef CONFIG_EFI_MIXED
286b8ff87a6SMatt Fleming 	if (efi32_stub_entry != addr)
287b8ff87a6SMatt Fleming 		die("32-bit and 64-bit EFI entry points do not match\n");
288b8ff87a6SMatt Fleming #endif
289cc3fdda2SArd Biesheuvel #endif
290b8ff87a6SMatt Fleming 	put_unaligned_le32(addr, &buf[0x264]);
291993c30a0SMatt Fleming }
292993c30a0SMatt Fleming 
293993c30a0SMatt Fleming #else
294993c30a0SMatt Fleming 
295b663a685SMatt Fleming static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
296b663a685SMatt Fleming static inline void update_pecoff_text(unsigned int text_start,
297*8eace5b3SArd Biesheuvel 				      unsigned int file_sz) {}
298993c30a0SMatt Fleming static inline void efi_stub_defaults(void) {}
299b663a685SMatt Fleming static inline void efi_stub_entry_update(void) {}
300993c30a0SMatt Fleming 
301993c30a0SMatt Fleming static inline int reserve_pecoff_reloc_section(int c)
302993c30a0SMatt Fleming {
303993c30a0SMatt Fleming 	return 0;
304993c30a0SMatt Fleming }
305743628e8SJordan Justen #endif /* CONFIG_EFI_STUB */
306743628e8SJordan Justen 
30797aa2765SArd Biesheuvel static int reserve_pecoff_compat_section(int c)
30897aa2765SArd Biesheuvel {
30997aa2765SArd Biesheuvel 	/* Reserve 0x20 bytes for .compat section */
31097aa2765SArd Biesheuvel 	memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
31197aa2765SArd Biesheuvel 	return PECOFF_COMPAT_RESERVE;
31297aa2765SArd Biesheuvel }
31399f857dbSDavid Woodhouse 
31499f857dbSDavid Woodhouse /*
31599f857dbSDavid Woodhouse  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
31699f857dbSDavid Woodhouse  * but that would mean tools/build would have to be rebuilt every time. It's
31799f857dbSDavid Woodhouse  * not as if parsing it is hard...
31899f857dbSDavid Woodhouse  */
31999f857dbSDavid Woodhouse #define PARSE_ZOFS(p, sym) do { \
32099f857dbSDavid Woodhouse 	if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym)))	\
32199f857dbSDavid Woodhouse 		sym = strtoul(p + 11 + sizeof(#sym), NULL, 16);		\
32299f857dbSDavid Woodhouse } while (0)
32399f857dbSDavid Woodhouse 
32499f857dbSDavid Woodhouse static void parse_zoffset(char *fname)
32599f857dbSDavid Woodhouse {
32699f857dbSDavid Woodhouse 	FILE *file;
32799f857dbSDavid Woodhouse 	char *p;
32899f857dbSDavid Woodhouse 	int c;
32999f857dbSDavid Woodhouse 
33099f857dbSDavid Woodhouse 	file = fopen(fname, "r");
33199f857dbSDavid Woodhouse 	if (!file)
33299f857dbSDavid Woodhouse 		die("Unable to open `%s': %m", fname);
33399f857dbSDavid Woodhouse 	c = fread(buf, 1, sizeof(buf) - 1, file);
33499f857dbSDavid Woodhouse 	if (ferror(file))
33599f857dbSDavid Woodhouse 		die("read-error on `zoffset.h'");
336062f4871SJiri Slaby 	fclose(file);
33799f857dbSDavid Woodhouse 	buf[c] = 0;
33899f857dbSDavid Woodhouse 
33999f857dbSDavid Woodhouse 	p = (char *)buf;
34099f857dbSDavid Woodhouse 
34199f857dbSDavid Woodhouse 	while (p && *p) {
342b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi32_stub_entry);
343b8ff87a6SMatt Fleming 		PARSE_ZOFS(p, efi64_stub_entry);
34499f857dbSDavid Woodhouse 		PARSE_ZOFS(p, efi_pe_entry);
34597aa2765SArd Biesheuvel 		PARSE_ZOFS(p, efi32_pe_entry);
3462c33c27fSDaniel Kiper 		PARSE_ZOFS(p, kernel_info);
34799f857dbSDavid Woodhouse 		PARSE_ZOFS(p, startup_64);
348964124a9SArvind Sankar 		PARSE_ZOFS(p, _end);
34999f857dbSDavid Woodhouse 
35099f857dbSDavid Woodhouse 		p = strchr(p, '\n');
35199f857dbSDavid Woodhouse 		while (p && (*p == '\r' || *p == '\n'))
35299f857dbSDavid Woodhouse 			p++;
35399f857dbSDavid Woodhouse 	}
35499f857dbSDavid Woodhouse }
35599f857dbSDavid Woodhouse 
35619d8d79cSThomas Gleixner int main(int argc, char ** argv)
35719d8d79cSThomas Gleixner {
358*8eace5b3SArd Biesheuvel 	unsigned int i, sz, setup_sectors;
35919d8d79cSThomas Gleixner 	int c;
36019d8d79cSThomas Gleixner 	u32 sys_size;
36119d8d79cSThomas Gleixner 	struct stat sb;
362809373e2SKees Cook 	FILE *file, *dest;
36319d8d79cSThomas Gleixner 	int fd;
36419d8d79cSThomas Gleixner 	void *kernel;
3657d6e737cSIan Campbell 	u32 crc = 0xffffffffUL;
36619d8d79cSThomas Gleixner 
367993c30a0SMatt Fleming 	efi_stub_defaults();
36899f857dbSDavid Woodhouse 
369809373e2SKees Cook 	if (argc != 5)
37019d8d79cSThomas Gleixner 		usage();
371809373e2SKees Cook 	parse_zoffset(argv[3]);
372809373e2SKees Cook 
373809373e2SKees Cook 	dest = fopen(argv[4], "w");
374809373e2SKees Cook 	if (!dest)
375809373e2SKees Cook 		die("Unable to write `%s': %m", argv[4]);
37619d8d79cSThomas Gleixner 
37719d8d79cSThomas Gleixner 	/* Copy the setup code */
37819d8d79cSThomas Gleixner 	file = fopen(argv[1], "r");
37919d8d79cSThomas Gleixner 	if (!file)
38019d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[1]);
38119d8d79cSThomas Gleixner 	c = fread(buf, 1, sizeof(buf), file);
38219d8d79cSThomas Gleixner 	if (ferror(file))
38319d8d79cSThomas Gleixner 		die("read-error on `setup'");
38419d8d79cSThomas Gleixner 	if (c < 1024)
38519d8d79cSThomas Gleixner 		die("The setup must be at least 1024 bytes");
38692f42c50SMatt Fleming 	if (get_unaligned_le16(&buf[510]) != 0xAA55)
38719d8d79cSThomas Gleixner 		die("Boot block hasn't got boot flag (0xAA55)");
38819d8d79cSThomas Gleixner 	fclose(file);
38919d8d79cSThomas Gleixner 
39097aa2765SArd Biesheuvel 	c += reserve_pecoff_compat_section(c);
391993c30a0SMatt Fleming 	c += reserve_pecoff_reloc_section(c);
392743628e8SJordan Justen 
39319d8d79cSThomas Gleixner 	/* Pad unused space with zeros */
39419d8d79cSThomas Gleixner 	setup_sectors = (c + 511) / 512;
39519d8d79cSThomas Gleixner 	if (setup_sectors < SETUP_SECT_MIN)
39619d8d79cSThomas Gleixner 		setup_sectors = SETUP_SECT_MIN;
39719d8d79cSThomas Gleixner 	i = setup_sectors*512;
39819d8d79cSThomas Gleixner 	memset(buf+c, 0, i-c);
39919d8d79cSThomas Gleixner 
400743628e8SJordan Justen 	update_pecoff_setup_and_reloc(i);
401743628e8SJordan Justen 
40219d8d79cSThomas Gleixner 	/* Set the default root device */
40392f42c50SMatt Fleming 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
40419d8d79cSThomas Gleixner 
40519d8d79cSThomas Gleixner 	/* Open and stat the kernel file */
40619d8d79cSThomas Gleixner 	fd = open(argv[2], O_RDONLY);
40719d8d79cSThomas Gleixner 	if (fd < 0)
40819d8d79cSThomas Gleixner 		die("Unable to open `%s': %m", argv[2]);
40919d8d79cSThomas Gleixner 	if (fstat(fd, &sb))
41019d8d79cSThomas Gleixner 		die("Unable to stat `%s': %m", argv[2]);
41119d8d79cSThomas Gleixner 	sz = sb.st_size;
41219d8d79cSThomas Gleixner 	kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
41319d8d79cSThomas Gleixner 	if (kernel == MAP_FAILED)
41419d8d79cSThomas Gleixner 		die("Unable to mmap '%s': %m", argv[2]);
4157d6e737cSIan Campbell 	/* Number of 16-byte paragraphs, including space for a 4-byte CRC */
4167d6e737cSIan Campbell 	sys_size = (sz + 15 + 4) / 16;
4179c1442a9SBen Hutchings #ifdef CONFIG_EFI_STUB
4189c1442a9SBen Hutchings 	/*
4199c1442a9SBen Hutchings 	 * COFF requires minimum 32-byte alignment of sections, and
4209c1442a9SBen Hutchings 	 * adding a signature is problematic without that alignment.
4219c1442a9SBen Hutchings 	 */
4229c1442a9SBen Hutchings 	sys_size = (sys_size + 1) & ~1;
4239c1442a9SBen Hutchings #endif
42419d8d79cSThomas Gleixner 
42519d8d79cSThomas Gleixner 	/* Patch the setup code with the appropriate size parameters */
42619d8d79cSThomas Gleixner 	buf[0x1f1] = setup_sectors-1;
42792f42c50SMatt Fleming 	put_unaligned_le32(sys_size, &buf[0x1f4]);
42819d8d79cSThomas Gleixner 
429*8eace5b3SArd Biesheuvel 	update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
43099f857dbSDavid Woodhouse 
431993c30a0SMatt Fleming 	efi_stub_entry_update();
4322c33c27fSDaniel Kiper 	/* Update kernel_info offset. */
4332c33c27fSDaniel Kiper 	put_unaligned_le32(kernel_info, &buf[0x268]);
4342c33c27fSDaniel Kiper 
4357d6e737cSIan Campbell 	crc = partial_crc32(buf, i, crc);
436809373e2SKees Cook 	if (fwrite(buf, 1, i, dest) != i)
43719d8d79cSThomas Gleixner 		die("Writing setup failed");
43819d8d79cSThomas Gleixner 
43919d8d79cSThomas Gleixner 	/* Copy the kernel code */
4407d6e737cSIan Campbell 	crc = partial_crc32(kernel, sz, crc);
441809373e2SKees Cook 	if (fwrite(kernel, 1, sz, dest) != sz)
44219d8d79cSThomas Gleixner 		die("Writing kernel failed");
4437d6e737cSIan Campbell 
4447d6e737cSIan Campbell 	/* Add padding leaving 4 bytes for the checksum */
4457d6e737cSIan Campbell 	while (sz++ < (sys_size*16) - 4) {
4467d6e737cSIan Campbell 		crc = partial_crc32_one('\0', crc);
447809373e2SKees Cook 		if (fwrite("\0", 1, 1, dest) != 1)
4487d6e737cSIan Campbell 			die("Writing padding failed");
4497d6e737cSIan Campbell 	}
4507d6e737cSIan Campbell 
4517d6e737cSIan Campbell 	/* Write the CRC */
452a51f4047SH. Peter Anvin 	put_unaligned_le32(crc, buf);
453809373e2SKees Cook 	if (fwrite(buf, 1, 4, dest) != 4)
4547d6e737cSIan Campbell 		die("Writing CRC failed");
4557d6e737cSIan Campbell 
456809373e2SKees Cook 	/* Catch any delayed write failures */
457809373e2SKees Cook 	if (fclose(dest))
458809373e2SKees Cook 		die("Writing image failed");
459809373e2SKees Cook 
46019d8d79cSThomas Gleixner 	close(fd);
46119d8d79cSThomas Gleixner 
46219d8d79cSThomas Gleixner 	/* Everything is OK */
46319d8d79cSThomas Gleixner 	return 0;
46419d8d79cSThomas Gleixner }
465