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