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