.. | .. |
---|
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"); |
---|