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 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; 394*9c1442a9SBen Hutchings #ifdef CONFIG_EFI_STUB 395*9c1442a9SBen Hutchings /* 396*9c1442a9SBen Hutchings * COFF requires minimum 32-byte alignment of sections, and 397*9c1442a9SBen Hutchings * adding a signature is problematic without that alignment. 398*9c1442a9SBen Hutchings */ 399*9c1442a9SBen Hutchings sys_size = (sys_size + 1) & ~1; 400*9c1442a9SBen Hutchings #endif 40119d8d79cSThomas Gleixner 40219d8d79cSThomas Gleixner /* Patch the setup code with the appropriate size parameters */ 40319d8d79cSThomas Gleixner buf[0x1f1] = setup_sectors-1; 40492f42c50SMatt Fleming put_unaligned_le32(sys_size, &buf[0x1f4]); 40519d8d79cSThomas Gleixner 406c7fb93ecSMichael Brown update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); 407c7fb93ecSMichael Brown init_sz = get_unaligned_le32(&buf[0x260]); 408c7fb93ecSMichael Brown update_pecoff_bss(i + (sys_size * 16), init_sz); 40999f857dbSDavid Woodhouse 410993c30a0SMatt Fleming efi_stub_entry_update(); 411291f3632SMatt Fleming 4127d6e737cSIan Campbell crc = partial_crc32(buf, i, crc); 413809373e2SKees Cook if (fwrite(buf, 1, i, dest) != i) 41419d8d79cSThomas Gleixner die("Writing setup failed"); 41519d8d79cSThomas Gleixner 41619d8d79cSThomas Gleixner /* Copy the kernel code */ 4177d6e737cSIan Campbell crc = partial_crc32(kernel, sz, crc); 418809373e2SKees Cook if (fwrite(kernel, 1, sz, dest) != sz) 41919d8d79cSThomas Gleixner die("Writing kernel failed"); 4207d6e737cSIan Campbell 4217d6e737cSIan Campbell /* Add padding leaving 4 bytes for the checksum */ 4227d6e737cSIan Campbell while (sz++ < (sys_size*16) - 4) { 4237d6e737cSIan Campbell crc = partial_crc32_one('\0', crc); 424809373e2SKees Cook if (fwrite("\0", 1, 1, dest) != 1) 4257d6e737cSIan Campbell die("Writing padding failed"); 4267d6e737cSIan Campbell } 4277d6e737cSIan Campbell 4287d6e737cSIan Campbell /* Write the CRC */ 429809373e2SKees Cook printf("CRC %x\n", crc); 430a51f4047SH. Peter Anvin put_unaligned_le32(crc, buf); 431809373e2SKees Cook if (fwrite(buf, 1, 4, dest) != 4) 4327d6e737cSIan Campbell die("Writing CRC failed"); 4337d6e737cSIan Campbell 434809373e2SKees Cook /* Catch any delayed write failures */ 435809373e2SKees Cook if (fclose(dest)) 436809373e2SKees Cook die("Writing image failed"); 437809373e2SKees Cook 43819d8d79cSThomas Gleixner close(fd); 43919d8d79cSThomas Gleixner 44019d8d79cSThomas Gleixner /* Everything is OK */ 44119d8d79cSThomas Gleixner return 0; 44219d8d79cSThomas Gleixner } 443