| .. | .. |
|---|
| 53 | 53 | |
|---|
| 54 | 54 | #define PECOFF_RELOC_RESERVE 0x20 |
|---|
| 55 | 55 | |
|---|
| 56 | | -unsigned long efi32_stub_entry; |
|---|
| 57 | | -unsigned long efi64_stub_entry; |
|---|
| 58 | | -unsigned long efi_pe_entry; |
|---|
| 59 | | -unsigned long startup_64; |
|---|
| 56 | +#ifdef CONFIG_EFI_MIXED |
|---|
| 57 | +#define PECOFF_COMPAT_RESERVE 0x20 |
|---|
| 58 | +#else |
|---|
| 59 | +#define PECOFF_COMPAT_RESERVE 0x0 |
|---|
| 60 | +#endif |
|---|
| 61 | + |
|---|
| 62 | +static unsigned long efi32_stub_entry; |
|---|
| 63 | +static unsigned long efi64_stub_entry; |
|---|
| 64 | +static unsigned long efi_pe_entry; |
|---|
| 65 | +static unsigned long efi32_pe_entry; |
|---|
| 66 | +static unsigned long kernel_info; |
|---|
| 67 | +static unsigned long startup_64; |
|---|
| 68 | +static unsigned long _ehead; |
|---|
| 69 | +static unsigned long _end; |
|---|
| 60 | 70 | |
|---|
| 61 | 71 | /*----------------------------------------------------------------------*/ |
|---|
| 62 | 72 | |
|---|
| .. | .. |
|---|
| 132 | 142 | va_list args; |
|---|
| 133 | 143 | va_start(args, str); |
|---|
| 134 | 144 | vfprintf(stderr, str, args); |
|---|
| 145 | + va_end(args); |
|---|
| 135 | 146 | fputc('\n', stderr); |
|---|
| 136 | 147 | exit(1); |
|---|
| 137 | 148 | } |
|---|
| .. | .. |
|---|
| 187 | 198 | static void update_pecoff_setup_and_reloc(unsigned int size) |
|---|
| 188 | 199 | { |
|---|
| 189 | 200 | u32 setup_offset = 0x200; |
|---|
| 190 | | - u32 reloc_offset = size - PECOFF_RELOC_RESERVE; |
|---|
| 201 | + u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE; |
|---|
| 202 | +#ifdef CONFIG_EFI_MIXED |
|---|
| 203 | + u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE; |
|---|
| 204 | +#endif |
|---|
| 191 | 205 | u32 setup_size = reloc_offset - setup_offset; |
|---|
| 192 | 206 | |
|---|
| 193 | 207 | update_pecoff_section_header(".setup", setup_offset, setup_size); |
|---|
| .. | .. |
|---|
| 199 | 213 | */ |
|---|
| 200 | 214 | put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]); |
|---|
| 201 | 215 | put_unaligned_le32(10, &buf[reloc_offset + 4]); |
|---|
| 216 | + |
|---|
| 217 | +#ifdef CONFIG_EFI_MIXED |
|---|
| 218 | + update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE); |
|---|
| 219 | + |
|---|
| 220 | + /* |
|---|
| 221 | + * Put the IA-32 machine type (0x14c) and the associated entry point |
|---|
| 222 | + * address in the .compat section, so loaders can figure out which other |
|---|
| 223 | + * execution modes this image supports. |
|---|
| 224 | + */ |
|---|
| 225 | + buf[compat_offset] = 0x1; |
|---|
| 226 | + buf[compat_offset + 1] = 0x8; |
|---|
| 227 | + put_unaligned_le16(0x14c, &buf[compat_offset + 2]); |
|---|
| 228 | + put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]); |
|---|
| 229 | +#endif |
|---|
| 202 | 230 | } |
|---|
| 203 | 231 | |
|---|
| 204 | | -static void update_pecoff_text(unsigned int text_start, unsigned int file_sz) |
|---|
| 232 | +static void update_pecoff_text(unsigned int text_start, unsigned int file_sz, |
|---|
| 233 | + unsigned int init_sz) |
|---|
| 205 | 234 | { |
|---|
| 206 | 235 | unsigned int pe_header; |
|---|
| 207 | 236 | unsigned int text_sz = file_sz - text_start; |
|---|
| 237 | + unsigned int bss_sz = init_sz - file_sz; |
|---|
| 208 | 238 | |
|---|
| 209 | 239 | pe_header = get_unaligned_le32(&buf[0x3c]); |
|---|
| 240 | + |
|---|
| 241 | + /* |
|---|
| 242 | + * The PE/COFF loader may load the image at an address which is |
|---|
| 243 | + * misaligned with respect to the kernel_alignment field in the setup |
|---|
| 244 | + * header. |
|---|
| 245 | + * |
|---|
| 246 | + * In order to avoid relocating the kernel to correct the misalignment, |
|---|
| 247 | + * add slack to allow the buffer to be aligned within the declared size |
|---|
| 248 | + * of the image. |
|---|
| 249 | + */ |
|---|
| 250 | + bss_sz += CONFIG_PHYSICAL_ALIGN; |
|---|
| 251 | + init_sz += CONFIG_PHYSICAL_ALIGN; |
|---|
| 210 | 252 | |
|---|
| 211 | 253 | /* |
|---|
| 212 | 254 | * Size of code: Subtract the size of the first sector (512 bytes) |
|---|
| 213 | 255 | * which includes the header. |
|---|
| 214 | 256 | */ |
|---|
| 215 | | - put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]); |
|---|
| 257 | + put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]); |
|---|
| 258 | + |
|---|
| 259 | + /* Size of image */ |
|---|
| 260 | + put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); |
|---|
| 216 | 261 | |
|---|
| 217 | 262 | /* |
|---|
| 218 | 263 | * Address of entry point for PE/COFF executable |
|---|
| 219 | 264 | */ |
|---|
| 220 | 265 | put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]); |
|---|
| 221 | 266 | |
|---|
| 222 | | - update_pecoff_section_header(".text", text_start, text_sz); |
|---|
| 223 | | -} |
|---|
| 224 | | - |
|---|
| 225 | | -static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz) |
|---|
| 226 | | -{ |
|---|
| 227 | | - unsigned int pe_header; |
|---|
| 228 | | - unsigned int bss_sz = init_sz - file_sz; |
|---|
| 229 | | - |
|---|
| 230 | | - pe_header = get_unaligned_le32(&buf[0x3c]); |
|---|
| 231 | | - |
|---|
| 232 | | - /* Size of uninitialized data */ |
|---|
| 233 | | - put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]); |
|---|
| 234 | | - |
|---|
| 235 | | - /* Size of image */ |
|---|
| 236 | | - put_unaligned_le32(init_sz, &buf[pe_header + 0x50]); |
|---|
| 237 | | - |
|---|
| 238 | | - update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0); |
|---|
| 267 | + update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz, |
|---|
| 268 | + text_sz, text_start); |
|---|
| 239 | 269 | } |
|---|
| 240 | 270 | |
|---|
| 241 | 271 | static int reserve_pecoff_reloc_section(int c) |
|---|
| .. | .. |
|---|
| 276 | 306 | |
|---|
| 277 | 307 | static inline void update_pecoff_setup_and_reloc(unsigned int size) {} |
|---|
| 278 | 308 | static inline void update_pecoff_text(unsigned int text_start, |
|---|
| 279 | | - unsigned int file_sz) {} |
|---|
| 280 | | -static inline void update_pecoff_bss(unsigned int file_sz, |
|---|
| 281 | | - unsigned int init_sz) {} |
|---|
| 309 | + unsigned int file_sz, |
|---|
| 310 | + unsigned int init_sz) {} |
|---|
| 282 | 311 | static inline void efi_stub_defaults(void) {} |
|---|
| 283 | 312 | static inline void efi_stub_entry_update(void) {} |
|---|
| 284 | 313 | |
|---|
| .. | .. |
|---|
| 288 | 317 | } |
|---|
| 289 | 318 | #endif /* CONFIG_EFI_STUB */ |
|---|
| 290 | 319 | |
|---|
| 320 | +static int reserve_pecoff_compat_section(int c) |
|---|
| 321 | +{ |
|---|
| 322 | + /* Reserve 0x20 bytes for .compat section */ |
|---|
| 323 | + memset(buf+c, 0, PECOFF_COMPAT_RESERVE); |
|---|
| 324 | + return PECOFF_COMPAT_RESERVE; |
|---|
| 325 | +} |
|---|
| 291 | 326 | |
|---|
| 292 | 327 | /* |
|---|
| 293 | 328 | * Parse zoffset.h and find the entry points. We could just #include zoffset.h |
|---|
| .. | .. |
|---|
| 320 | 355 | PARSE_ZOFS(p, efi32_stub_entry); |
|---|
| 321 | 356 | PARSE_ZOFS(p, efi64_stub_entry); |
|---|
| 322 | 357 | PARSE_ZOFS(p, efi_pe_entry); |
|---|
| 358 | + PARSE_ZOFS(p, efi32_pe_entry); |
|---|
| 359 | + PARSE_ZOFS(p, kernel_info); |
|---|
| 323 | 360 | PARSE_ZOFS(p, startup_64); |
|---|
| 361 | + PARSE_ZOFS(p, _ehead); |
|---|
| 362 | + PARSE_ZOFS(p, _end); |
|---|
| 324 | 363 | |
|---|
| 325 | 364 | p = strchr(p, '\n'); |
|---|
| 326 | 365 | while (p && (*p == '\r' || *p == '\n')) |
|---|
| .. | .. |
|---|
| 362 | 401 | die("Boot block hasn't got boot flag (0xAA55)"); |
|---|
| 363 | 402 | fclose(file); |
|---|
| 364 | 403 | |
|---|
| 404 | + c += reserve_pecoff_compat_section(c); |
|---|
| 365 | 405 | c += reserve_pecoff_reloc_section(c); |
|---|
| 366 | 406 | |
|---|
| 367 | 407 | /* Pad unused space with zeros */ |
|---|
| .. | .. |
|---|
| 376 | 416 | /* Set the default root device */ |
|---|
| 377 | 417 | put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]); |
|---|
| 378 | 418 | |
|---|
| 379 | | - printf("Setup is %d bytes (padded to %d bytes).\n", c, i); |
|---|
| 380 | | - |
|---|
| 381 | 419 | /* Open and stat the kernel file */ |
|---|
| 382 | 420 | fd = open(argv[2], O_RDONLY); |
|---|
| 383 | 421 | if (fd < 0) |
|---|
| .. | .. |
|---|
| 385 | 423 | if (fstat(fd, &sb)) |
|---|
| 386 | 424 | die("Unable to stat `%s': %m", argv[2]); |
|---|
| 387 | 425 | sz = sb.st_size; |
|---|
| 388 | | - printf("System is %d kB\n", (sz+1023)/1024); |
|---|
| 389 | 426 | kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0); |
|---|
| 390 | 427 | if (kernel == MAP_FAILED) |
|---|
| 391 | 428 | die("Unable to mmap '%s': %m", argv[2]); |
|---|
| .. | .. |
|---|
| 403 | 440 | buf[0x1f1] = setup_sectors-1; |
|---|
| 404 | 441 | put_unaligned_le32(sys_size, &buf[0x1f4]); |
|---|
| 405 | 442 | |
|---|
| 406 | | - update_pecoff_text(setup_sectors * 512, i + (sys_size * 16)); |
|---|
| 407 | 443 | init_sz = get_unaligned_le32(&buf[0x260]); |
|---|
| 408 | | - update_pecoff_bss(i + (sys_size * 16), init_sz); |
|---|
| 444 | +#ifdef CONFIG_EFI_STUB |
|---|
| 445 | + /* |
|---|
| 446 | + * The decompression buffer will start at ImageBase. When relocating |
|---|
| 447 | + * the compressed kernel to its end, we must ensure that the head |
|---|
| 448 | + * section does not get overwritten. The head section occupies |
|---|
| 449 | + * [i, i + _ehead), and the destination is [init_sz - _end, init_sz). |
|---|
| 450 | + * |
|---|
| 451 | + * At present these should never overlap, because 'i' is at most 32k |
|---|
| 452 | + * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the |
|---|
| 453 | + * calculation of INIT_SIZE in boot/header.S ensures that |
|---|
| 454 | + * 'init_sz - _end' is at least 64k. |
|---|
| 455 | + * |
|---|
| 456 | + * For future-proofing, increase init_sz if necessary. |
|---|
| 457 | + */ |
|---|
| 458 | + |
|---|
| 459 | + if (init_sz - _end < i + _ehead) { |
|---|
| 460 | + init_sz = (i + _ehead + _end + 4095) & ~4095; |
|---|
| 461 | + put_unaligned_le32(init_sz, &buf[0x260]); |
|---|
| 462 | + } |
|---|
| 463 | +#endif |
|---|
| 464 | + update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz); |
|---|
| 409 | 465 | |
|---|
| 410 | 466 | efi_stub_entry_update(); |
|---|
| 467 | + |
|---|
| 468 | + /* Update kernel_info offset. */ |
|---|
| 469 | + put_unaligned_le32(kernel_info, &buf[0x268]); |
|---|
| 411 | 470 | |
|---|
| 412 | 471 | crc = partial_crc32(buf, i, crc); |
|---|
| 413 | 472 | if (fwrite(buf, 1, i, dest) != i) |
|---|
| .. | .. |
|---|
| 426 | 485 | } |
|---|
| 427 | 486 | |
|---|
| 428 | 487 | /* Write the CRC */ |
|---|
| 429 | | - printf("CRC %x\n", crc); |
|---|
| 430 | 488 | put_unaligned_le32(crc, buf); |
|---|
| 431 | 489 | if (fwrite(buf, 1, 4, dest) != 4) |
|---|
| 432 | 490 | die("Writing CRC failed"); |
|---|