]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Library/EdkPeCoffLoaderX64Lib/EdkPeCoffLoaderX64.c
1. adjust contents layout of SPD header editor, FPD header editor.
[mirror_edk2.git] / EdkModulePkg / Library / EdkPeCoffLoaderX64Lib / EdkPeCoffLoaderX64.c
1 /*++
2
3 Copyright (c) 2006, 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 EdkPeCoffLoaderX64.c
15
16 Abstract:
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
28 STATIC
29 EFI_STATUS
30 PeCoffLoader64GetPeHeader (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
32 OUT EFI_IMAGE_NT_HEADERS64 *PeHdr
33 );
34
35 STATIC
36 EFI_STATUS
37 PeCoffLoader64CheckImageType (
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
39 IN EFI_IMAGE_NT_HEADERS64 *PeHdr
40 );
41
42 STATIC
43 VOID *
44 PeCoffLoader64ImageAddress (
45 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
46 IN UINTN Address
47 );
48
49 EFI_STATUS
50 EFIAPI
51 PeCoffLoader64GetImageInfo (
52 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
53 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
54 );
55
56 EFI_STATUS
57 EFIAPI
58 PeCoffLoader64RelocateImage (
59 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
60 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
61 );
62
63 EFI_STATUS
64 EFIAPI
65 PeCoffLoader64LoadImage (
66 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
67 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
68 );
69
70 EFI_STATUS
71 EFIAPI
72 PeCoffLoader64UnloadImage (
73 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
74 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
75 );
76
77 EFI_STATUS
78 PeCoffLoader64RelocateImageEx (
79 IN UINT16 *Reloc,
80 IN OUT CHAR8 *Fixup,
81 IN OUT CHAR8 **FixupData,
82 IN UINT64 Adjust
83 );
84
85 EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoaderX64 = {
86 PeCoffLoader64GetImageInfo,
87 PeCoffLoader64LoadImage,
88 PeCoffLoader64RelocateImage,
89 PeCoffLoader64UnloadImage
90 };
91
92 STATIC
93 EFI_STATUS
94 PeCoffLoader64GetPeHeader (
95 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
96 OUT EFI_IMAGE_NT_HEADERS64 *PeHdr
97 )
98 /*++
99
100 Routine Description:
101 Retrieves the PE Header from a PE/COFF image
102
103 Arguments:
104 ImageContext - The context of the image being loaded
105 PeHdr - The buffer in which to return the PE header
106
107 Returns:
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
158 static
159 EFI_STATUS
160 PeCoffLoader64CheckImageType (
161 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
162 IN EFI_IMAGE_NT_HEADERS64 *PeHdr
163 )
164 /*++
165
166 Routine Description:
167 Checks the PE header of a PE/COFF image to determine if it supported
168
169 Arguments:
170 ImageContext - The context of the image being loaded
171 PeHdr - The buffer in which to return the PE header
172
173 Returns:
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
228 EFI_STATUS
229 EFIAPI
230 PeCoffLoader64GetImageInfo (
231 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
232 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
233 )
234 /*++
235
236 Routine Description:
237 Retrieves information on a PE/COFF image
238
239 Arguments:
240 ImageContext - The context of the image being loaded
241 PeHdr - The buffer in which to return the PE header
242
243 Returns:
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
402 static
403 VOID *
404 PeCoffLoader64ImageAddress (
405 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
406 IN UINTN Address
407 )
408 /*++
409
410 Routine Description:
411 Converts an image address to the loaded address
412
413 Arguments:
414 ImageContext - The context of the image being loaded
415 Address - The address to be converted to the loaded address
416
417 Returns:
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
429 EFI_STATUS
430 EFIAPI
431 PeCoffLoader64RelocateImage (
432 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
433 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
434 )
435 /*++
436
437 Routine Description:
438 Relocates a PE/COFF image in memory
439
440 Arguments:
441 ImageContext - Contains information on the loaded image to relocate
442
443 Returns:
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
593 EFI_STATUS
594 PeCoffLoader64RelocateImageEx (
595 IN UINT16 *Reloc,
596 IN OUT CHAR8 *Fixup,
597 IN OUT CHAR8 **FixupData,
598 IN UINT64 Adjust
599 )
600 /*++
601
602 Routine Description:
603 Performs an IA-32 specific relocation fixup
604
605 Arguments:
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
611 Returns:
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
639 EFI_STATUS
640 EFIAPI
641 PeCoffLoader64LoadImage (
642 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
643 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
644 )
645 /*++
646
647 Routine Description:
648 Loads a PE/COFF image into memory
649
650 Arguments:
651 ImageContext - Contains information on image to load into memory
652
653 Returns:
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
910 EFI_STATUS
911 EFIAPI
912 PeCoffLoader64UnloadImage (
913 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
914 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
915 )
916 /*++
917
918 Routine Description:
919 Unload of images is not supported
920
921 Arguments:
922 ImageContext - The image to unload
923
924 Returns:
925 EFI_SUCCESS
926
927 --*/
928 {
929 return EFI_SUCCESS;
930 }
931
932 EFI_PEI_PE_COFF_LOADER_PROTOCOL *
933 EFIAPI
934 GetPeCoffLoaderX64Protocol (
935 )
936 {
937 return &mPeCoffLoaderX64;
938 }
939
940