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
);
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
) {
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.
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
112 @retval EFI_INVALID_PARAMETER The image withou .reloc section can't be relocated.
116 LoadAndRelocatePeCoffImage (
118 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
119 OUT UINT64
*ImageSize
,
120 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
124 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
125 PEI_CORE_INSTANCE
*Private
;
127 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
129 ZeroMem (&ImageContext
, sizeof (ImageContext
));
130 ImageContext
.Handle
= Pe32Data
;
131 Status
= GetImageReadFunction (&ImageContext
);
133 ASSERT_EFI_ERROR (Status
);
135 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
136 if (EFI_ERROR (Status
)) {
140 // When Image has no reloc section, it can't be relocated into memory.
142 if (ImageContext
.RelocationsStripped
) {
143 DEBUG ((EFI_D_ERROR
, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN
) Pe32Data
));
146 // Allocate Memory for the image
148 if (Private
->PeiMemoryInstalled
) {
149 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
150 ASSERT (ImageContext
.ImageAddress
!= 0);
153 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
155 if (ImageContext
.IsTeImage
) {
156 ImageContext
.ImageAddress
= ImageContext
.ImageAddress
+
157 ((EFI_TE_IMAGE_HEADER
*) Pe32Data
)->StrippedSize
-
158 sizeof (EFI_TE_IMAGE_HEADER
);
161 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) Pe32Data
;
165 // Load the image to our new buffer
167 Status
= PeCoffLoaderLoadImage (&ImageContext
);
168 if (EFI_ERROR (Status
)) {
172 // Relocate the image in our new buffer
174 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
175 if (EFI_ERROR (Status
)) {
180 // Flush the instruction cache so the image data is written before we execute it
182 if (Private
->PeiMemoryInstalled
) {
183 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
186 *ImageAddress
= ImageContext
.ImageAddress
;
187 *ImageSize
= ImageContext
.ImageSize
;
188 *EntryPoint
= ImageContext
.EntryPoint
;
194 Loads a PEIM into memory for subsequent execution. If there are compressed
195 images or images that need to be relocated into memory for performance reasons,
196 this service performs that transformation.
198 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
199 @param FileHandle Pointer to the FFS file header of the image.
200 @param ImageAddressArg Pointer to PE/TE image.
201 @param ImageSizeArg Size of PE/TE image.
202 @param EntryPoint Pointer to entry point of specified image file for output.
203 @param AuthenticationState - Pointer to attestation authentication state of image.
205 @retval EFI_SUCCESS Image is successfully loaded.
206 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
207 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
211 PeiLoadImageLoadImage (
212 IN CONST EFI_PEI_SERVICES
**PeiServices
,
213 IN EFI_PEI_FILE_HANDLE FileHandle
,
214 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
215 OUT UINT64
*ImageSizeArg
, OPTIONAL
216 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
217 OUT UINT32
*AuthenticationState
222 EFI_PHYSICAL_ADDRESS ImageAddress
;
224 EFI_PHYSICAL_ADDRESS ImageEntryPoint
;
226 PEI_CORE_INSTANCE
*Private
;
227 EFI_SECTION_TYPE SearchType1
;
228 EFI_SECTION_TYPE SearchType2
;
232 *AuthenticationState
= 0;
234 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst
)) {
235 SearchType1
= EFI_SECTION_TE
;
236 SearchType2
= EFI_SECTION_PE32
;
238 SearchType1
= EFI_SECTION_PE32
;
239 SearchType2
= EFI_SECTION_TE
;
242 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
243 // is true, TE will be searched first).
245 Status
= PeiServicesFfsFindSectionData (
251 // If we didn't find a first exe section, try to find the second exe section.
253 if (EFI_ERROR (Status
)) {
254 Status
= PeiServicesFfsFindSectionData (
259 if (EFI_ERROR (Status
)) {
261 // PEI core only carry the loader function fro TE and PE32 executables
262 // If this two section does not exist, just return.
268 Private
= PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices
);
271 // If memory is installed, perform the shadow operations
273 Status
= LoadAndRelocatePeCoffImage (
280 ASSERT_EFI_ERROR (Status
);
283 if (EFI_ERROR (Status
)) {
288 // Got the entry point from the loaded Pe32Data
290 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
291 *EntryPoint
= ImageEntryPoint
;
293 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
295 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
296 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine
)) {
297 return EFI_UNSUPPORTED
;
301 if (ImageAddressArg
!= NULL
) {
302 *ImageAddressArg
= ImageAddress
;
305 if (ImageSizeArg
!= NULL
) {
306 *ImageSizeArg
= ImageSize
;
311 CHAR8 AsciiBuffer
[512];
316 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
318 if (Machine
!= EFI_IMAGE_MACHINE_IA64
) {
319 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)*EntryPoint
));
322 // For IPF Image, the real entry point should be print.
324 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)*EntryPoint
)));
328 // Print Module Name by PeImage PDB file name.
330 AsciiString
= PeCoffLoaderGetPdbPointer (Pe32Data
);
332 if (AsciiString
!= NULL
) {
333 for (Index
= (INT32
) AsciiStrLen (AsciiString
) - 1; Index
>= 0; Index
--) {
334 if (AsciiString
[Index
] == '\\') {
340 for (Index1
= 0; AsciiString
[Index
+ 1 + Index1
] != '.'; Index1
++) {
341 AsciiBuffer
[Index1
] = AsciiString
[Index
+ 1 + Index1
];
343 AsciiBuffer
[Index1
] = '\0';
344 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
350 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
358 The wrapper function of PeiLoadImageLoadImage().
360 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
361 @param FileHandle - Pointer to the FFS file header of the image.
362 @param ImageAddressArg - Pointer to PE/TE image.
363 @param ImageSizeArg - Size of PE/TE image.
364 @param EntryPoint - Pointer to entry point of specified image file for output.
365 @param AuthenticationState - Pointer to attestation authentication state of image.
367 @return Status of PeiLoadImageLoadImage().
372 PeiLoadImageLoadImageWrapper (
373 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
374 IN EFI_PEI_FILE_HANDLE FileHandle
,
375 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
376 OUT UINT64
*ImageSizeArg
, OPTIONAL
377 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
378 OUT UINT32
*AuthenticationState
381 return PeiLoadImageLoadImage (
382 GetPeiServicesTablePointer (),
392 Routine to load image file for subsequent execution by LoadFile Ppi.
393 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
394 XIP image format is used.
396 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
397 @param FileHandle - Pointer to the FFS file header of the image.
398 @param EntryPoint - Pointer to entry point of specified image file for output.
399 @param AuthenticationState - Pointer to attestation authentication state of image.
401 @retval EFI_SUCCESS - Image is successfully loaded.
402 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
403 @retval Others - Fail to load file.
408 IN CONST EFI_PEI_SERVICES
**PeiServices
,
409 IN EFI_PEI_FILE_HANDLE FileHandle
,
410 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
411 OUT UINT32
*AuthenticationState
414 EFI_STATUS PpiStatus
;
417 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
418 EFI_PHYSICAL_ADDRESS ImageAddress
;
422 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
423 // one at a time, until one reports EFI_SUCCESS.
427 PpiStatus
= PeiServicesLocatePpi (
428 &gEfiPeiLoadFilePpiGuid
,
433 if (!EFI_ERROR (PpiStatus
)) {
434 Status
= LoadFile
->LoadFile (
442 if (!EFI_ERROR (Status
)) {
444 // The image to be started must have the machine type supported by PeiCore.
446 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
)));
447 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
))) {
448 return EFI_UNSUPPORTED
;
454 } while (!EFI_ERROR (PpiStatus
));
462 Install Pei Load File PPI.
465 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
466 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
470 InitializeImageServices (
471 IN PEI_CORE_INSTANCE
*PrivateData
,
472 IN PEI_CORE_INSTANCE
*OldCoreData
475 if (OldCoreData
== NULL
) {
477 // The first time we are XIP (running from FLASH). We need to remember the
478 // FLASH address so we can reinstall the memory version that runs faster
480 PrivateData
->XipLoadFile
= &gPpiLoadFilePpiList
;
481 PeiServicesInstallPpi (PrivateData
->XipLoadFile
);
484 // 2nd time we are running from memory so replace the XIP version with the
485 // new memory version.
487 PeiServicesReInstallPpi (PrivateData
->XipLoadFile
, &gPpiLoadFilePpiList
);