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