2 Pei Core Load Image Support
4 Copyright (c) 2006 - 2010, 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
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.
18 EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi
= {
19 PeiLoadImageLoadImageWrapper
23 EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList
= {
24 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
25 &gEfiPeiLoadFilePpiGuid
,
31 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
34 @param FileHandle - The handle to the PE/COFF file
35 @param FileOffset - The offset, in bytes, into the file to read
36 @param ReadSize - The number of bytes to read from the file starting at FileOffset
37 @param Buffer - A pointer to the buffer to read the data into.
39 @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
55 Destination8
= Buffer
;
56 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
57 if (Destination8
!= Source8
) {
59 while ((Length
--) > 0) {
60 *(Destination8
++) = *(Source8
++);
69 Support routine to get the Image read file function.
71 @param ImageContext - The context of the image being loaded
73 @retval EFI_SUCCESS - If Image function location is found
77 GetImageReadFunction (
78 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
81 PEI_CORE_INSTANCE
*Private
;
84 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
86 if (!Private
->PeiMemoryInstalled
|| (Private
->HobList
.HandoffInformationTable
->BootMode
== BOOT_ON_S3_RESUME
)) {
87 ImageContext
->ImageRead
= PeiImageRead
;
89 MemoryBuffer
= AllocatePages (0x400 / EFI_PAGE_SIZE
+ 1);
90 ASSERT (MemoryBuffer
!= NULL
);
92 CopyMem (MemoryBuffer
, (CONST VOID
*) (UINTN
) PeiImageRead
, 0x400);
94 ImageContext
->ImageRead
= (PE_COFF_LOADER_READ_FILE
) (UINTN
) MemoryBuffer
;
102 Loads and relocates a PE/COFF image into memory.
103 If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
105 @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
106 @param ImageAddress - The base address of the relocated PE/COFF image
107 @param ImageSize - The size of the relocated PE/COFF image
108 @param EntryPoint - The entry point of the relocated PE/COFF image
110 @retval EFI_SUCCESS The file was loaded and relocated
111 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
115 LoadAndRelocatePeCoffImage (
117 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
118 OUT UINT64
*ImageSize
,
119 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
123 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
124 PEI_CORE_INSTANCE
*Private
;
126 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
128 ZeroMem (&ImageContext
, sizeof (ImageContext
));
129 ImageContext
.Handle
= Pe32Data
;
130 Status
= GetImageReadFunction (&ImageContext
);
132 ASSERT_EFI_ERROR (Status
);
134 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
135 if (EFI_ERROR (Status
)) {
139 // When Image has no reloc section, it can't be relocated into memory.
141 if (ImageContext
.RelocationsStripped
&& (Private
->PeiMemoryInstalled
) && (Private
->HobList
.HandoffInformationTable
->BootMode
!= BOOT_ON_S3_RESUME
)) {
142 DEBUG ((EFI_D_INFO
, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN
) Pe32Data
));
146 // Set default base address to current image address.
148 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Pe32Data
;
151 // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.
153 if ((!ImageContext
.RelocationsStripped
) && (Private
->PeiMemoryInstalled
) && (Private
->HobList
.HandoffInformationTable
->BootMode
!= BOOT_ON_S3_RESUME
)) {
154 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
155 ASSERT (ImageContext
.ImageAddress
!= 0);
156 if (ImageContext
.ImageAddress
== 0) {
157 return EFI_OUT_OF_RESOURCES
;
161 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
163 if (ImageContext
.IsTeImage
) {
164 ImageContext
.ImageAddress
= ImageContext
.ImageAddress
+
165 ((EFI_TE_IMAGE_HEADER
*) Pe32Data
)->StrippedSize
-
166 sizeof (EFI_TE_IMAGE_HEADER
);
171 // Load the image to our new buffer
173 Status
= PeCoffLoaderLoadImage (&ImageContext
);
174 if (EFI_ERROR (Status
)) {
178 // Relocate the image in our new buffer
180 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
181 if (EFI_ERROR (Status
)) {
186 // Flush the instruction cache so the image data is written before we execute it
188 if ((!ImageContext
.RelocationsStripped
) && (Private
->PeiMemoryInstalled
) && (Private
->HobList
.HandoffInformationTable
->BootMode
!= BOOT_ON_S3_RESUME
)) {
189 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
192 *ImageAddress
= ImageContext
.ImageAddress
;
193 *ImageSize
= ImageContext
.ImageSize
;
194 *EntryPoint
= ImageContext
.EntryPoint
;
200 Loads a PEIM into memory for subsequent execution. If there are compressed
201 images or images that need to be relocated into memory for performance reasons,
202 this service performs that transformation.
204 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
205 @param FileHandle Pointer to the FFS file header of the image.
206 @param ImageAddressArg Pointer to PE/TE image.
207 @param ImageSizeArg Size of PE/TE image.
208 @param EntryPoint Pointer to entry point of specified image file for output.
209 @param AuthenticationState - Pointer to attestation authentication state of image.
211 @retval EFI_SUCCESS Image is successfully loaded.
212 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
213 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
217 PeiLoadImageLoadImage (
218 IN CONST EFI_PEI_SERVICES
**PeiServices
,
219 IN EFI_PEI_FILE_HANDLE FileHandle
,
220 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
221 OUT UINT64
*ImageSizeArg
, OPTIONAL
222 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
223 OUT UINT32
*AuthenticationState
228 EFI_PHYSICAL_ADDRESS ImageAddress
;
230 EFI_PHYSICAL_ADDRESS ImageEntryPoint
;
232 EFI_SECTION_TYPE SearchType1
;
233 EFI_SECTION_TYPE SearchType2
;
237 *AuthenticationState
= 0;
239 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst
)) {
240 SearchType1
= EFI_SECTION_TE
;
241 SearchType2
= EFI_SECTION_PE32
;
243 SearchType1
= EFI_SECTION_PE32
;
244 SearchType2
= EFI_SECTION_TE
;
248 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
249 // is true, TE will be searched first).
251 Status
= PeiServicesFfsFindSectionData (
257 // If we didn't find a first exe section, try to find the second exe section.
259 if (EFI_ERROR (Status
)) {
260 Status
= PeiServicesFfsFindSectionData (
265 if (EFI_ERROR (Status
)) {
267 // PEI core only carry the loader function fro TE and PE32 executables
268 // If this two section does not exist, just return.
275 // If memory is installed, perform the shadow operations
277 Status
= LoadAndRelocatePeCoffImage (
284 ASSERT_EFI_ERROR (Status
);
287 if (EFI_ERROR (Status
)) {
292 // Got the entry point from the loaded Pe32Data
294 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
295 *EntryPoint
= ImageEntryPoint
;
297 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
299 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
300 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine
)) {
301 return EFI_UNSUPPORTED
;
305 if (ImageAddressArg
!= NULL
) {
306 *ImageAddressArg
= ImageAddress
;
309 if (ImageSizeArg
!= NULL
) {
310 *ImageSizeArg
= ImageSize
;
315 CHAR8 AsciiBuffer
[512];
320 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
322 if (Machine
!= EFI_IMAGE_MACHINE_IA64
) {
323 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)*EntryPoint
));
326 // For IPF Image, the real entry point should be print.
328 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)*EntryPoint
)));
332 // Print Module Name by PeImage PDB file name.
334 AsciiString
= PeCoffLoaderGetPdbPointer (Pe32Data
);
336 if (AsciiString
!= NULL
) {
337 for (Index
= (INT32
) AsciiStrLen (AsciiString
) - 1; Index
>= 0; Index
--) {
338 if (AsciiString
[Index
] == '\\') {
344 for (Index1
= 0; AsciiString
[Index
+ 1 + Index1
] != '.'; Index1
++) {
345 AsciiBuffer
[Index1
] = AsciiString
[Index
+ 1 + Index1
];
347 AsciiBuffer
[Index1
] = '\0';
348 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
354 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
362 The wrapper function of PeiLoadImageLoadImage().
364 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
365 @param FileHandle - Pointer to the FFS file header of the image.
366 @param ImageAddressArg - Pointer to PE/TE image.
367 @param ImageSizeArg - Size of PE/TE image.
368 @param EntryPoint - Pointer to entry point of specified image file for output.
369 @param AuthenticationState - Pointer to attestation authentication state of image.
371 @return Status of PeiLoadImageLoadImage().
376 PeiLoadImageLoadImageWrapper (
377 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
378 IN EFI_PEI_FILE_HANDLE FileHandle
,
379 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
380 OUT UINT64
*ImageSizeArg
, OPTIONAL
381 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
382 OUT UINT32
*AuthenticationState
385 return PeiLoadImageLoadImage (
386 GetPeiServicesTablePointer (),
396 Check whether the input image has the relocation.
398 @param Pe32Data Pointer to the PE/COFF or TE image.
400 @retval TRUE Relocation is stripped.
401 @retval FALSE Relocation is not stripped.
409 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
410 EFI_IMAGE_DOS_HEADER
*DosHdr
;
412 ASSERT (Pe32Data
!= NULL
);
414 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
415 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
417 // DOS image header is present, so read the PE header after the DOS image header.
419 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
422 // DOS image header is not present, so PE header is at the image base.
424 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
428 // Three cases with regards to relocations:
429 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
430 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
431 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
432 // has no base relocs to apply
433 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
435 // Look at the file header to determine if relocations have been stripped, and
436 // save this info in the image context for later use.
438 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
439 if ((Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
444 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
445 if ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0) {
456 Routine to load image file for subsequent execution by LoadFile Ppi.
457 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
458 XIP image format is used.
460 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
461 @param FileHandle - Pointer to the FFS file header of the image.
462 @param PeimState - The dispatch state of the input PEIM handle.
463 @param EntryPoint - Pointer to entry point of specified image file for output.
464 @param AuthenticationState - Pointer to attestation authentication state of image.
466 @retval EFI_SUCCESS - Image is successfully loaded.
467 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
468 @retval Others - Fail to load file.
473 IN CONST EFI_PEI_SERVICES
**PeiServices
,
474 IN EFI_PEI_FILE_HANDLE FileHandle
,
476 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
477 OUT UINT32
*AuthenticationState
480 EFI_STATUS PpiStatus
;
483 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
484 EFI_PHYSICAL_ADDRESS ImageAddress
;
490 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
491 // one at a time, until one reports EFI_SUCCESS.
495 PpiStatus
= PeiServicesLocatePpi (
496 &gEfiPeiLoadFilePpiGuid
,
501 if (!EFI_ERROR (PpiStatus
)) {
502 Status
= LoadFile
->LoadFile (
510 if (!EFI_ERROR (Status
)) {
512 // The shadowed PEIM must be relocatable.
514 if (PeimState
== PEIM_STATE_REGISITER_FOR_SHADOW
) {
515 IsStrip
= RelocationIsStrip ((VOID
*) (UINTN
) ImageAddress
);
518 return EFI_UNSUPPORTED
;
523 // The image to be started must have the machine type supported by PeiCore.
525 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
)));
526 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
))) {
527 return EFI_UNSUPPORTED
;
533 } while (!EFI_ERROR (PpiStatus
));
541 Install Pei Load File PPI.
544 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
545 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
549 InitializeImageServices (
550 IN PEI_CORE_INSTANCE
*PrivateData
,
551 IN PEI_CORE_INSTANCE
*OldCoreData
554 if (OldCoreData
== NULL
) {
556 // The first time we are XIP (running from FLASH). We need to remember the
557 // FLASH address so we can reinstall the memory version that runs faster
559 PrivateData
->XipLoadFile
= &gPpiLoadFilePpiList
;
560 PeiServicesInstallPpi (PrivateData
->XipLoadFile
);
563 // 2nd time we are running from memory so replace the XIP version with the
564 // new memory version.
566 PeiServicesReInstallPpi (PrivateData
->XipLoadFile
, &gPpiLoadFilePpiList
);