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