2 Pei Core Load Image Support
4 Copyright (c) 2006 - 2009, 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
);
58 while ((Length
--) > 0) {
59 *(Destination8
++) = *(Source8
++);
67 Support routine to get the Image read file function.
69 @param ImageContext - The context of the image being loaded
71 @retval EFI_SUCCESS - If Image function location is found
75 GetImageReadFunction (
76 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
81 MemoryBuffer
= AllocatePages (0x400 / EFI_PAGE_SIZE
+ 1);
82 ASSERT (MemoryBuffer
!= NULL
);
84 CopyMem (MemoryBuffer
, (CONST VOID
*) (UINTN
) PeiImageRead
, 0x400);
86 ImageContext
->ImageRead
= (PE_COFF_LOADER_READ_FILE
) (UINTN
) MemoryBuffer
;
93 Loads and relocates a PE/COFF image into memory.
96 @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
97 @param ImageAddress - The base address of the relocated PE/COFF image
98 @param ImageSize - The size of the relocated PE/COFF image
99 @param EntryPoint - The entry point of the relocated PE/COFF image
101 @retval EFI_SUCCESS The file was loaded and relocated
102 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
103 @retval EFI_INVALID_PARAMETER The image withou .reloc section can't be relocated.
107 LoadAndRelocatePeCoffImage (
109 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
110 OUT UINT64
*ImageSize
,
111 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
115 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
117 ZeroMem (&ImageContext
, sizeof (ImageContext
));
118 ImageContext
.Handle
= Pe32Data
;
119 Status
= GetImageReadFunction (&ImageContext
);
121 ASSERT_EFI_ERROR (Status
);
123 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
124 if (EFI_ERROR (Status
)) {
128 // When Image has no reloc section, it can't be relocated into memory.
130 if (ImageContext
.RelocationsStripped
) {
131 DEBUG ((EFI_D_ERROR
, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN
) Pe32Data
));
132 return EFI_INVALID_PARAMETER
;
135 // Allocate Memory for the image
137 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
138 ASSERT (ImageContext
.ImageAddress
!= 0);
141 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
143 if (ImageContext
.IsTeImage
) {
144 ImageContext
.ImageAddress
= ImageContext
.ImageAddress
+
145 ((EFI_TE_IMAGE_HEADER
*) Pe32Data
)->StrippedSize
-
146 sizeof (EFI_TE_IMAGE_HEADER
);
150 // Load the image to our new buffer
152 Status
= PeCoffLoaderLoadImage (&ImageContext
);
153 if (EFI_ERROR (Status
)) {
157 // Relocate the image in our new buffer
159 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
160 if (EFI_ERROR (Status
)) {
165 // Flush the instruction cache so the image data is written before we execute it
167 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
169 *ImageAddress
= ImageContext
.ImageAddress
;
170 *ImageSize
= ImageContext
.ImageSize
;
171 *EntryPoint
= ImageContext
.EntryPoint
;
177 Loads a PEIM into memory for subsequent execution. If there are compressed
178 images or images that need to be relocated into memory for performance reasons,
179 this service performs that transformation.
181 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
182 @param FileHandle Pointer to the FFS file header of the image.
183 @param ImageAddressArg Pointer to PE/TE image.
184 @param ImageSizeArg Size of PE/TE image.
185 @param EntryPoint Pointer to entry point of specified image file for output.
186 @param AuthenticationState - Pointer to attestation authentication state of image.
188 @retval EFI_SUCCESS Image is successfully loaded.
189 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
190 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
194 PeiLoadImageLoadImage (
195 IN CONST EFI_PEI_SERVICES
**PeiServices
,
196 IN EFI_PEI_FILE_HANDLE FileHandle
,
197 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
198 OUT UINT64
*ImageSizeArg
, OPTIONAL
199 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
200 OUT UINT32
*AuthenticationState
205 EFI_PHYSICAL_ADDRESS ImageAddress
;
207 EFI_PHYSICAL_ADDRESS ImageEntryPoint
;
209 PEI_CORE_INSTANCE
*Private
;
211 EFI_SECTION_TYPE SearchType1
;
212 EFI_SECTION_TYPE SearchType2
;
216 *AuthenticationState
= 0;
218 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst
)) {
219 SearchType1
= EFI_SECTION_TE
;
220 SearchType2
= EFI_SECTION_PE32
;
222 SearchType1
= EFI_SECTION_PE32
;
223 SearchType2
= EFI_SECTION_TE
;
226 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
227 // is true, TE will be searched first).
229 Status
= PeiServicesFfsFindSectionData (
235 // If we didn't find a first exe section, try to find the second exe section.
237 if (EFI_ERROR (Status
)) {
238 Status
= PeiServicesFfsFindSectionData (
243 if (EFI_ERROR (Status
)) {
245 // PEI core only carry the loader function fro TE and PE32 executables
246 // If this two section does not exist, just return.
252 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
254 if (Private
->PeiMemoryInstalled
&&
255 (Private
->HobList
.HandoffInformationTable
->BootMode
!= BOOT_ON_S3_RESUME
)) {
257 // If memory is installed, perform the shadow operations
259 Status
= LoadAndRelocatePeCoffImage (
266 if (EFI_ERROR (Status
)) {
271 // Got the entry point from the loaded Pe32Data
273 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
274 *EntryPoint
= ImageEntryPoint
;
277 // Retrieve the entry point from the PE/COFF or TE image header
279 ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Pe32Data
;
280 Status
= PeCoffLoaderGetEntryPoint (Pe32Data
, &EntryPointArg
);
281 if (EFI_ERROR (Status
)) {
284 *EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) EntryPointArg
;
287 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
289 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
290 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine
)) {
291 return EFI_UNSUPPORTED
;
295 if (ImageAddressArg
!= NULL
) {
296 *ImageAddressArg
= ImageAddress
;
299 if (ImageSizeArg
!= NULL
) {
300 *ImageSizeArg
= ImageSize
;
305 CHAR8 AsciiBuffer
[512];
310 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
312 if (Machine
!= EFI_IMAGE_MACHINE_IA64
) {
313 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)*EntryPoint
));
316 // For IPF Image, the real entry point should be print.
318 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)*EntryPoint
)));
322 // Print Module Name by PeImage PDB file name.
324 AsciiString
= PeCoffLoaderGetPdbPointer (Pe32Data
);
326 if (AsciiString
!= NULL
) {
327 for (Index
= (INT32
) AsciiStrLen (AsciiString
) - 1; Index
>= 0; Index
--) {
328 if (AsciiString
[Index
] == '\\') {
334 for (Index1
= 0; AsciiString
[Index
+ 1 + Index1
] != '.'; Index1
++) {
335 AsciiBuffer
[Index1
] = AsciiString
[Index
+ 1 + Index1
];
337 AsciiBuffer
[Index1
] = '\0';
338 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
344 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
352 The wrapper function of PeiLoadImageLoadImage().
354 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
355 @param FileHandle - Pointer to the FFS file header of the image.
356 @param ImageAddressArg - Pointer to PE/TE image.
357 @param ImageSizeArg - Size of PE/TE image.
358 @param EntryPoint - Pointer to entry point of specified image file for output.
359 @param AuthenticationState - Pointer to attestation authentication state of image.
361 @return Status of PeiLoadImageLoadImage().
366 PeiLoadImageLoadImageWrapper (
367 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
368 IN EFI_PEI_FILE_HANDLE FileHandle
,
369 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
370 OUT UINT64
*ImageSizeArg
, OPTIONAL
371 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
372 OUT UINT32
*AuthenticationState
375 return PeiLoadImageLoadImage (
376 GetPeiServicesTablePointer (),
386 Routine to load image file for subsequent execution by LoadFile Ppi.
387 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
388 XIP image format is used.
390 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
391 @param FileHandle - Pointer to the FFS file header of the image.
392 @param EntryPoint - Pointer to entry point of specified image file for output.
393 @param AuthenticationState - Pointer to attestation authentication state of image.
395 @retval EFI_SUCCESS - Image is successfully loaded.
396 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
397 @retval Others - Fail to load file.
402 IN CONST EFI_PEI_SERVICES
**PeiServices
,
403 IN EFI_PEI_FILE_HANDLE FileHandle
,
404 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
405 OUT UINT32
*AuthenticationState
408 EFI_STATUS PpiStatus
;
411 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
412 EFI_PHYSICAL_ADDRESS ImageAddress
;
416 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
417 // one at a time, until one reports EFI_SUCCESS.
421 PpiStatus
= PeiServicesLocatePpi (
422 &gEfiPeiLoadFilePpiGuid
,
427 if (!EFI_ERROR (PpiStatus
)) {
428 Status
= LoadFile
->LoadFile (
436 if (!EFI_ERROR (Status
)) {
441 } while (!EFI_ERROR (PpiStatus
));
449 Install Pei Load File PPI.
452 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
453 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
457 InitializeImageServices (
458 IN PEI_CORE_INSTANCE
*PrivateData
,
459 IN PEI_CORE_INSTANCE
*OldCoreData
462 if (OldCoreData
== NULL
) {
464 // The first time we are XIP (running from FLASH). We need to remember the
465 // FLASH address so we can reinstall the memory version that runs faster
467 PrivateData
->XipLoadFile
= &gPpiLoadFilePpiList
;
468 PeiServicesInstallPpi (PrivateData
->XipLoadFile
);
471 // 2nd time we are running from memory so replace the XIP version with the
472 // new memory version.
474 PeiServicesReInstallPpi (PrivateData
->XipLoadFile
, &gPpiLoadFilePpiList
);