1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 1991, 1992 Linus Torvalds 4 * Copyright (C) 1997 Martin Mares 5 * Copyright (C) 2007 H. Peter Anvin 6 */ 7 8 /* 9 * This file builds a disk-image from three different files: 10 * 11 * - setup: 8086 machine code, sets up system parm 12 * - system: 80386 code for actual system 13 * - zoffset.h: header with ZO_* defines 14 * 15 * It does some checking that all files are of the correct type, and writes 16 * the result to the specified destination, removing headers and padding to 17 * the right amount. It also writes some system data to stdout. 18 */ 19 20 /* 21 * Changes by tytso to allow root device specification 22 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 23 * Cross compiling fixes by Gertjan van Wingerde, July 1996 24 * Rewritten by Martin Mares, April 1997 25 * Substantially overhauled by H. Peter Anvin, April 2007 26 */ 27 28 #include <stdio.h> 29 #include <string.h> 30 #include <stdlib.h> 31 #include <stdarg.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <sys/mman.h> 37 #include <tools/le_byteshift.h> 38 39 typedef unsigned char u8; 40 typedef unsigned short u16; 41 typedef unsigned int u32; 42 43 /* Minimal number of setup sectors */ 44 #define SETUP_SECT_MIN 5 45 #define SETUP_SECT_MAX 64 46 47 /* This must be large enough to hold the entire setup */ 48 u8 buf[SETUP_SECT_MAX*512]; 49 50 #define PECOFF_RELOC_RESERVE 0x20 51 52 #ifdef CONFIG_EFI_MIXED 53 #define PECOFF_COMPAT_RESERVE 0x20 54 #else 55 #define PECOFF_COMPAT_RESERVE 0x0 56 #endif 57 58 static unsigned long efi32_stub_entry; 59 static unsigned long efi64_stub_entry; 60 static unsigned long efi_pe_entry; 61 static unsigned long efi32_pe_entry; 62 static unsigned long _end; 63 64 /*----------------------------------------------------------------------*/ 65 66 static const u32 crctab32[] = { 67 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 68 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 69 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 70 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 71 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 72 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 73 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 74 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 75 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 76 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 77 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 78 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 79 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 80 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 81 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 82 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 83 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 84 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 85 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 86 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 87 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 88 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 89 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 90 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 91 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 92 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 93 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 94 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 95 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 96 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 97 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 98 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 99 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 100 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 101 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 102 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 103 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 104 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 105 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 106 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 107 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 108 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 109 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 110 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 111 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 112 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 113 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 114 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 115 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 116 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 117 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 118 0x2d02ef8d 119 }; 120 121 static u32 partial_crc32_one(u8 c, u32 crc) 122 { 123 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8); 124 } 125 126 static u32 partial_crc32(const u8 *s, int len, u32 crc) 127 { 128 while (len--) 129 crc = partial_crc32_one(*s++, crc); 130 return crc; 131 } 132 133 static void die(const char * str, ...) 134 { 135 va_list args; 136 va_start(args, str); 137 vfprintf(stderr, str, args); 138 va_end(args); 139 fputc('\n', stderr); 140 exit(1); 141 } 142 143 static void usage(void) 144 { 145 die("Usage: build setup system zoffset.h image"); 146 } 147 148 #ifdef CONFIG_EFI_STUB 149 150 static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset) 151 { 152 unsigned int pe_header; 153 unsigned short num_sections; 154 u8 *section; 155 156 pe_header = get_unaligned_le32(&buf[0x3c]); 157 num_sections = get_unaligned_le16(&buf[pe_header + 6]); 158 159 #ifdef CONFIG_X86_32 160 section = &buf[pe_header + 0xa8]; 161 #else 162 section = &buf[pe_header + 0xb8]; 163 #endif 164 165 while (num_sections > 0) { 166 if (strncmp((char*)section, section_name, 8) == 0) { 167 /* section header size field */ 168 put_unaligned_le32(size, section + 0x8); 169 170 /* section header vma field */ 171 put_unaligned_le32(vma, section + 0xc); 172 173 /* section header 'size of initialised data' field */ 174 put_unaligned_le32(datasz, section + 0x10); 175 176 /* section header 'file offset' field */ 177 put_unaligned_le32(offset, section + 0x14); 178 179 break; 180 } 181 section += 0x28; 182 num_sections--; 183 } 184 } 185 186 static void update_pecoff_section_header(char *section_name, u32 offset, u32 size) 187 { 188 update_pecoff_section_header_fields(section_name, offset, size, size, offset); 189 } 190 191 static void update_pecoff_setup_and_reloc(unsigned int size) 192 { 193 u32 setup_offset = 0x200; 194 u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE; 195 #ifdef CONFIG_EFI_MIXED 196 u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE; 197 #endif 198 u32 setup_size = reloc_offset - setup_offset; 199 200 update_pecoff_section_header(".setup", setup_offset, setup_size); 201 update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE); 202 203 /* 204 * Modify .reloc section contents with a single entry. The 205 * relocation is applied to offset 10 of the relocation section. 206 */ 207 put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); 208 put_unaligned_le32(10, &buf[reloc_offset + 4]); 209 210 #ifdef CONFIG_EFI_MIXED 211 update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE); 212 213 /* 214 * Put the IA-32 machine type (0x14c) and the associated entry point 215 * address in the .compat section, so loaders can figure out which other 216 * execution modes this image supports. 217 */ 218 buf[compat_offset] = 0x1; 219 buf[compat_offset + 1] = 0x8; 220 put_unaligned_le16(0x14c, &buf[compat_offset + 2]); 221 put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]); 222 #endif 223 } 224 225 static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) 226 { 227 unsigned int pe_header; 228 unsigned int text_sz = file_sz - text_start; 229 unsigned int bss_sz = _end - text_sz; 230 231 pe_header = get_unaligned_le32(&buf[0x3c]); 232 233 /* 234 * Size of code: Subtract the size of the first sector (512 bytes) 235 * which includes the header. 236 */ 237 put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]); 238 239 /* Size of image */ 240 put_unaligned_le32(file_sz + bss_sz, &buf[pe_header + 0x50]); 241 242 /* 243 * Address of entry point for PE/COFF executable 244 */ 245 put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]); 246 247 update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz, 248 text_sz, text_start); 249 } 250 251 static int reserve_pecoff_reloc_section(int c) 252 { 253 /* Reserve 0x20 bytes for .reloc section */ 254 memset(buf+c, 0, PECOFF_RELOC_RESERVE); 255 return PECOFF_RELOC_RESERVE; 256 } 257 258 static void efi_stub_defaults(void) 259 { 260 /* Defaults for old kernel */ 261 #ifdef CONFIG_X86_32 262 efi_pe_entry = 0x10; 263 #else 264 efi_pe_entry = 0x210; 265 #endif 266 } 267 268 static void efi_stub_entry_update(void) 269 { 270 unsigned long addr = efi32_stub_entry; 271 272 #ifdef CONFIG_EFI_HANDOVER_PROTOCOL 273 #ifdef CONFIG_X86_64 274 /* Yes, this is really how we defined it :( */ 275 addr = efi64_stub_entry - 0x200; 276 #endif 277 278 #ifdef CONFIG_EFI_MIXED 279 if (efi32_stub_entry != addr) 280 die("32-bit and 64-bit EFI entry points do not match\n"); 281 #endif 282 #endif 283 put_unaligned_le32(addr, &buf[0x264]); 284 } 285 286 #else 287 288 static inline void update_pecoff_setup_and_reloc(unsigned int size) {} 289 static inline void update_pecoff_text(unsigned int text_start, 290 unsigned int file_sz) {} 291 static inline void efi_stub_defaults(void) {} 292 static inline void efi_stub_entry_update(void) {} 293 294 static inline int reserve_pecoff_reloc_section(int c) 295 { 296 return 0; 297 } 298 #endif /* CONFIG_EFI_STUB */ 299 300 static int reserve_pecoff_compat_section(int c) 301 { 302 /* Reserve 0x20 bytes for .compat section */ 303 memset(buf+c, 0, PECOFF_COMPAT_RESERVE); 304 return PECOFF_COMPAT_RESERVE; 305 } 306 307 /* 308 * Parse zoffset.h and find the entry points. We could just #include zoffset.h 309 * but that would mean tools/build would have to be rebuilt every time. It's 310 * not as if parsing it is hard... 311 */ 312 #define PARSE_ZOFS(p, sym) do { \ 313 if (!strncmp(p, "#define ZO_" #sym " ", 11+sizeof(#sym))) \ 314 sym = strtoul(p + 11 + sizeof(#sym), NULL, 16); \ 315 } while (0) 316 317 static void parse_zoffset(char *fname) 318 { 319 FILE *file; 320 char *p; 321 int c; 322 323 file = fopen(fname, "r"); 324 if (!file) 325 die("Unable to open `%s': %m", fname); 326 c = fread(buf, 1, sizeof(buf) - 1, file); 327 if (ferror(file)) 328 die("read-error on `zoffset.h'"); 329 fclose(file); 330 buf[c] = 0; 331 332 p = (char *)buf; 333 334 while (p && *p) { 335 PARSE_ZOFS(p, efi32_stub_entry); 336 PARSE_ZOFS(p, efi64_stub_entry); 337 PARSE_ZOFS(p, efi_pe_entry); 338 PARSE_ZOFS(p, efi32_pe_entry); 339 PARSE_ZOFS(p, _end); 340 341 p = strchr(p, '\n'); 342 while (p && (*p == '\r' || *p == '\n')) 343 p++; 344 } 345 } 346 347 int main(int argc, char ** argv) 348 { 349 unsigned int i, sz, setup_sectors; 350 int c; 351 u32 sys_size; 352 struct stat sb; 353 FILE *file, *dest; 354 int fd; 355 void *kernel; 356 u32 crc = 0xffffffffUL; 357 358 efi_stub_defaults(); 359 360 if (argc != 5) 361 usage(); 362 parse_zoffset(argv[3]); 363 364 dest = fopen(argv[4], "w"); 365 if (!dest) 366 die("Unable to write `%s': %m", argv[4]); 367 368 /* Copy the setup code */ 369 file = fopen(argv[1], "r"); 370 if (!file) 371 die("Unable to open `%s': %m", argv[1]); 372 c = fread(buf, 1, sizeof(buf), file); 373 if (ferror(file)) 374 die("read-error on `setup'"); 375 if (c < 1024) 376 die("The setup must be at least 1024 bytes"); 377 if (get_unaligned_le16(&buf[510]) != 0xAA55) 378 die("Boot block hasn't got boot flag (0xAA55)"); 379 fclose(file); 380 381 c += reserve_pecoff_compat_section(c); 382 c += reserve_pecoff_reloc_section(c); 383 384 /* Pad unused space with zeros */ 385 setup_sectors = (c + 511) / 512; 386 if (setup_sectors < SETUP_SECT_MIN) 387 setup_sectors = SETUP_SECT_MIN; 388 i = setup_sectors*512; 389 memset(buf+c, 0, i-c); 390 391 update_pecoff_setup_and_reloc(i); 392 393 /* Open and stat the kernel file */ 394 fd = open(argv[2], O_RDONLY); 395 if (fd < 0) 396 die("Unable to open `%s': %m", argv[2]); 397 if (fstat(fd, &sb)) 398 die("Unable to stat `%s': %m", argv[2]); 399 sz = sb.st_size; 400 kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0); 401 if (kernel == MAP_FAILED) 402 die("Unable to mmap '%s': %m", argv[2]); 403 /* Number of 16-byte paragraphs, including space for a 4-byte CRC */ 404 sys_size = (sz + 15 + 4) / 16; 405 #ifdef CONFIG_EFI_STUB 406 /* 407 * COFF requires minimum 32-byte alignment of sections, and 408 * adding a signature is problematic without that alignment. 409 */ 410 sys_size = (sys_size + 1) & ~1; 411 #endif 412 413 /* Patch the setup code with the appropriate size parameters */ 414 buf[0x1f1] = setup_sectors-1; 415 put_unaligned_le32(sys_size, &buf[0x1f4]); 416 417 update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); 418 419 efi_stub_entry_update(); 420 421 crc = partial_crc32(buf, i, crc); 422 if (fwrite(buf, 1, i, dest) != i) 423 die("Writing setup failed"); 424 425 /* Copy the kernel code */ 426 crc = partial_crc32(kernel, sz, crc); 427 if (fwrite(kernel, 1, sz, dest) != sz) 428 die("Writing kernel failed"); 429 430 /* Add padding leaving 4 bytes for the checksum */ 431 while (sz++ < (sys_size*16) - 4) { 432 crc = partial_crc32_one('\0', crc); 433 if (fwrite("\0", 1, 1, dest) != 1) 434 die("Writing padding failed"); 435 } 436 437 /* Write the CRC */ 438 put_unaligned_le32(crc, buf); 439 if (fwrite(buf, 1, 4, dest) != 4) 440 die("Writing CRC failed"); 441 442 /* Catch any delayed write failures */ 443 if (fclose(dest)) 444 die("Writing image failed"); 445 446 close(fd); 447 448 /* Everything is OK */ 449 return 0; 450 } 451