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