]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/BasePeCoff.c
fb7ce251221d3f49082052507255a895632e3863
[mirror_edk2.git] / BaseTools / Source / C / Common / BasePeCoff.c
1 /** @file
2
3 Functions to get info and load PE/COFF image.
4
5 Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
6 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <Common/UefiBaseTypes.h>
18 #include <CommonLib.h>
19 #include <IndustryStandard/PeImage.h>
20 #include "PeCoffLib.h"
21
22 typedef union {
23 VOID *Header;
24 EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
25 EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
26 } EFI_IMAGE_OPTIONAL_HEADER_POINTER;
27
28 STATIC
29 RETURN_STATUS
30 PeCoffLoaderGetPeHeader (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
32 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
33 OUT EFI_TE_IMAGE_HEADER **TeHdr
34 );
35
36 STATIC
37 RETURN_STATUS
38 PeCoffLoaderCheckImageType (
39 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
40 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
41 IN EFI_TE_IMAGE_HEADER *TeHdr
42 );
43
44 STATIC
45 VOID *
46 PeCoffLoaderImageAddress (
47 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
48 IN UINTN Address
49 );
50
51 RETURN_STATUS
52 PeCoffLoaderRelocateIa32Image (
53 IN UINT16 *Reloc,
54 IN OUT CHAR8 *Fixup,
55 IN OUT CHAR8 **FixupData,
56 IN UINT64 Adjust
57 );
58
59 RETURN_STATUS
60 PeCoffLoaderRelocateIpfImage (
61 IN UINT16 *Reloc,
62 IN OUT CHAR8 *Fixup,
63 IN OUT CHAR8 **FixupData,
64 IN UINT64 Adjust
65 );
66
67 RETURN_STATUS
68 PeCoffLoaderRelocateArmImage (
69 IN UINT16 **Reloc,
70 IN OUT CHAR8 *Fixup,
71 IN OUT CHAR8 **FixupData,
72 IN UINT64 Adjust
73 );
74
75 STATIC
76 RETURN_STATUS
77 PeCoffLoaderGetPeHeader (
78 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
79 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
80 OUT EFI_TE_IMAGE_HEADER **TeHdr
81 )
82 /*++
83
84 Routine Description:
85
86 Retrieves the PE or TE Header from a PE/COFF or TE image
87
88 Arguments:
89
90 ImageContext - The context of the image being loaded
91
92 PeHdr - The buffer in which to return the PE header
93
94 TeHdr - The buffer in which to return the TE header
95
96 Returns:
97
98 RETURN_SUCCESS if the PE or TE Header is read,
99 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
100
101 --*/
102 {
103 RETURN_STATUS Status;
104 EFI_IMAGE_DOS_HEADER DosHdr;
105 UINTN Size;
106
107 ImageContext->IsTeImage = FALSE;
108 //
109 // Read the DOS image headers
110 //
111 Size = sizeof (EFI_IMAGE_DOS_HEADER);
112 Status = ImageContext->ImageRead (
113 ImageContext->Handle,
114 0,
115 &Size,
116 &DosHdr
117 );
118 if (RETURN_ERROR (Status)) {
119 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
120 return Status;
121 }
122
123 ImageContext->PeCoffHeaderOffset = 0;
124 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
125 //
126 // DOS image header is present, so read the PE header after the DOS image header
127 //
128 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
129 }
130 //
131 // Get the PE/COFF Header pointer
132 //
133 *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
134 if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
135 //
136 // Check the PE/COFF Header Signature. If not, then try to get a TE header
137 //
138 *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr;
139 if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
140 return RETURN_UNSUPPORTED;
141 }
142 ImageContext->IsTeImage = TRUE;
143 }
144
145 return RETURN_SUCCESS;
146 }
147
148 STATIC
149 RETURN_STATUS
150 PeCoffLoaderCheckImageType (
151 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
152 IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
153 IN EFI_TE_IMAGE_HEADER *TeHdr
154 )
155 /*++
156
157 Routine Description:
158
159 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
160
161 Arguments:
162
163 ImageContext - The context of the image being loaded
164
165 PeHdr - The buffer in which to return the PE header
166
167 TeHdr - The buffer in which to return the TE header
168
169 Returns:
170
171 RETURN_SUCCESS if the PE/COFF or TE image is supported
172 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
173
174 --*/
175 {
176 //
177 // See if the machine type is supported.
178 // We support a native machine type (IA-32/Itanium-based)
179 //
180 if (ImageContext->IsTeImage == FALSE) {
181 ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;
182 } else {
183 ImageContext->Machine = TeHdr->Machine;
184 }
185
186 if (ImageContext->Machine != EFI_IMAGE_MACHINE_IA32 && \
187 ImageContext->Machine != EFI_IMAGE_MACHINE_IA64 && \
188 ImageContext->Machine != EFI_IMAGE_MACHINE_X64 && \
189 ImageContext->Machine != EFI_IMAGE_MACHINE_ARMT && \
190 ImageContext->Machine != EFI_IMAGE_MACHINE_EBC && \
191 ImageContext->Machine != EFI_IMAGE_MACHINE_AARCH64) {
192 if (ImageContext->Machine == IMAGE_FILE_MACHINE_ARM) {
193 //
194 // There are two types of ARM images. Pure ARM and ARM/Thumb.
195 // If we see the ARM say it is the ARM/Thumb so there is only
196 // a single machine type we need to check for ARM.
197 //
198 ImageContext->Machine = EFI_IMAGE_MACHINE_ARMT;
199 if (ImageContext->IsTeImage == FALSE) {
200 PeHdr->Pe32.FileHeader.Machine = ImageContext->Machine;
201 } else {
202 TeHdr->Machine = ImageContext->Machine;
203 }
204
205 } else {
206 //
207 // unsupported PeImage machine type
208 //
209 return RETURN_UNSUPPORTED;
210 }
211 }
212
213 //
214 // See if the image type is supported. We support EFI Applications,
215 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
216 //
217 if (ImageContext->IsTeImage == FALSE) {
218 ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;
219 } else {
220 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
221 }
222
223 if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
224 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \
225 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \
226 ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {
227 //
228 // upsupported PeImage subsystem type
229 //
230 return RETURN_UNSUPPORTED;
231 }
232
233 return RETURN_SUCCESS;
234 }
235
236 RETURN_STATUS
237 EFIAPI
238 PeCoffLoaderGetImageInfo (
239 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
240 )
241 /*++
242
243 Routine Description:
244
245 Retrieves information on a PE/COFF image
246
247 Arguments:
248
249 This - Calling context
250 ImageContext - The context of the image being loaded
251
252 Returns:
253
254 RETURN_SUCCESS - The information on the PE/COFF image was collected.
255 RETURN_INVALID_PARAMETER - ImageContext is NULL.
256 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
257 Otherwise - The error status from reading the PE/COFF image using the
258 ImageContext->ImageRead() function
259
260 --*/
261 {
262 RETURN_STATUS Status;
263 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
264 EFI_TE_IMAGE_HEADER *TeHdr;
265 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
266 UINTN Size;
267 UINTN Index;
268 UINTN DebugDirectoryEntryRva;
269 UINTN DebugDirectoryEntryFileOffset;
270 UINTN SectionHeaderOffset;
271 EFI_IMAGE_SECTION_HEADER SectionHeader;
272 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
273 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
274
275 PeHdr = NULL;
276 TeHdr = NULL;
277 DebugDirectoryEntry = NULL;
278 DebugDirectoryEntryRva = 0;
279
280 if (NULL == ImageContext) {
281 return RETURN_INVALID_PARAMETER;
282 }
283 //
284 // Assume success
285 //
286 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
287
288 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
289 if (RETURN_ERROR (Status)) {
290 return Status;
291 }
292
293 //
294 // Verify machine type
295 //
296 Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);
297 if (RETURN_ERROR (Status)) {
298 return Status;
299 }
300 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
301
302 //
303 // Retrieve the base address of the image
304 //
305 if (!(ImageContext->IsTeImage)) {
306 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
307 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;
308 } else {
309 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;
310 }
311 } else {
312 ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
313 }
314 //
315 // Initialize the alternate destination address to 0 indicating that it
316 // should not be used.
317 //
318 ImageContext->DestinationAddress = 0;
319
320 //
321 // Initialize the codeview pointer.
322 //
323 ImageContext->CodeView = NULL;
324 ImageContext->PdbPointer = NULL;
325
326 //
327 // Three cases with regards to relocations:
328 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
329 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
330 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
331 // has no base relocs to apply
332 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
333 //
334 // Look at the file header to determine if relocations have been stripped, and
335 // save this info in the image context for later use.
336 //
337 if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
338 ImageContext->RelocationsStripped = TRUE;
339 } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0) && (TeHdr->DataDirectory[0].VirtualAddress == 0)) {
340 ImageContext->RelocationsStripped = TRUE;
341 } else {
342 ImageContext->RelocationsStripped = FALSE;
343 }
344
345 if (!(ImageContext->IsTeImage)) {
346
347 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
348 ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage;
349 ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment;
350 ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders;
351
352 //
353 // Modify ImageSize to contain .PDB file name if required and initialize
354 // PdbRVA field...
355 //
356 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
357 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
358 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
359 }
360 } else {
361 ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage;
362 ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment;
363 ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders;
364
365 //
366 // Modify ImageSize to contain .PDB file name if required and initialize
367 // PdbRVA field...
368 //
369 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
370 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
371 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
372 }
373 }
374
375 if (DebugDirectoryEntryRva != 0) {
376 //
377 // Determine the file offset of the debug directory... This means we walk
378 // the sections to find which section contains the RVA of the debug
379 // directory
380 //
381 DebugDirectoryEntryFileOffset = 0;
382
383 SectionHeaderOffset = (UINTN)(
384 ImageContext->PeCoffHeaderOffset +
385 sizeof (UINT32) +
386 sizeof (EFI_IMAGE_FILE_HEADER) +
387 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
388 );
389
390 for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {
391 //
392 // Read section header from file
393 //
394 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
395 Status = ImageContext->ImageRead (
396 ImageContext->Handle,
397 SectionHeaderOffset,
398 &Size,
399 &SectionHeader
400 );
401 if (RETURN_ERROR (Status)) {
402 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
403 return Status;
404 }
405
406 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
407 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
408 DebugDirectoryEntryFileOffset =
409 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
410 break;
411 }
412
413 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
414 }
415
416 if (DebugDirectoryEntryFileOffset != 0) {
417 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
418 //
419 // Read next debug directory entry
420 //
421 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
422 Status = ImageContext->ImageRead (
423 ImageContext->Handle,
424 DebugDirectoryEntryFileOffset + Index,
425 &Size,
426 &DebugEntry
427 );
428 if (RETURN_ERROR (Status)) {
429 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
430 return Status;
431 }
432
433 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
434 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
435 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
436 ImageContext->ImageSize += DebugEntry.SizeOfData;
437 }
438
439 return RETURN_SUCCESS;
440 }
441 }
442 }
443 }
444 } else {
445 ImageContext->ImageSize = 0;
446 ImageContext->SectionAlignment = 4096;
447 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;
448
449 DebugDirectoryEntry = &TeHdr->DataDirectory[1];
450 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
451 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
452
453 DebugDirectoryEntryFileOffset = 0;
454
455 for (Index = 0; Index < TeHdr->NumberOfSections;) {
456 //
457 // Read section header from file
458 //
459 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
460 Status = ImageContext->ImageRead (
461 ImageContext->Handle,
462 SectionHeaderOffset,
463 &Size,
464 &SectionHeader
465 );
466 if (RETURN_ERROR (Status)) {
467 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
468 return Status;
469 }
470
471 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
472 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
473 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
474 SectionHeader.VirtualAddress +
475 SectionHeader.PointerToRawData +
476 sizeof (EFI_TE_IMAGE_HEADER) -
477 TeHdr->StrippedSize;
478
479 //
480 // File offset of the debug directory was found, if this is not the last
481 // section, then skip to the last section for calculating the image size.
482 //
483 if (Index < (UINTN) TeHdr->NumberOfSections - 1) {
484 SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
485 Index = TeHdr->NumberOfSections - 1;
486 continue;
487 }
488 }
489
490 //
491 // In Te image header there is not a field to describe the ImageSize.
492 // Actually, the ImageSize equals the RVA plus the VirtualSize of
493 // the last section mapped into memory (Must be rounded up to
494 // a mulitple of Section Alignment). Per the PE/COFF specification, the
495 // section headers in the Section Table must appear in order of the RVA
496 // values for the corresponding sections. So the ImageSize can be determined
497 // by the RVA and the VirtualSize of the last section header in the
498 // Section Table.
499 //
500 if ((++Index) == (UINTN) TeHdr->NumberOfSections) {
501 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
502 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
503 }
504
505 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
506 }
507
508 if (DebugDirectoryEntryFileOffset != 0) {
509 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
510 //
511 // Read next debug directory entry
512 //
513 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
514 Status = ImageContext->ImageRead (
515 ImageContext->Handle,
516 DebugDirectoryEntryFileOffset,
517 &Size,
518 &DebugEntry
519 );
520 if (RETURN_ERROR (Status)) {
521 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
522 return Status;
523 }
524
525 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
526 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
527 return RETURN_SUCCESS;
528 }
529 }
530 }
531 }
532
533 return RETURN_SUCCESS;
534 }
535
536 STATIC
537 VOID *
538 PeCoffLoaderImageAddress (
539 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
540 IN UINTN Address
541 )
542 /*++
543
544 Routine Description:
545
546 Converts an image address to the loaded address
547
548 Arguments:
549
550 ImageContext - The context of the image being loaded
551
552 Address - The address to be converted to the loaded address
553
554 Returns:
555
556 NULL if the address can not be converted, otherwise, the converted address
557
558 --*/
559 {
560 if (Address >= ImageContext->ImageSize) {
561 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
562 return NULL;
563 }
564
565 return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);
566 }
567
568 RETURN_STATUS
569 EFIAPI
570 PeCoffLoaderRelocateImage (
571 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
572 )
573 /*++
574
575 Routine Description:
576
577 Relocates a PE/COFF image in memory
578
579 Arguments:
580
581 This - Calling context
582
583 ImageContext - Contains information on the loaded image to relocate
584
585 Returns:
586
587 RETURN_SUCCESS if the PE/COFF image was relocated
588 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
589 RETURN_UNSUPPORTED not support
590
591 --*/
592 {
593 RETURN_STATUS Status;
594 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
595 EFI_TE_IMAGE_HEADER *TeHdr;
596 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
597 UINT64 Adjust;
598 EFI_IMAGE_BASE_RELOCATION *RelocBase;
599 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
600 UINT16 *Reloc;
601 UINT16 *RelocEnd;
602 CHAR8 *Fixup;
603 CHAR8 *FixupBase;
604 UINT16 *F16;
605 UINT32 *F32;
606 UINT64 *F64;
607 CHAR8 *FixupData;
608 PHYSICAL_ADDRESS BaseAddress;
609 UINT16 MachineType;
610 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
611
612 PeHdr = NULL;
613 TeHdr = NULL;
614 //
615 // Assume success
616 //
617 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
618
619 //
620 // If there are no relocation entries, then we are done
621 //
622 if (ImageContext->RelocationsStripped) {
623 return RETURN_SUCCESS;
624 }
625
626 //
627 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
628 //
629 BaseAddress = ImageContext->DestinationAddress;
630
631 if (!(ImageContext->IsTeImage)) {
632 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress +
633 ImageContext->PeCoffHeaderOffset);
634 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
635 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
636 Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;
637 OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;
638 MachineType = ImageContext->Machine;
639 //
640 // Find the relocation block
641 //
642 // Per the PE/COFF spec, you can't assume that a given data directory
643 // is present in the image. You have to check the NumberOfRvaAndSizes in
644 // the optional header to verify a desired directory entry is there.
645 //
646 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
647 RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
648 if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
649 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
650 RelocBaseEnd = PeCoffLoaderImageAddress (
651 ImageContext,
652 RelocDir->VirtualAddress + RelocDir->Size - 1
653 );
654 if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
655 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
656 return RETURN_LOAD_ERROR;
657 }
658 } else {
659 //
660 // Set base and end to bypass processing below.
661 //
662 RelocBase = RelocBaseEnd = 0;
663 }
664 } else {
665 //
666 // Set base and end to bypass processing below.
667 //
668 RelocBase = RelocBaseEnd = 0;
669 }
670 } else {
671 Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
672 OptionHeader.Optional64->ImageBase = BaseAddress;
673 MachineType = ImageContext->Machine;
674 //
675 // Find the relocation block
676 //
677 // Per the PE/COFF spec, you can't assume that a given data directory
678 // is present in the image. You have to check the NumberOfRvaAndSizes in
679 // the optional header to verify a desired directory entry is there.
680 //
681 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
682 RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
683 if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
684 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
685 RelocBaseEnd = PeCoffLoaderImageAddress (
686 ImageContext,
687 RelocDir->VirtualAddress + RelocDir->Size - 1
688 );
689 if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
690 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
691 return RETURN_LOAD_ERROR;
692 }
693 } else {
694 //
695 // Set base and end to bypass processing below.
696 //
697 RelocBase = RelocBaseEnd = 0;
698 }
699 } else {
700 //
701 // Set base and end to bypass processing below.
702 //
703 RelocBase = RelocBaseEnd = 0;
704 }
705 }
706 } else {
707 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
708 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
709 TeHdr->ImageBase = (UINT64) (BaseAddress);
710 MachineType = TeHdr->Machine;
711
712 //
713 // Find the relocation block
714 //
715 RelocDir = &TeHdr->DataDirectory[0];
716 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
717 ImageContext->ImageAddress +
718 RelocDir->VirtualAddress +
719 sizeof(EFI_TE_IMAGE_HEADER) -
720 TeHdr->StrippedSize
721 );
722 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
723 }
724
725 //
726 // Run the relocation information and apply the fixups
727 //
728 FixupData = ImageContext->FixupData;
729 while (RelocBase < RelocBaseEnd) {
730
731 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
732 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
733 if (!(ImageContext->IsTeImage)) {
734 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
735 if (FixupBase == NULL) {
736 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
737 return RETURN_LOAD_ERROR;
738 }
739 } else {
740 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
741 RelocBase->VirtualAddress +
742 sizeof(EFI_TE_IMAGE_HEADER) -
743 TeHdr->StrippedSize
744 );
745 }
746
747 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
748 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
749 (UINTN)ImageContext->ImageSize)) {
750 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
751 return RETURN_LOAD_ERROR;
752 }
753
754 //
755 // Run this relocation record
756 //
757 while (Reloc < RelocEnd) {
758
759 Fixup = FixupBase + (*Reloc & 0xFFF);
760 switch ((*Reloc) >> 12) {
761 case EFI_IMAGE_REL_BASED_ABSOLUTE:
762 break;
763
764 case EFI_IMAGE_REL_BASED_HIGH:
765 F16 = (UINT16 *) Fixup;
766 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
767 if (FixupData != NULL) {
768 *(UINT16 *) FixupData = *F16;
769 FixupData = FixupData + sizeof (UINT16);
770 }
771 break;
772
773 case EFI_IMAGE_REL_BASED_LOW:
774 F16 = (UINT16 *) Fixup;
775 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
776 if (FixupData != NULL) {
777 *(UINT16 *) FixupData = *F16;
778 FixupData = FixupData + sizeof (UINT16);
779 }
780 break;
781
782 case EFI_IMAGE_REL_BASED_HIGHLOW:
783 F32 = (UINT32 *) Fixup;
784 *F32 = *F32 + (UINT32) Adjust;
785 if (FixupData != NULL) {
786 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
787 *(UINT32 *) FixupData = *F32;
788 FixupData = FixupData + sizeof (UINT32);
789 }
790 break;
791
792 case EFI_IMAGE_REL_BASED_DIR64:
793 F64 = (UINT64 *) Fixup;
794 *F64 = *F64 + (UINT64) Adjust;
795 if (FixupData != NULL) {
796 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
797 *(UINT64 *) FixupData = *F64;
798 FixupData = FixupData + sizeof (UINT64);
799 }
800 break;
801
802 case EFI_IMAGE_REL_BASED_HIGHADJ:
803 //
804 // Return the same EFI_UNSUPPORTED return code as
805 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
806 // the relocation type.
807 //
808 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
809 return RETURN_UNSUPPORTED;
810
811 default:
812 switch (MachineType) {
813 case EFI_IMAGE_MACHINE_IA32:
814 Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
815 break;
816 case EFI_IMAGE_MACHINE_ARMT:
817 Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
818 break;
819 case EFI_IMAGE_MACHINE_IA64:
820 Status = PeCoffLoaderRelocateIpfImage (Reloc, Fixup, &FixupData, Adjust);
821 break;
822 default:
823 Status = RETURN_UNSUPPORTED;
824 break;
825 }
826 if (RETURN_ERROR (Status)) {
827 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
828 return Status;
829 }
830 }
831
832 //
833 // Next relocation record
834 //
835 Reloc += 1;
836 }
837
838 //
839 // Next reloc block
840 //
841 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
842 }
843
844 return RETURN_SUCCESS;
845 }
846
847 RETURN_STATUS
848 EFIAPI
849 PeCoffLoaderLoadImage (
850 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
851 )
852 /*++
853
854 Routine Description:
855
856 Loads a PE/COFF image into memory
857
858 Arguments:
859
860 This - Calling context
861
862 ImageContext - Contains information on image to load into memory
863
864 Returns:
865
866 RETURN_SUCCESS if the PE/COFF image was loaded
867 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
868 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
869 RETURN_INVALID_PARAMETER if the image address is invalid
870
871 --*/
872 {
873 RETURN_STATUS Status;
874 EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
875 EFI_TE_IMAGE_HEADER *TeHdr;
876 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
877 EFI_IMAGE_SECTION_HEADER *FirstSection;
878 EFI_IMAGE_SECTION_HEADER *Section;
879 UINTN NumberOfSections;
880 UINTN Index;
881 CHAR8 *Base;
882 CHAR8 *End;
883 CHAR8 *MaxEnd;
884 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
885 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
886 UINTN Size;
887 UINT32 TempDebugEntryRva;
888 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
889
890 PeHdr = NULL;
891 TeHdr = NULL;
892 OptionHeader.Header = NULL;
893 //
894 // Assume success
895 //
896 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
897
898 //
899 // Copy the provided context info into our local version, get what we
900 // can from the original image, and then use that to make sure everything
901 // is legit.
902 //
903 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
904
905 Status = PeCoffLoaderGetImageInfo (&CheckContext);
906 if (RETURN_ERROR (Status)) {
907 return Status;
908 }
909
910 //
911 // Make sure there is enough allocated space for the image being loaded
912 //
913 if (ImageContext->ImageSize < CheckContext.ImageSize) {
914 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
915 return RETURN_BUFFER_TOO_SMALL;
916 }
917
918 //
919 // If there's no relocations, then make sure it's not a runtime driver,
920 // and that it's being loaded at the linked address.
921 //
922 if (CheckContext.RelocationsStripped) {
923 //
924 // If the image does not contain relocations and it is a runtime driver
925 // then return an error.
926 //
927 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
928 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
929 return RETURN_LOAD_ERROR;
930 }
931 //
932 // If the image does not contain relocations, and the requested load address
933 // is not the linked address, then return an error.
934 //
935 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
936 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
937 return RETURN_INVALID_PARAMETER;
938 }
939 }
940 //
941 // Make sure the allocated space has the proper section alignment
942 //
943 if (!(ImageContext->IsTeImage)) {
944 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
945 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
946 return RETURN_INVALID_PARAMETER;
947 }
948 }
949 //
950 // Read the entire PE/COFF or TE header into memory
951 //
952 if (!(ImageContext->IsTeImage)) {
953 Status = ImageContext->ImageRead (
954 ImageContext->Handle,
955 0,
956 &ImageContext->SizeOfHeaders,
957 (VOID *) (UINTN) ImageContext->ImageAddress
958 );
959
960 PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
961 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
962
963 OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
964
965 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
966 (UINTN)ImageContext->ImageAddress +
967 ImageContext->PeCoffHeaderOffset +
968 sizeof(UINT32) +
969 sizeof(EFI_IMAGE_FILE_HEADER) +
970 PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
971 );
972 NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
973 } else {
974 Status = ImageContext->ImageRead (
975 ImageContext->Handle,
976 0,
977 &ImageContext->SizeOfHeaders,
978 (VOID *) (UINTN) ImageContext->ImageAddress
979 );
980
981 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
982
983 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
984 (UINTN)ImageContext->ImageAddress +
985 sizeof(EFI_TE_IMAGE_HEADER)
986 );
987 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
988
989 }
990
991 if (RETURN_ERROR (Status)) {
992 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
993 return RETURN_LOAD_ERROR;
994 }
995
996 //
997 // Load each section of the image
998 //
999 Section = FirstSection;
1000 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
1001
1002 //
1003 // Compute sections address
1004 //
1005 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
1006 End = PeCoffLoaderImageAddress (
1007 ImageContext,
1008 Section->VirtualAddress + Section->Misc.VirtualSize - 1
1009 );
1010
1011 //
1012 // If the base start or end address resolved to 0, then fail.
1013 //
1014 if ((Base == NULL) || (End == NULL)) {
1015 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1016 return RETURN_LOAD_ERROR;
1017 }
1018
1019
1020 if (ImageContext->IsTeImage) {
1021 Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1022 End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
1023 }
1024
1025 if (End > MaxEnd) {
1026 MaxEnd = End;
1027 }
1028
1029 //
1030 // Read the section
1031 //
1032 Size = (UINTN) Section->Misc.VirtualSize;
1033 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1034 Size = (UINTN) Section->SizeOfRawData;
1035 }
1036
1037 if (Section->SizeOfRawData) {
1038 if (!(ImageContext->IsTeImage)) {
1039 Status = ImageContext->ImageRead (
1040 ImageContext->Handle,
1041 Section->PointerToRawData,
1042 &Size,
1043 Base
1044 );
1045 } else {
1046 Status = ImageContext->ImageRead (
1047 ImageContext->Handle,
1048 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1049 &Size,
1050 Base
1051 );
1052 }
1053
1054 if (RETURN_ERROR (Status)) {
1055 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1056 return Status;
1057 }
1058 }
1059
1060 //
1061 // If raw size is less then virt size, zero fill the remaining
1062 //
1063
1064 if (Size < Section->Misc.VirtualSize) {
1065 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1066 }
1067
1068 //
1069 // Next Section
1070 //
1071 Section += 1;
1072 }
1073
1074 //
1075 // Get image's entry point
1076 //
1077 if (!(ImageContext->IsTeImage)) {
1078 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1079 ImageContext,
1080 PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
1081 );
1082 } else {
1083 ImageContext->EntryPoint = (UINTN)ImageContext->ImageAddress +
1084 (UINTN)TeHdr->AddressOfEntryPoint +
1085 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1086 (UINTN) TeHdr->StrippedSize;
1087 }
1088
1089 //
1090 // Determine the size of the fixup data
1091 //
1092 // Per the PE/COFF spec, you can't assume that a given data directory
1093 // is present in the image. You have to check the NumberOfRvaAndSizes in
1094 // the optional header to verify a desired directory entry is there.
1095 //
1096 if (!(ImageContext->IsTeImage)) {
1097 if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1098 if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1099 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1100 &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1101 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1102 } else {
1103 ImageContext->FixupDataSize = 0;
1104 }
1105 } else {
1106 if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1107 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1108 &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1109 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1110 } else {
1111 ImageContext->FixupDataSize = 0;
1112 }
1113 }
1114 } else {
1115 DirectoryEntry = &TeHdr->DataDirectory[0];
1116 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1117 }
1118 //
1119 // Consumer must allocate a buffer for the relocation fixup log.
1120 // Only used for runtime drivers.
1121 //
1122 ImageContext->FixupData = NULL;
1123
1124 //
1125 // Load the Codeview info if present
1126 //
1127 if (ImageContext->DebugDirectoryEntryRva != 0) {
1128 if (!(ImageContext->IsTeImage)) {
1129 DebugEntry = PeCoffLoaderImageAddress (
1130 ImageContext,
1131 ImageContext->DebugDirectoryEntryRva
1132 );
1133 } else {
1134 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1135 ImageContext->ImageAddress +
1136 ImageContext->DebugDirectoryEntryRva +
1137 sizeof(EFI_TE_IMAGE_HEADER) -
1138 TeHdr->StrippedSize
1139 );
1140 }
1141
1142 if (DebugEntry != NULL) {
1143 TempDebugEntryRva = DebugEntry->RVA;
1144 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1145 Section--;
1146 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1147 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1148 } else {
1149 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1150 }
1151 }
1152
1153 if (TempDebugEntryRva != 0) {
1154 if (!(ImageContext->IsTeImage)) {
1155 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1156 } else {
1157 ImageContext->CodeView = (VOID *)(
1158 (UINTN)ImageContext->ImageAddress +
1159 (UINTN)TempDebugEntryRva +
1160 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1161 (UINTN) TeHdr->StrippedSize
1162 );
1163 }
1164
1165 if (ImageContext->CodeView == NULL) {
1166 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1167 return RETURN_LOAD_ERROR;
1168 }
1169
1170 if (DebugEntry->RVA == 0) {
1171 Size = DebugEntry->SizeOfData;
1172 if (!(ImageContext->IsTeImage)) {
1173 Status = ImageContext->ImageRead (
1174 ImageContext->Handle,
1175 DebugEntry->FileOffset,
1176 &Size,
1177 ImageContext->CodeView
1178 );
1179 } else {
1180 Status = ImageContext->ImageRead (
1181 ImageContext->Handle,
1182 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1183 &Size,
1184 ImageContext->CodeView
1185 );
1186 //
1187 // Should we apply fix up to this field according to the size difference between PE and TE?
1188 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1189 // in original PE image.
1190 //
1191 }
1192
1193 if (RETURN_ERROR (Status)) {
1194 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1195 return RETURN_LOAD_ERROR;
1196 }
1197
1198 DebugEntry->RVA = TempDebugEntryRva;
1199 }
1200
1201 switch (*(UINT32 *) ImageContext->CodeView) {
1202 case CODEVIEW_SIGNATURE_NB10:
1203 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1204 break;
1205
1206 case CODEVIEW_SIGNATURE_RSDS:
1207 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1208 break;
1209
1210 case CODEVIEW_SIGNATURE_MTOC:
1211 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1212
1213 default:
1214 break;
1215 }
1216 }
1217 }
1218 }
1219
1220 return Status;
1221 }
1222
1223 /**
1224 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1225 loaded into system memory with the PE/COFF Loader Library functions.
1226
1227 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1228 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1229 returned. If the PE/COFF image specified by Pe32Data does not contain a
1230 debug directory entry, then NULL is returned. If the debug directory entry
1231 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1232 then NULL is returned.
1233 If Pe32Data is NULL, then return NULL.
1234
1235 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1236 memory.
1237
1238 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1239 if it cannot be retrieved.
1240
1241 **/
1242 VOID *
1243 EFIAPI
1244 PeCoffLoaderGetPdbPointer (
1245 IN VOID *Pe32Data
1246 )
1247 {
1248 EFI_IMAGE_DOS_HEADER *DosHdr;
1249 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1250 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1251 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1252 UINTN DirCount;
1253 VOID *CodeViewEntryPointer;
1254 INTN TEImageAdjust;
1255 UINT32 NumberOfRvaAndSizes;
1256 UINT16 Magic;
1257 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1258 UINT32 Index, Index1;
1259
1260 if (Pe32Data == NULL) {
1261 return NULL;
1262 }
1263
1264 TEImageAdjust = 0;
1265 DirectoryEntry = NULL;
1266 DebugEntry = NULL;
1267 NumberOfRvaAndSizes = 0;
1268 Index = 0;
1269 Index1 = 0;
1270 SectionHeader = NULL;
1271
1272 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1273 if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
1274 //
1275 // DOS image header is present, so read the PE header after the DOS image header.
1276 //
1277 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1278 } else {
1279 //
1280 // DOS image header is not present, so PE header is at the image base.
1281 //
1282 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1283 }
1284
1285 if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
1286 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
1287 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
1288 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
1289
1290 //
1291 // Get the DebugEntry offset in the raw data image.
1292 //
1293 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
1294 Index = Hdr.Te->NumberOfSections;
1295 for (Index1 = 0; Index1 < Index; Index1 ++) {
1296 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1297 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1298 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
1299 DirectoryEntry->VirtualAddress -
1300 SectionHeader [Index1].VirtualAddress +
1301 SectionHeader [Index1].PointerToRawData +
1302 TEImageAdjust);
1303 break;
1304 }
1305 }
1306 }
1307 } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
1308 //
1309 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1310 // It is due to backward-compatibility, for some system might
1311 // generate PE32+ image with PE32 Magic.
1312 //
1313 switch (Hdr.Pe32->FileHeader.Machine) {
1314 case EFI_IMAGE_MACHINE_IA32:
1315 case EFI_IMAGE_MACHINE_ARMT:
1316 //
1317 // Assume PE32 image with IA32 Machine field.
1318 //
1319 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1320 break;
1321 case EFI_IMAGE_MACHINE_X64:
1322 case EFI_IMAGE_MACHINE_IPF:
1323 //
1324 // Assume PE32+ image with X64 or IPF Machine field
1325 //
1326 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1327 break;
1328 default:
1329 //
1330 // For unknow Machine field, use Magic in optional Header
1331 //
1332 Magic = Hdr.Pe32->OptionalHeader.Magic;
1333 }
1334
1335 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
1336 (UINT8 *) Hdr.Pe32 +
1337 sizeof (UINT32) +
1338 sizeof (EFI_IMAGE_FILE_HEADER) +
1339 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1340 );
1341 Index = Hdr.Pe32->FileHeader.NumberOfSections;
1342
1343 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
1344 //
1345 // Use PE32 offset get Debug Directory Entry
1346 //
1347 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1348 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1349 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1350 //
1351 // Use PE32+ offset get Debug Directory Entry
1352 //
1353 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1354 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
1355 }
1356
1357 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
1358 DirectoryEntry = NULL;
1359 DebugEntry = NULL;
1360 } else {
1361 //
1362 // Get the DebugEntry offset in the raw data image.
1363 //
1364 for (Index1 = 0; Index1 < Index; Index1 ++) {
1365 if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
1366 (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1367 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
1368 (UINTN) Pe32Data +
1369 DirectoryEntry->VirtualAddress -
1370 SectionHeader[Index1].VirtualAddress +
1371 SectionHeader[Index1].PointerToRawData);
1372 break;
1373 }
1374 }
1375 }
1376 } else {
1377 return NULL;
1378 }
1379
1380 if (NULL == DebugEntry || NULL == DirectoryEntry) {
1381 return NULL;
1382 }
1383
1384 //
1385 // Scan the directory to find the debug entry.
1386 //
1387 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
1388 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
1389 if (DebugEntry->SizeOfData > 0) {
1390 //
1391 // Get the DebugEntry offset in the raw data image.
1392 //
1393 CodeViewEntryPointer = NULL;
1394 for (Index1 = 0; Index1 < Index; Index1 ++) {
1395 if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
1396 (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
1397 CodeViewEntryPointer = (VOID *) (
1398 ((UINTN)Pe32Data) +
1399 (UINTN) DebugEntry->RVA -
1400 SectionHeader[Index1].VirtualAddress +
1401 SectionHeader[Index1].PointerToRawData +
1402 (UINTN)TEImageAdjust);
1403 break;
1404 }
1405 }
1406 if (Index1 >= Index) {
1407 //
1408 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1409 //
1410 continue;
1411 }
1412 switch (* (UINT32 *) CodeViewEntryPointer) {
1413 case CODEVIEW_SIGNATURE_NB10:
1414 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
1415 case CODEVIEW_SIGNATURE_RSDS:
1416 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
1417 case CODEVIEW_SIGNATURE_MTOC:
1418 return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
1419 default:
1420 break;
1421 }
1422 }
1423 }
1424 }
1425
1426 return NULL;
1427 }
1428
1429
1430 RETURN_STATUS
1431 EFIAPI
1432 PeCoffLoaderGetEntryPoint (
1433 IN VOID *Pe32Data,
1434 OUT VOID **EntryPoint,
1435 OUT VOID **BaseOfImage
1436 )
1437 {
1438 EFI_IMAGE_DOS_HEADER *DosHdr;
1439 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1440
1441 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
1442 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1443 //
1444 // DOS image header is present, so read the PE header after the DOS image header.
1445 //
1446 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
1447 } else {
1448 //
1449 // DOS image header is not present, so PE header is at the image base.
1450 //
1451 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
1452 }
1453
1454 //
1455 // Calculate the entry point relative to the start of the image.
1456 // AddressOfEntryPoint is common for PE32 & PE32+
1457 //
1458 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
1459 *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
1460 *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
1461 return RETURN_SUCCESS;
1462 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
1463 *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;
1464 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1465 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;
1466 } else {
1467 *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;
1468 }
1469 *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);
1470 return RETURN_SUCCESS;
1471 }
1472
1473 return RETURN_UNSUPPORTED;
1474 }