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