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