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 EFI_SECTION_TYPE SearchType1
;
227 EFI_SECTION_TYPE SearchType2
;
231 *AuthenticationState
= 0;
233 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst
)) {
234 SearchType1
= EFI_SECTION_TE
;
235 SearchType2
= EFI_SECTION_PE32
;
237 SearchType1
= EFI_SECTION_PE32
;
238 SearchType2
= EFI_SECTION_TE
;
241 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
242 // is true, TE will be searched first).
244 Status
= PeiServicesFfsFindSectionData (
250 // If we didn't find a first exe section, try to find the second exe section.
252 if (EFI_ERROR (Status
)) {
253 Status
= PeiServicesFfsFindSectionData (
258 if (EFI_ERROR (Status
)) {
260 // PEI core only carry the loader function fro TE and PE32 executables
261 // If this two section does not exist, just return.
268 // If memory is installed, perform the shadow operations
270 Status
= LoadAndRelocatePeCoffImage (
277 ASSERT_EFI_ERROR (Status
);
280 if (EFI_ERROR (Status
)) {
285 // Got the entry point from the loaded Pe32Data
287 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
288 *EntryPoint
= ImageEntryPoint
;
290 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
292 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
293 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine
)) {
294 return EFI_UNSUPPORTED
;
298 if (ImageAddressArg
!= NULL
) {
299 *ImageAddressArg
= ImageAddress
;
302 if (ImageSizeArg
!= NULL
) {
303 *ImageSizeArg
= ImageSize
;
308 CHAR8 AsciiBuffer
[512];
313 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
315 if (Machine
!= EFI_IMAGE_MACHINE_IA64
) {
316 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)*EntryPoint
));
319 // For IPF Image, the real entry point should be print.
321 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID
*)(UINTN
)ImageAddress
, (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)*EntryPoint
)));
325 // Print Module Name by PeImage PDB file name.
327 AsciiString
= PeCoffLoaderGetPdbPointer (Pe32Data
);
329 if (AsciiString
!= NULL
) {
330 for (Index
= (INT32
) AsciiStrLen (AsciiString
) - 1; Index
>= 0; Index
--) {
331 if (AsciiString
[Index
] == '\\') {
337 for (Index1
= 0; AsciiString
[Index
+ 1 + Index1
] != '.'; Index1
++) {
338 AsciiBuffer
[Index1
] = AsciiString
[Index
+ 1 + Index1
];
340 AsciiBuffer
[Index1
] = '\0';
341 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
347 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));
355 The wrapper function of PeiLoadImageLoadImage().
357 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
358 @param FileHandle - Pointer to the FFS file header of the image.
359 @param ImageAddressArg - Pointer to PE/TE image.
360 @param ImageSizeArg - Size of PE/TE image.
361 @param EntryPoint - Pointer to entry point of specified image file for output.
362 @param AuthenticationState - Pointer to attestation authentication state of image.
364 @return Status of PeiLoadImageLoadImage().
369 PeiLoadImageLoadImageWrapper (
370 IN CONST EFI_PEI_LOAD_FILE_PPI
*This
,
371 IN EFI_PEI_FILE_HANDLE FileHandle
,
372 OUT EFI_PHYSICAL_ADDRESS
*ImageAddressArg
, OPTIONAL
373 OUT UINT64
*ImageSizeArg
, OPTIONAL
374 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
375 OUT UINT32
*AuthenticationState
378 return PeiLoadImageLoadImage (
379 GetPeiServicesTablePointer (),
389 Routine to load image file for subsequent execution by LoadFile Ppi.
390 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
391 XIP image format is used.
393 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
394 @param FileHandle - Pointer to the FFS file header of the image.
395 @param EntryPoint - Pointer to entry point of specified image file for output.
396 @param AuthenticationState - Pointer to attestation authentication state of image.
398 @retval EFI_SUCCESS - Image is successfully loaded.
399 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
400 @retval Others - Fail to load file.
405 IN CONST EFI_PEI_SERVICES
**PeiServices
,
406 IN EFI_PEI_FILE_HANDLE FileHandle
,
407 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
,
408 OUT UINT32
*AuthenticationState
411 EFI_STATUS PpiStatus
;
414 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
415 EFI_PHYSICAL_ADDRESS ImageAddress
;
419 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
420 // one at a time, until one reports EFI_SUCCESS.
424 PpiStatus
= PeiServicesLocatePpi (
425 &gEfiPeiLoadFilePpiGuid
,
430 if (!EFI_ERROR (PpiStatus
)) {
431 Status
= LoadFile
->LoadFile (
439 if (!EFI_ERROR (Status
)) {
441 // The image to be started must have the machine type supported by PeiCore.
443 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
)));
444 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID
*) (UINTN
) ImageAddress
))) {
445 return EFI_UNSUPPORTED
;
451 } while (!EFI_ERROR (PpiStatus
));
459 Install Pei Load File PPI.
462 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
463 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
467 InitializeImageServices (
468 IN PEI_CORE_INSTANCE
*PrivateData
,
469 IN PEI_CORE_INSTANCE
*OldCoreData
472 if (OldCoreData
== NULL
) {
474 // The first time we are XIP (running from FLASH). We need to remember the
475 // FLASH address so we can reinstall the memory version that runs faster
477 PrivateData
->XipLoadFile
= &gPpiLoadFilePpiList
;
478 PeiServicesInstallPpi (PrivateData
->XipLoadFile
);
481 // 2nd time we are running from memory so replace the XIP version with the
482 // new memory version.
484 PeiServicesReInstallPpi (PrivateData
->XipLoadFile
, &gPpiLoadFilePpiList
);