3 Copyright (c) 2006 - 2007, 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
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.
18 Pei Core Load Image Support
28 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
32 FileHandle - The handle to the PE/COFF file
33 FileOffset - The offset, in bytes, into the file to read
34 ReadSize - The number of bytes to read from the file starting at FileOffset
35 Buffer - A pointer to the buffer to read the data into.
39 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
44 PeiLoadImageLoadImage (
45 IN EFI_PEI_SERVICES
**PeiServices
,
46 IN EFI_PEI_FILE_HANDLE FileHandle
,
47 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
48 OUT UINT64
*ImageSizeArg
, OPTIONAL
49 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
50 OUT UINT32
*AuthenticationState
56 Routine for loading file image.
60 PeiServices - The PEI core services table.
61 FileHandle - Pointer to the FFS file header of the image.
62 ImageAddressArg - Pointer to PE/TE image.
63 ImageSizeArg - Size of PE/TE image.
64 EntryPoint - Pointer to entry point of specified image file for output.
65 AuthenticationState - Pointer to attestation authentication state of image.
69 Status - EFI_SUCCESS - Image is successfully loaded.
70 EFI_NOT_FOUND - Fail to locate necessary PPI
71 Others - Fail to load file.
78 PeiLoadImageLoadImageWrapper (
79 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
80 IN EFI_PEI_FILE_HANDLE FileHandle
,
81 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
82 OUT UINT64
*ImageSizeArg
, OPTIONAL
83 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
84 OUT UINT32
*AuthenticationState
90 The wrapper function of PeiLoadImageLoadImage().
94 This - Pointer to EFI_PEI_LOAD_FILE_PPI.
95 PeiServices - The PEI core services table.
96 FileHandle - Pointer to the FFS file header of the image.
97 ImageAddressArg - Pointer to PE/TE image.
98 ImageSizeArg - Size of PE/TE image.
99 EntryPoint - Pointer to entry point of specified image file for output.
100 AuthenticationState - Pointer to attestation authentication state of image.
109 STATIC EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi
= {
110 PeiLoadImageLoadImageWrapper
114 STATIC EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList
= {
115 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
116 &gEfiPeiLoadFilePpiGuid
,
125 IN OUT UINTN
*ReadSize
,
132 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
136 FileHandle - The handle to the PE/COFF file
137 FileOffset - The offset, in bytes, into the file to read
138 ReadSize - The number of bytes to read from the file starting at FileOffset
139 Buffer - A pointer to the buffer to read the data into.
143 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
151 Destination8
= Buffer
;
152 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
155 *(Destination8
++) = *(Source8
++);
162 GetImageReadFunction (
163 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
169 Support routine to return the Image Read
173 PeiServices - PEI Services Table
175 ImageContext - The context of the image being loaded
179 EFI_SUCCESS - If Image function location is found
185 MemoryBuffer
= AllocatePages (0x400 / EFI_PAGE_SIZE
+ 1);
186 ASSERT (MemoryBuffer
!= NULL
);
188 CopyMem (MemoryBuffer
, (CONST VOID
*) (UINTN
) PeiImageRead
, 0x400);
190 ImageContext
->ImageRead
= (PE_COFF_LOADER_READ_FILE
) (UINTN
) MemoryBuffer
;
197 LoadAndRelocatePeCoffImage (
198 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*PeiEfiPeiPeCoffLoader
,
200 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
201 OUT UINT64
*ImageSize
,
202 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
208 Loads and relocates a PE/COFF image into memory.
212 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
214 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
216 ImageAddress - The base address of the relocated PE/COFF image
218 ImageSize - The size of the relocated PE/COFF image
220 EntryPoint - The entry point of the relocated PE/COFF image
224 EFI_SUCCESS - The file was loaded and relocated
226 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
231 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
233 ASSERT (PeiEfiPeiPeCoffLoader
!= NULL
);
235 ZeroMem (&ImageContext
, sizeof (ImageContext
));
236 ImageContext
.Handle
= Pe32Data
;
237 Status
= GetImageReadFunction (&ImageContext
);
239 ASSERT_EFI_ERROR (Status
);
241 Status
= PeiEfiPeiPeCoffLoader
->GetImageInfo (PeiEfiPeiPeCoffLoader
, &ImageContext
);
242 if (EFI_ERROR (Status
)) {
246 // Allocate Memory for the image
248 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
249 ASSERT (ImageContext
.ImageAddress
!= 0);
252 // Load the image to our new buffer
254 Status
= PeiEfiPeiPeCoffLoader
->LoadImage (PeiEfiPeiPeCoffLoader
, &ImageContext
);
255 if (EFI_ERROR (Status
)) {
259 // Relocate the image in our new buffer
261 Status
= PeiEfiPeiPeCoffLoader
->RelocateImage (PeiEfiPeiPeCoffLoader
, &ImageContext
);
262 if (EFI_ERROR (Status
)) {
267 // Flush the instruction cache so the image data is written before we execute it
269 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
271 *ImageAddress
= ImageContext
.ImageAddress
;
272 *ImageSize
= ImageContext
.ImageSize
;
273 *EntryPoint
= ImageContext
.EntryPoint
;
279 PeiLoadImageLoadImage (
280 IN EFI_PEI_SERVICES
**PeiServices
,
281 IN EFI_PEI_FILE_HANDLE FileHandle
,
282 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
283 OUT UINT64
*ImageSizeArg
, OPTIONAL
284 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
285 OUT UINT32
*AuthenticationState
291 Routine for loading file image.
295 PeiServices - The PEI core services table.
296 FileHandle - Pointer to the FFS file header of the image.
297 ImageAddressArg - Pointer to PE/TE image.
298 ImageSizeArg - Size of PE/TE image.
299 EntryPoint - Pointer to entry point of specified image file for output.
300 AuthenticationState - Pointer to attestation authentication state of image.
304 Status - EFI_SUCCESS - Image is successfully loaded.
305 EFI_NOT_FOUND - Fail to locate necessary PPI
306 Others - Fail to load file.
312 EFI_PHYSICAL_ADDRESS ImageAddress
;
314 EFI_PHYSICAL_ADDRESS ImageEntryPoint
;
315 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
317 PEI_CORE_INSTANCE
*Private
;
321 TEImageHeader
= NULL
;
323 *AuthenticationState
= 0;
326 // Try to find a TE section.
328 Status
= PeiServicesFfsFindSectionData (
333 if (!EFI_ERROR (Status
)) {
334 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*)Pe32Data
;
337 // If we didn't find a PE32 section, try to find a TE section.
339 if (EFI_ERROR (Status
)) {
340 Status
= PeiServicesFfsFindSectionData (
345 if (EFI_ERROR (Status
)) {
347 // PEI core only carry the loader function fro TE and PE32 executables
348 // If this two section does not exist, just return.
354 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
356 if (Private
->PeiMemoryInstalled
&&
357 (Private
->HobList
.HandoffInformationTable
->BootMode
!= BOOT_ON_S3_RESUME
)) {
360 // If memory is installed, perform the shadow operations
362 Status
= LoadAndRelocatePeCoffImage (
363 Private
->PeCoffLoader
,
370 if (EFI_ERROR (Status
)) {
371 return EFI_NOT_FOUND
;
375 // Got the entry point from ImageEntryPoint and ImageStartAddress
377 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
378 *EntryPoint
= ImageEntryPoint
;
381 if (TEImageHeader
!= NULL
) {
383 // Retrieve the entry point from the TE image header
385 ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) TEImageHeader
;
387 *EntryPoint
= (EFI_PHYSICAL_ADDRESS
)((UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) +
388 TEImageHeader
->AddressOfEntryPoint
- TEImageHeader
->StrippedSize
);
391 // Retrieve the entry point from the PE/COFF image header
393 ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Pe32Data
;
395 Status
= PeCoffLoaderGetEntryPoint (Pe32Data
, &EntryPointArg
);
396 *EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) EntryPointArg
;
397 if (EFI_ERROR (Status
)) {
398 return EFI_NOT_FOUND
;
403 if (((EFI_TE_IMAGE_HEADER
*) (UINTN
) ImageAddress
)->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
404 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) ImageAddress
;
405 Machine
= TEImageHeader
->Machine
;
407 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
410 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
411 return EFI_UNSUPPORTED
;
414 if (ImageAddressArg
!= NULL
) {
415 *ImageAddressArg
= ImageAddress
;
418 if (ImageSizeArg
!= NULL
) {
419 *ImageSizeArg
= ImageSize
;
423 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
425 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", (UINTN
) ImageAddress
, *EntryPoint
));
427 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
428 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
432 BOOLEAN FileNameFound
;
434 CHAR8 AsciiBuffer
[512];
435 VOID
*CodeViewEntryPointer
;
437 EFI_IMAGE_DOS_HEADER
*DosHeader
;
438 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
439 UINT32 NumberOfRvaAndSizes
;
442 if (TEImageHeader
== NULL
) {
443 DosHeader
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
444 if (DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
446 // DOS image header is present, so read the PE header after the DOS image header
448 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)Pe32Data
+ (UINTN
)((DosHeader
->e_lfanew
) & 0x0ffff));
451 // DOS image header is not present, so PE header is at the image base
453 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
458 // Find the codeview info in the image and display the file name
461 // Per the PE/COFF spec, you can't assume that a given data directory
462 // is present in the image. You have to check the NumberOfRvaAndSizes in
463 // the optional header to verify a desired directory entry is there.
466 DirectoryEntry
= NULL
;
467 NumberOfRvaAndSizes
= 0;
470 if (TEImageHeader
== NULL
) {
471 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
473 // Use PE32 offset get Debug Directory Entry
475 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
476 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
477 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) ((UINTN
) Pe32Data
+ DirectoryEntry
->VirtualAddress
);
478 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
480 // Use PE32+ offset get Debug Directory Entry
482 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
483 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
484 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) ((UINTN
) Pe32Data
+ DirectoryEntry
->VirtualAddress
);
487 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
488 DirectoryEntry
= NULL
;
492 if (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
493 DirectoryEntry
= &TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
494 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
;
495 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) TEImageHeader
+
496 TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
+
501 if (DebugEntry
!= NULL
&& DirectoryEntry
!= NULL
) {
502 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
503 if (DebugEntry
->Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
504 if (DebugEntry
->SizeOfData
> 0) {
505 CodeViewEntryPointer
= (VOID
*) ((UINTN
) DebugEntry
->RVA
+ (UINTN
) ImageAddress
+ (UINTN
)TEImageAdjust
);
506 switch (* (UINT32
*) CodeViewEntryPointer
) {
507 case CODEVIEW_SIGNATURE_NB10
:
508 AsciiString
= (CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
511 case CODEVIEW_SIGNATURE_RSDS
:
512 AsciiString
= (CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
519 if (AsciiString
!= NULL
) {
520 FileNameFound
= FALSE
;
521 for (Index
= 0, Index1
= 0; AsciiString
[Index
] != '\0'; Index
++) {
522 if (AsciiString
[Index
] == '\\') {
524 FileNameFound
= TRUE
;
529 for (Index
= Index1
+ 1; AsciiString
[Index
] != '.'; Index
++) {
530 AsciiBuffer
[Index
- (Index1
+ 1)] = AsciiString
[Index
];
532 AsciiBuffer
[Index
- (Index1
+ 1)] = 0;
533 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
543 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
552 PeiLoadImageLoadImageWrapper (
553 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
554 IN EFI_PEI_FILE_HANDLE FileHandle
,
555 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
556 OUT UINT64
*ImageSizeArg
, OPTIONAL
557 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
558 OUT UINT32
*AuthenticationState
564 The wrapper function of PeiLoadImageLoadImage().
568 This - Pointer to EFI_PEI_LOAD_FILE_PPI.
569 PeiServices - The PEI core services table.
570 FileHandle - Pointer to the FFS file header of the image.
571 ImageAddressArg - Pointer to PE/TE image.
572 ImageSizeArg - Size of PE/TE image.
573 EntryPoint - Pointer to entry point of specified image file for output.
574 AuthenticationState - Pointer to attestation authentication state of image.
582 return PeiLoadImageLoadImage (
583 GetPeiServicesTablePointer (),
594 IN EFI_PEI_SERVICES
**PeiServices
,
595 IN EFI_PEI_FILE_HANDLE FileHandle
,
596 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
597 OUT UINT32
*AuthenticationState
603 Routine for load image file.
607 PeiServices - The PEI core services table.
608 FileHandle - Pointer to the FFS file header of the image.
609 EntryPoint - Pointer to entry point of specified image file for output.
610 AuthenticationState - Pointer to attestation authentication state of image.
614 Status - EFI_SUCCESS - Image is successfully loaded.
615 EFI_NOT_FOUND - Fail to locate necessary PPI
616 Others - Fail to load file.
620 EFI_STATUS PpiStatus
;
623 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
624 EFI_PHYSICAL_ADDRESS ImageAddress
;
628 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
629 // one at a time, until one reports EFI_SUCCESS.
633 PpiStatus
= PeiServicesLocatePpi (
634 &gEfiPeiLoadFilePpiGuid
,
639 if (!EFI_ERROR (PpiStatus
)) {
640 Status
= LoadFile
->LoadFile (
648 if (!EFI_ERROR (Status
)) {
653 } while (!EFI_ERROR (PpiStatus
));
656 // If no instances reports EFI_SUCCESS, then build-in support for
657 // the PE32+/TE XIP image format is used.
659 Status
= PeiLoadImageLoadImage (
672 InitializeImageServices (
673 IN PEI_CORE_INSTANCE
*PrivateData
,
674 IN PEI_CORE_INSTANCE
*OldCoreData
680 Regitser PeCoffLoader to PeiCore PrivateData. And install
685 PrivateData - Pointer to PEI_CORE_INSTANCE.
686 OldCoreData - Pointer to PEI_CORE_INSTANCE.
695 // Always update PeCoffLoader pointer as PEI core itself may get
696 // shadowed into memory
698 PrivateData
->PeCoffLoader
= GetPeCoffLoaderProtocol ();
700 if (OldCoreData
== NULL
) {
702 // The first time we are XIP (running from FLASH). We need to remember the
703 // FLASH address so we can reinstall the memory version that runs faster
705 PrivateData
->XipLoadFile
= &gPpiLoadFilePpiList
;
706 PeiServicesInstallPpi (PrivateData
->XipLoadFile
);
709 // 2nd time we are running from memory so replace the XIP version with the
710 // new memory version.
712 PeiServicesReInstallPpi (PrivateData
->XipLoadFile
, &gPpiLoadFilePpiList
);