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