]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/TianoTools/Common/PeiLib/PeCoffLoader.c
0e84319f696291ad85e0c4646f7d3731313ad29b
[mirror_edk2.git] / Tools / Source / TianoTools / Common / PeiLib / PeCoffLoader.c
1 /*++
2
3 Copyright (c) 2004 - 2005, Intel Corporation
4 All rights reserved. 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_NT_HEADERS *PeHdr,
40 OUT EFI_TE_IMAGE_HEADER *TeHdr
41 );
42
43 STATIC
44 EFI_STATUS
45 PeCoffLoaderCheckImageType (
46 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
47 IN EFI_IMAGE_NT_HEADERS *PeHdr,
48 IN EFI_TE_IMAGE_HEADER *TeHdr
49 );
50
51 STATIC
52 VOID *
53 PeCoffLoaderImageAddress (
54 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
55 IN UINTN Address
56 );
57
58 EFI_STATUS
59 EFIAPI
60 PeCoffLoaderGetImageInfo (
61 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
62 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
63 );
64
65 EFI_STATUS
66 EFIAPI
67 PeCoffLoaderRelocateImage (
68 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
69 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
70 );
71
72 EFI_STATUS
73 EFIAPI
74 PeCoffLoaderLoadImage (
75 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
76 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
77 );
78
79 EFI_STATUS
80 EFIAPI
81 PeCoffLoaderUnloadImage (
82 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
83 );
84
85 EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader = {
86 PeCoffLoaderGetImageInfo,
87 PeCoffLoaderLoadImage,
88 PeCoffLoaderRelocateImage,
89 PeCoffLoaderUnloadImage
90 };
91
92 #ifdef EFI_NT_EMULATOR
93 EFI_NT_LOAD_AS_DLL_PPI *mPeCoffLoaderWinNtLoadAsDll = NULL;
94 #endif
95
96 EFI_STATUS
97 InstallEfiPeiPeCoffLoader (
98 IN EFI_PEI_SERVICES **PeiServices,
99 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL **This,
100 IN EFI_PEI_PPI_DESCRIPTOR *ThisPpi
101 )
102 /*++
103
104 Routine Description:
105
106 Install PE/COFF loader PPI
107
108 Arguments:
109
110 PeiServices - General purpose services available to every PEIM
111
112 This - Pointer to get Pei PE coff loader protocol as output
113
114 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform
115
116 Returns:
117
118 EFI_SUCCESS
119
120 --*/
121 {
122 EFI_STATUS Status;
123
124 Status = EFI_SUCCESS;
125
126 #ifdef EFI_NT_EMULATOR
127 //
128 // For use by PEI Core and Modules
129 //
130 if (NULL != PeiServices) {
131 Status = (**PeiServices).LocatePpi (
132 PeiServices,
133 &gEfiNtLoadAsDllPpiGuid,
134 0,
135 NULL,
136 &mPeCoffLoaderWinNtLoadAsDll
137 );
138 } else {
139 //
140 // Now in SecMain or ERM usage, bind appropriately
141 //
142 PEI_ASSERT (PeiServices, (NULL != ThisPpi));
143
144 mPeCoffLoaderWinNtLoadAsDll = (EFI_NT_LOAD_AS_DLL_PPI *) ThisPpi;
145 PEI_ASSERT (PeiServices, (NULL != mPeCoffLoaderWinNtLoadAsDll));
146 }
147 #endif
148
149 if (NULL != This) {
150 *This = &mPeCoffLoader;
151 }
152
153 return Status;
154 }
155
156 STATIC
157 EFI_STATUS
158 PeCoffLoaderGetPeHeader (
159 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
160 OUT EFI_IMAGE_NT_HEADERS *PeHdr,
161 OUT EFI_TE_IMAGE_HEADER *TeHdr
162 )
163 /*++
164
165 Routine Description:
166
167 Retrieves the PE or TE Header from a PE/COFF or TE image
168
169 Arguments:
170
171 ImageContext - The context of the image being loaded
172
173 PeHdr - The buffer in which to return the PE header
174
175 TeHdr - The buffer in which to return the TE header
176
177 Returns:
178
179 EFI_SUCCESS if the PE or TE Header is read,
180 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
181
182 --*/
183 {
184 EFI_STATUS Status;
185 EFI_IMAGE_DOS_HEADER DosHdr;
186 UINTN Size;
187
188 ImageContext->IsTeImage = FALSE;
189 //
190 // Read the DOS image headers
191 //
192 Size = sizeof (EFI_IMAGE_DOS_HEADER);
193 Status = ImageContext->ImageRead (
194 ImageContext->Handle,
195 0,
196 &Size,
197 &DosHdr
198 );
199 if (EFI_ERROR (Status)) {
200 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
201 return Status;
202 }
203
204 ImageContext->PeCoffHeaderOffset = 0;
205 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
206 //
207 // DOS image header is present, so read the PE header after the DOS image header
208 //
209 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
210 }
211 //
212 // Read the PE/COFF Header
213 //
214 Size = sizeof (EFI_IMAGE_NT_HEADERS);
215 Status = ImageContext->ImageRead (
216 ImageContext->Handle,
217 ImageContext->PeCoffHeaderOffset,
218 &Size,
219 PeHdr
220 );
221 if (EFI_ERROR (Status)) {
222 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
223 return Status;
224 }
225 //
226 // Check the PE/COFF Header Signature. If not, then try to read a TE header
227 //
228 if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
229 Size = sizeof (EFI_TE_IMAGE_HEADER);
230 Status = ImageContext->ImageRead (
231 ImageContext->Handle,
232 0,
233 &Size,
234 TeHdr
235 );
236 if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
237 return EFI_UNSUPPORTED;
238 }
239
240 ImageContext->IsTeImage = TRUE;
241 }
242
243 return EFI_SUCCESS;
244 }
245
246 STATIC
247 EFI_STATUS
248 PeCoffLoaderCheckImageType (
249 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
250 IN EFI_IMAGE_NT_HEADERS *PeHdr,
251 IN EFI_TE_IMAGE_HEADER *TeHdr
252 )
253 /*++
254
255 Routine Description:
256
257 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
258
259 Arguments:
260
261 ImageContext - The context of the image being loaded
262
263 PeHdr - The buffer in which to return the PE header
264
265 TeHdr - The buffer in which to return the TE header
266
267 Returns:
268
269 EFI_SUCCESS if the PE/COFF or TE image is supported
270 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.
271
272 --*/
273 {
274 //
275 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
276 // and the machine type for the Virtual Machine.
277 //
278 if (ImageContext->IsTeImage == FALSE) {
279 ImageContext->Machine = PeHdr->FileHeader.Machine;
280 } else {
281 ImageContext->Machine = TeHdr->Machine;
282 }
283
284 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {
285 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE;
286 return EFI_UNSUPPORTED;
287 }
288
289 //
290 // See if the image type is supported. We support EFI Applications,
291 // EFI Boot Service Drivers, and EFI Runtime Drivers.
292 //
293 if (ImageContext->IsTeImage == FALSE) {
294 ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;
295 } else {
296 ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
297 }
298
299 switch (ImageContext->ImageType) {
300
301 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
302 ImageContext->ImageCodeMemoryType = EfiLoaderCode;
303 ImageContext->ImageDataMemoryType = EfiLoaderData;
304 break;
305
306 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
307 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;
308 ImageContext->ImageDataMemoryType = EfiBootServicesData;
309 break;
310
311 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
312 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
313 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;
314 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;
315 break;
316
317 default:
318 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;
319 return EFI_UNSUPPORTED;
320 }
321
322 return EFI_SUCCESS;
323 }
324
325 EFI_STATUS
326 EFIAPI
327 PeCoffLoaderGetImageInfo (
328 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
329 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
330 )
331 /*++
332
333 Routine Description:
334
335 Retrieves information on a PE/COFF image
336
337 Arguments:
338
339 This - Calling context
340 ImageContext - The context of the image being loaded
341
342 Returns:
343
344 EFI_SUCCESS - The information on the PE/COFF image was collected.
345 EFI_INVALID_PARAMETER - ImageContext is NULL.
346 EFI_UNSUPPORTED - The PE/COFF image is not supported.
347 Otherwise - The error status from reading the PE/COFF image using the
348 ImageContext->ImageRead() function
349
350 --*/
351 {
352 EFI_STATUS Status;
353 EFI_IMAGE_NT_HEADERS PeHdr;
354 EFI_TE_IMAGE_HEADER TeHdr;
355 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
356 UINTN Size;
357 UINTN Index;
358 UINTN DebugDirectoryEntryRva;
359 UINTN DebugDirectoryEntryFileOffset;
360 UINTN SectionHeaderOffset;
361 EFI_IMAGE_SECTION_HEADER SectionHeader;
362 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
363
364 if (NULL == ImageContext) {
365 return EFI_INVALID_PARAMETER;
366 }
367 //
368 // Assume success
369 //
370 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;
371
372 Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
373 if (EFI_ERROR (Status)) {
374 return Status;
375 }
376 //
377 // Verify machine type
378 //
379 Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr);
380 if (EFI_ERROR (Status)) {
381 return Status;
382 }
383 //
384 // Retrieve the base address of the image
385 //
386 if (!(ImageContext->IsTeImage)) {
387 ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;
388 } else {
389 ImageContext->ImageAddress = (EFI_PHYSICAL_ADDRESS) (TeHdr.ImageBase);
390 }
391 //
392 // Initialize the alternate destination address to 0 indicating that it
393 // should not be used.
394 //
395 ImageContext->DestinationAddress = 0;
396
397 //
398 // Initialize the codeview pointer.
399 //
400 ImageContext->CodeView = NULL;
401 ImageContext->PdbPointer = NULL;
402
403 //
404 // Three cases with regards to relocations:
405 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
406 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
407 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
408 // has no base relocs to apply
409 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
410 //
411 // Look at the file header to determine if relocations have been stripped, and
412 // save this info in the image context for later use.
413 //
414 if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
415 ImageContext->RelocationsStripped = TRUE;
416 } else {
417 ImageContext->RelocationsStripped = FALSE;
418 }
419
420 if (!(ImageContext->IsTeImage)) {
421 ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage;
422 ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;
423 ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders;
424
425 //
426 // Modify ImageSize to contain .PDB file name if required and initialize
427 // PdbRVA field...
428 //
429 if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
430 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
431
432 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
433
434 //
435 // Determine the file offset of the debug directory... This means we walk
436 // the sections to find which section contains the RVA of the debug
437 // directory
438 //
439 DebugDirectoryEntryFileOffset = 0;
440
441 SectionHeaderOffset = (UINTN)(
442 ImageContext->PeCoffHeaderOffset +
443 sizeof (UINT32) +
444 sizeof (EFI_IMAGE_FILE_HEADER) +
445 PeHdr.FileHeader.SizeOfOptionalHeader
446 );
447
448 for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) {
449 //
450 // Read section header from file
451 //
452 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
453 Status = ImageContext->ImageRead (
454 ImageContext->Handle,
455 SectionHeaderOffset,
456 &Size,
457 &SectionHeader
458 );
459 if (EFI_ERROR (Status)) {
460 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
461 return Status;
462 }
463
464 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
465 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
466 DebugDirectoryEntryFileOffset =
467 DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
468 break;
469 }
470
471 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
472 }
473
474 if (DebugDirectoryEntryFileOffset != 0) {
475 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {
476 //
477 // Read next debug directory entry
478 //
479 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
480 Status = ImageContext->ImageRead (
481 ImageContext->Handle,
482 DebugDirectoryEntryFileOffset,
483 &Size,
484 &DebugEntry
485 );
486 if (EFI_ERROR (Status)) {
487 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
488 return Status;
489 }
490
491 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
492 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
493 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
494 ImageContext->ImageSize += DebugEntry.SizeOfData;
495 }
496
497 return EFI_SUCCESS;
498 }
499 }
500 }
501 }
502 } else {
503 ImageContext->ImageSize = 0;
504 ImageContext->SectionAlignment = 4096;
505 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize;
506
507 DebugDirectoryEntry = &TeHdr.DataDirectory[1];
508 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
509 SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
510
511 DebugDirectoryEntryFileOffset = 0;
512
513 for (Index = 0; Index < TeHdr.NumberOfSections;) {
514 //
515 // Read section header from file
516 //
517 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
518 Status = ImageContext->ImageRead (
519 ImageContext->Handle,
520 SectionHeaderOffset,
521 &Size,
522 &SectionHeader
523 );
524 if (EFI_ERROR (Status)) {
525 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
526 return Status;
527 }
528
529 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
530 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
531 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
532 SectionHeader.VirtualAddress +
533 SectionHeader.PointerToRawData +
534 sizeof (EFI_TE_IMAGE_HEADER) -
535 TeHdr.StrippedSize;
536
537 //
538 // File offset of the debug directory was found, if this is not the last
539 // section, then skip to the last section for calculating the image size.
540 //
541 if (Index < (UINTN) TeHdr.NumberOfSections - 1) {
542 SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
543 Index = TeHdr.NumberOfSections - 1;
544 continue;
545 }
546 }
547
548 //
549 // In Te image header there is not a field to describe the ImageSize.
550 // Actually, the ImageSize equals the RVA plus the VirtualSize of
551 // the last section mapped into memory (Must be rounded up to
552 // a mulitple of Section Alignment). Per the PE/COFF specification, the
553 // section headers in the Section Table must appear in order of the RVA
554 // values for the corresponding sections. So the ImageSize can be determined
555 // by the RVA and the VirtualSize of the last section header in the
556 // Section Table.
557 //
558 if ((++Index) == (UINTN) TeHdr.NumberOfSections) {
559 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
560 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
561 }
562
563 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
564 }
565
566 if (DebugDirectoryEntryFileOffset != 0) {
567 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {
568 //
569 // Read next debug directory entry
570 //
571 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
572 Status = ImageContext->ImageRead (
573 ImageContext->Handle,
574 DebugDirectoryEntryFileOffset,
575 &Size,
576 &DebugEntry
577 );
578 if (EFI_ERROR (Status)) {
579 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
580 return Status;
581 }
582
583 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
584 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
585 return EFI_SUCCESS;
586 }
587 }
588 }
589 }
590
591 return EFI_SUCCESS;
592 }
593
594 STATIC
595 VOID *
596 PeCoffLoaderImageAddress (
597 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
598 IN UINTN Address
599 )
600 /*++
601
602 Routine Description:
603
604 Converts an image address to the loaded address
605
606 Arguments:
607
608 ImageContext - The context of the image being loaded
609
610 Address - The address to be converted to the loaded address
611
612 Returns:
613
614 NULL if the address can not be converted, otherwise, the converted address
615
616 --*/
617 {
618 if (Address >= ImageContext->ImageSize) {
619 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
620 return NULL;
621 }
622
623 return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);
624 }
625
626 EFI_STATUS
627 EFIAPI
628 PeCoffLoaderRelocateImage (
629 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
630 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
631 )
632 /*++
633
634 Routine Description:
635
636 Relocates a PE/COFF image in memory
637
638 Arguments:
639
640 This - Calling context
641
642 ImageContext - Contains information on the loaded image to relocate
643
644 Returns:
645
646 EFI_SUCCESS if the PE/COFF image was relocated
647 EFI_LOAD_ERROR if the image is not a valid PE/COFF image
648 EFI_UNSUPPORTED not support
649
650 --*/
651 {
652 EFI_STATUS Status;
653 EFI_IMAGE_NT_HEADERS *PeHdr;
654 EFI_TE_IMAGE_HEADER *TeHdr;
655 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
656 UINT64 Adjust;
657 EFI_IMAGE_BASE_RELOCATION *RelocBase;
658 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
659 UINT16 *Reloc;
660 UINT16 *RelocEnd;
661 CHAR8 *Fixup;
662 CHAR8 *FixupBase;
663 UINT16 *F16;
664 UINT32 *F32;
665 CHAR8 *FixupData;
666 EFI_PHYSICAL_ADDRESS BaseAddress;
667 #ifdef EFI_NT_EMULATOR
668 VOID *DllEntryPoint;
669 VOID *ModHandle;
670 ModHandle = NULL;
671 #endif
672
673 PeHdr = NULL;
674 TeHdr = NULL;
675 //
676 // Assume success
677 //
678 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;
679
680 //
681 // If there are no relocation entries, then we are done
682 //
683 if (ImageContext->RelocationsStripped) {
684 return EFI_SUCCESS;
685 }
686
687 //
688 // If the destination address is not 0, use that rather than the
689 // image address as the relocation target.
690 //
691 if (ImageContext->DestinationAddress) {
692 BaseAddress = ImageContext->DestinationAddress;
693 } else {
694 BaseAddress = ImageContext->ImageAddress;
695 }
696
697 if (!(ImageContext->IsTeImage)) {
698 PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress +
699 ImageContext->PeCoffHeaderOffset);
700 Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;
701 PeHdr->OptionalHeader.ImageBase = (UINTN) BaseAddress;
702
703 //
704 // Find the relocation block
705 //
706 // Per the PE/COFF spec, you can't assume that a given data directory
707 // is present in the image. You have to check the NumberOfRvaAndSizes in
708 // the optional header to verify a desired directory entry is there.
709 //
710 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
711 RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
712 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
713 RelocBaseEnd = PeCoffLoaderImageAddress (
714 ImageContext,
715 RelocDir->VirtualAddress + RelocDir->Size - 1
716 );
717 } else {
718 //
719 // Set base and end to bypass processing below.
720 //
721 RelocBase = RelocBaseEnd = 0;
722 }
723 } else {
724 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
725 Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
726 TeHdr->ImageBase = (UINT64) (BaseAddress);
727
728 //
729 // Find the relocation block
730 //
731 RelocDir = &TeHdr->DataDirectory[0];
732 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
733 ImageContext->ImageAddress +
734 RelocDir->VirtualAddress +
735 sizeof(EFI_TE_IMAGE_HEADER) -
736 TeHdr->StrippedSize
737 );
738 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
739 }
740
741 //
742 // Run the relocation information and apply the fixups
743 //
744 FixupData = ImageContext->FixupData;
745 while (RelocBase < RelocBaseEnd) {
746
747 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
748 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
749 if (!(ImageContext->IsTeImage)) {
750 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
751 } else {
752 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
753 RelocBase->VirtualAddress +
754 sizeof(EFI_TE_IMAGE_HEADER) -
755 TeHdr->StrippedSize
756 );
757 }
758
759 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
760 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
761 (UINTN)ImageContext->ImageSize)) {
762 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;
763 return EFI_LOAD_ERROR;
764 }
765
766 //
767 // Run this relocation record
768 //
769 while (Reloc < RelocEnd) {
770
771 Fixup = FixupBase + (*Reloc & 0xFFF);
772 switch ((*Reloc) >> 12) {
773 case EFI_IMAGE_REL_BASED_ABSOLUTE:
774 break;
775
776 case EFI_IMAGE_REL_BASED_HIGH:
777 F16 = (UINT16 *) Fixup;
778 *F16 = (UINT16) ((*F16 << 16) + (UINT16) Adjust);
779 if (FixupData != NULL) {
780 *(UINT16 *) FixupData = *F16;
781 FixupData = FixupData + sizeof (UINT16);
782 }
783 break;
784
785 case EFI_IMAGE_REL_BASED_LOW:
786 F16 = (UINT16 *) Fixup;
787 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
788 if (FixupData != NULL) {
789 *(UINT16 *) FixupData = *F16;
790 FixupData = FixupData + sizeof (UINT16);
791 }
792 break;
793
794 case EFI_IMAGE_REL_BASED_HIGHLOW:
795 F32 = (UINT32 *) Fixup;
796 *F32 = *F32 + (UINT32) Adjust;
797 if (FixupData != NULL) {
798 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
799 *(UINT32 *) FixupData = *F32;
800 FixupData = FixupData + sizeof (UINT32);
801 }
802 break;
803
804 case EFI_IMAGE_REL_BASED_HIGHADJ:
805 //
806 // Return the same EFI_UNSUPPORTED return code as
807 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
808 // the relocation type.
809 //
810 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;
811 return EFI_UNSUPPORTED;
812
813 default:
814 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
815 if (EFI_ERROR (Status)) {
816 ImageContext->ImageError = EFI_IMAGE_ERROR_FAILED_RELOCATION;
817 return Status;
818 }
819 }
820
821 //
822 // Next relocation record
823 //
824 Reloc += 1;
825 }
826
827 //
828 // Next reloc block
829 //
830 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
831 }
832
833 #ifdef EFI_NT_EMULATOR
834 DllEntryPoint = NULL;
835 ImageContext->ModHandle = NULL;
836 //
837 // Load the DLL if it's not an EBC image.
838 //
839 if ((ImageContext->PdbPointer != NULL) &&
840 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
841 Status = mPeCoffLoaderWinNtLoadAsDll->Entry (
842 ImageContext->PdbPointer,
843 &DllEntryPoint,
844 &ModHandle
845 );
846
847 if (!EFI_ERROR (Status) && DllEntryPoint != NULL) {
848 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
849 ImageContext->ModHandle = ModHandle;
850 }
851 }
852 #endif
853
854 return EFI_SUCCESS;
855 }
856
857 EFI_STATUS
858 EFIAPI
859 PeCoffLoaderLoadImage (
860 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
861 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
862 )
863 /*++
864
865 Routine Description:
866
867 Loads a PE/COFF image into memory
868
869 Arguments:
870
871 This - Calling context
872
873 ImageContext - Contains information on image to load into memory
874
875 Returns:
876
877 EFI_SUCCESS if the PE/COFF image was loaded
878 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
879 EFI_LOAD_ERROR if the image is a runtime driver with no relocations
880 EFI_INVALID_PARAMETER if the image address is invalid
881
882 --*/
883 {
884 EFI_STATUS Status;
885 EFI_IMAGE_NT_HEADERS *PeHdr;
886 EFI_TE_IMAGE_HEADER *TeHdr;
887 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
888 EFI_IMAGE_SECTION_HEADER *FirstSection;
889 EFI_IMAGE_SECTION_HEADER *Section;
890 UINTN NumberOfSections;
891 UINTN Index;
892 CHAR8 *Base;
893 CHAR8 *End;
894 CHAR8 *MaxEnd;
895 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
896 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
897 UINTN Size;
898 UINT32 TempDebugEntryRva;
899
900 PeHdr = NULL;
901 TeHdr = NULL;
902 //
903 // Assume success
904 //
905 ImageContext->ImageError = EFI_IMAGE_ERROR_SUCCESS;
906
907 //
908 // Copy the provided context info into our local version, get what we
909 // can from the original image, and then use that to make sure everything
910 // is legit.
911 //
912 CopyMem (&CheckContext, ImageContext, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT));
913
914 Status = PeCoffLoaderGetImageInfo (
915 This,
916 &CheckContext
917 );
918 if (EFI_ERROR (Status)) {
919 return Status;
920 }
921
922 //
923 // Make sure there is enough allocated space for the image being loaded
924 //
925 if (ImageContext->ImageSize < CheckContext.ImageSize) {
926 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE;
927 return EFI_BUFFER_TOO_SMALL;
928 }
929
930 //
931 // If there's no relocations, then make sure it's not a runtime driver,
932 // and that it's being loaded at the linked address.
933 //
934 if (CheckContext.RelocationsStripped) {
935 //
936 // If the image does not contain relocations and it is a runtime driver
937 // then return an error.
938 //
939 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
940 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SUBSYSTEM;
941 return EFI_LOAD_ERROR;
942 }
943 //
944 // If the image does not contain relocations, and the requested load address
945 // is not the linked address, then return an error.
946 //
947 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
948 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
949 return EFI_INVALID_PARAMETER;
950 }
951 }
952 //
953 // Make sure the allocated space has the proper section alignment
954 //
955 if (!(ImageContext->IsTeImage)) {
956 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
957 ImageContext->ImageError = EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
958 return EFI_INVALID_PARAMETER;
959 }
960 }
961 //
962 // Read the entire PE/COFF or TE header into memory
963 //
964 if (!(ImageContext->IsTeImage)) {
965 Status = ImageContext->ImageRead (
966 ImageContext->Handle,
967 0,
968 &ImageContext->SizeOfHeaders,
969 (VOID *) (UINTN) ImageContext->ImageAddress
970 );
971
972 PeHdr = (EFI_IMAGE_NT_HEADERS *)
973 ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
974
975 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
976 (UINTN)ImageContext->ImageAddress +
977 ImageContext->PeCoffHeaderOffset +
978 sizeof(UINT32) +
979 sizeof(EFI_IMAGE_FILE_HEADER) +
980 PeHdr->FileHeader.SizeOfOptionalHeader
981 );
982 NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);
983 } else {
984 Status = ImageContext->ImageRead (
985 ImageContext->Handle,
986 0,
987 &ImageContext->SizeOfHeaders,
988 (void *) (UINTN) ImageContext->ImageAddress
989 );
990
991 TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
992
993 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
994 (UINTN)ImageContext->ImageAddress +
995 sizeof(EFI_TE_IMAGE_HEADER)
996 );
997 NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
998
999 }
1000
1001 if (EFI_ERROR (Status)) {
1002 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
1003 return EFI_LOAD_ERROR;
1004 }
1005
1006 //
1007 // Load each section of the image
1008 //
1009 Section = FirstSection;
1010 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
1011
1012 //
1013 // Compute sections address
1014 //
1015 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
1016 End = PeCoffLoaderImageAddress (
1017 ImageContext,
1018 Section->VirtualAddress + Section->Misc.VirtualSize - 1
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 // If the base start or end address resolved to 0, then fail.
1030 //
1031 if ((Base == NULL) || (End == NULL)) {
1032 ImageContext->ImageError = EFI_IMAGE_ERROR_SECTION_NOT_LOADED;
1033 return EFI_LOAD_ERROR;
1034 }
1035
1036 //
1037 // Read the section
1038 //
1039 Size = (UINTN) Section->Misc.VirtualSize;
1040 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1041 Size = (UINTN) Section->SizeOfRawData;
1042 }
1043
1044 if (Section->SizeOfRawData) {
1045 if (!(ImageContext->IsTeImage)) {
1046 Status = ImageContext->ImageRead (
1047 ImageContext->Handle,
1048 Section->PointerToRawData,
1049 &Size,
1050 Base
1051 );
1052 } else {
1053 Status = ImageContext->ImageRead (
1054 ImageContext->Handle,
1055 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
1056 &Size,
1057 Base
1058 );
1059 }
1060
1061 if (EFI_ERROR (Status)) {
1062 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
1063 return Status;
1064 }
1065 }
1066
1067 //
1068 // If raw size is less then virt size, zero fill the remaining
1069 //
1070
1071 if (Size < Section->Misc.VirtualSize) {
1072 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1073 }
1074
1075 //
1076 // Next Section
1077 //
1078 Section += 1;
1079 }
1080
1081 //
1082 // Get image's entry point
1083 //
1084 if (!(ImageContext->IsTeImage)) {
1085 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
1086 ImageContext,
1087 PeHdr->OptionalHeader.AddressOfEntryPoint
1088 );
1089 } else {
1090 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (
1091 (UINTN)ImageContext->ImageAddress +
1092 (UINTN)TeHdr->AddressOfEntryPoint +
1093 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1094 (UINTN) TeHdr->StrippedSize
1095 );
1096 }
1097
1098 //
1099 // Determine the size of the fixup data
1100 //
1101 // Per the PE/COFF spec, you can't assume that a given data directory
1102 // is present in the image. You have to check the NumberOfRvaAndSizes in
1103 // the optional header to verify a desired directory entry is there.
1104 //
1105 if (!(ImageContext->IsTeImage)) {
1106 if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1107 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
1108 &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1109 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1110 } else {
1111 ImageContext->FixupDataSize = 0;
1112 }
1113 } else {
1114 DirectoryEntry = &TeHdr->DataDirectory[0];
1115 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1116 }
1117 //
1118 // Consumer must allocate a buffer for the relocation fixup log.
1119 // Only used for runtime drivers.
1120 //
1121 ImageContext->FixupData = NULL;
1122
1123 //
1124 // Load the Codeview info if present
1125 //
1126 if (ImageContext->DebugDirectoryEntryRva != 0) {
1127 if (!(ImageContext->IsTeImage)) {
1128 DebugEntry = PeCoffLoaderImageAddress (
1129 ImageContext,
1130 ImageContext->DebugDirectoryEntryRva
1131 );
1132 } else {
1133 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1134 ImageContext->ImageAddress +
1135 ImageContext->DebugDirectoryEntryRva +
1136 sizeof(EFI_TE_IMAGE_HEADER) -
1137 TeHdr->StrippedSize
1138 );
1139 }
1140
1141 if (DebugEntry != NULL) {
1142 TempDebugEntryRva = DebugEntry->RVA;
1143 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1144 Section--;
1145 if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
1146 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1147 } else {
1148 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1149 }
1150 }
1151
1152 if (TempDebugEntryRva != 0) {
1153 if (!(ImageContext->IsTeImage)) {
1154 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1155 } else {
1156 ImageContext->CodeView = (VOID *)(
1157 (UINTN)ImageContext->ImageAddress +
1158 (UINTN)TempDebugEntryRva +
1159 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
1160 (UINTN) TeHdr->StrippedSize
1161 );
1162 }
1163
1164 if (ImageContext->CodeView == NULL) {
1165 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
1166 return EFI_LOAD_ERROR;
1167 }
1168
1169 if (DebugEntry->RVA == 0) {
1170 Size = DebugEntry->SizeOfData;
1171 if (!(ImageContext->IsTeImage)) {
1172 Status = ImageContext->ImageRead (
1173 ImageContext->Handle,
1174 DebugEntry->FileOffset,
1175 &Size,
1176 ImageContext->CodeView
1177 );
1178 } else {
1179 Status = ImageContext->ImageRead (
1180 ImageContext->Handle,
1181 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
1182 &Size,
1183 ImageContext->CodeView
1184 );
1185 //
1186 // Should we apply fix up to this field according to the size difference between PE and TE?
1187 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1188 // in original PE image.
1189 //
1190 }
1191
1192 if (EFI_ERROR (Status)) {
1193 ImageContext->ImageError = EFI_IMAGE_ERROR_IMAGE_READ;
1194 return EFI_LOAD_ERROR;
1195 }
1196
1197 DebugEntry->RVA = TempDebugEntryRva;
1198 }
1199
1200 switch (*(UINT32 *) ImageContext->CodeView) {
1201 case CODEVIEW_SIGNATURE_NB10:
1202 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1203 break;
1204
1205 case CODEVIEW_SIGNATURE_RSDS:
1206 ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1207 break;
1208
1209 default:
1210 break;
1211 }
1212 }
1213 }
1214 }
1215
1216 return Status;
1217 }
1218
1219 EFI_STATUS
1220 EFIAPI
1221 PeCoffLoaderUnloadImage (
1222 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1223 )
1224 /*++
1225
1226 Routine Description:
1227
1228 Unload a PE/COFF image from memory
1229
1230 Arguments:
1231
1232 ImageContext - Contains information on image to load into memory
1233
1234 Returns:
1235
1236 EFI_SUCCESS
1237
1238 --*/
1239 {
1240 #ifdef EFI_NT_EMULATOR
1241 //
1242 // Calling Win32 API free library
1243 //
1244 mPeCoffLoaderWinNtLoadAsDll->FreeLibrary (ImageContext->ModHandle);
1245
1246 #endif
1247
1248 return EFI_SUCCESS;
1249 }