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