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