]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
Correct some comments to add the detailed information.
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
1 /** @file
2 Pei Core Load Image Support
3
4 Copyright (c) 2006 - 2008, 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
9
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.
12
13 **/
14
15 #include <PeiMain.h>
16
17 /**
18 The wrapper function of PeiLoadImageLoadImage().
19
20 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
21 @param FileHandle - Pointer to the FFS file header of the image.
22 @param ImageAddressArg - Pointer to PE/TE image.
23 @param ImageSizeArg - Size of PE/TE image.
24 @param EntryPoint - Pointer to entry point of specified image file for output.
25 @param AuthenticationState - Pointer to attestation authentication state of image.
26
27 @return Status of PeiLoadImageLoadImage().
28
29 **/
30 EFI_STATUS
31 EFIAPI
32 PeiLoadImageLoadImageWrapper (
33 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
34 IN EFI_PEI_FILE_HANDLE FileHandle,
35 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
36 OUT UINT64 *ImageSizeArg, OPTIONAL
37 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
38 OUT UINT32 *AuthenticationState
39 )
40 ;
41
42 STATIC EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
43 PeiLoadImageLoadImageWrapper
44 };
45
46
47 STATIC EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
48 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
49 &gEfiPeiLoadFilePpiGuid,
50 &mPeiLoadImagePpi
51 };
52
53 /**
54
55 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
56
57
58 @param FileHandle - The handle to the PE/COFF file
59 @param FileOffset - The offset, in bytes, into the file to read
60 @param ReadSize - The number of bytes to read from the file starting at FileOffset
61 @param Buffer - A pointer to the buffer to read the data into.
62
63 @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
64
65 **/
66 EFI_STATUS
67 EFIAPI
68 PeiImageRead (
69 IN VOID *FileHandle,
70 IN UINTN FileOffset,
71 IN UINTN *ReadSize,
72 OUT VOID *Buffer
73 )
74 {
75 CopyMem (Buffer, (VOID *)((UINTN) FileHandle + FileOffset), *ReadSize);
76 return EFI_SUCCESS;
77 }
78
79 /**
80
81 Support routine to get the Image read file function.
82
83 @param ImageContext - The context of the image being loaded
84
85 @retval EFI_SUCCESS - If Image function location is found
86
87 **/
88 EFI_STATUS
89 GetImageReadFunction (
90 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
91 )
92 {
93 VOID* MemoryBuffer;
94
95 MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);
96 ASSERT (MemoryBuffer != NULL);
97
98 CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageRead, 0x400);
99
100 ImageContext->ImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;
101
102 return EFI_SUCCESS;
103 }
104
105 /**
106
107 Loads and relocates a PE/COFF image into memory.
108
109
110 @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
111 @param ImageAddress - The base address of the relocated PE/COFF image
112 @param ImageSize - The size of the relocated PE/COFF image
113 @param EntryPoint - The entry point of the relocated PE/COFF image
114
115 @retval EFI_SUCCESS The file was loaded and relocated
116 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
117 @retval EFI_INVALID_PARAMETER The image withou .reloc section can't be relocated.
118
119 **/
120 EFI_STATUS
121 LoadAndRelocatePeCoffImage (
122 IN VOID *Pe32Data,
123 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
124 OUT UINT64 *ImageSize,
125 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
126 )
127 {
128 EFI_STATUS Status;
129 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
130
131 ZeroMem (&ImageContext, sizeof (ImageContext));
132 ImageContext.Handle = Pe32Data;
133 Status = GetImageReadFunction (&ImageContext);
134
135 ASSERT_EFI_ERROR (Status);
136
137 Status = PeCoffLoaderGetImageInfo (&ImageContext);
138 if (EFI_ERROR (Status)) {
139 return Status;
140 }
141 //
142 // When Image has no reloc section, it can't be relocated into memory.
143 //
144 if (ImageContext.RelocationsStripped) {
145 DEBUG ((EFI_D_ERROR, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
146 return EFI_INVALID_PARAMETER;
147 }
148 //
149 // Allocate Memory for the image
150 //
151 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
152 ASSERT (ImageContext.ImageAddress != 0);
153
154 //
155 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
156 //
157 if (ImageContext.IsTeImage) {
158 ImageContext.ImageAddress = ImageContext.ImageAddress +
159 ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
160 sizeof (EFI_TE_IMAGE_HEADER);
161 }
162
163 //
164 // Load the image to our new buffer
165 //
166 Status = PeCoffLoaderLoadImage (&ImageContext);
167 if (EFI_ERROR (Status)) {
168 return Status;
169 }
170 //
171 // Relocate the image in our new buffer
172 //
173 Status = PeCoffLoaderRelocateImage (&ImageContext);
174 if (EFI_ERROR (Status)) {
175 return Status;
176 }
177
178 //
179 // Flush the instruction cache so the image data is written before we execute it
180 //
181 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
182
183 *ImageAddress = ImageContext.ImageAddress;
184 *ImageSize = ImageContext.ImageSize;
185 *EntryPoint = ImageContext.EntryPoint;
186
187 return EFI_SUCCESS;
188 }
189
190 /**
191 Loads a PEIM into memory for subsequent execution. If there are compressed
192 images or images that need to be relocated into memory for performance reasons,
193 this service performs that transformation.
194
195 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
196 @param FileHandle Pointer to the FFS file header of the image.
197 @param ImageAddressArg Pointer to PE/TE image.
198 @param ImageSizeArg Size of PE/TE image.
199 @param EntryPoint Pointer to entry point of specified image file for output.
200 @param AuthenticationState - Pointer to attestation authentication state of image.
201
202 @retval EFI_SUCCESS Image is successfully loaded.
203 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
204 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
205
206 **/
207 EFI_STATUS
208 PeiLoadImageLoadImage (
209 IN EFI_PEI_SERVICES **PeiServices,
210 IN EFI_PEI_FILE_HANDLE FileHandle,
211 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
212 OUT UINT64 *ImageSizeArg, OPTIONAL
213 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
214 OUT UINT32 *AuthenticationState
215 )
216 {
217 EFI_STATUS Status;
218 VOID *Pe32Data;
219 EFI_PHYSICAL_ADDRESS ImageAddress;
220 UINT64 ImageSize;
221 EFI_PHYSICAL_ADDRESS ImageEntryPoint;
222 UINT16 Machine;
223 PEI_CORE_INSTANCE *Private;
224 VOID *EntryPointArg;
225 EFI_SECTION_TYPE SearchType1;
226 EFI_SECTION_TYPE SearchType2;
227
228 *EntryPoint = 0;
229 ImageSize = 0;
230 *AuthenticationState = 0;
231
232 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
233 SearchType1 = EFI_SECTION_TE;
234 SearchType2 = EFI_SECTION_PE32;
235 } else {
236 SearchType1 = EFI_SECTION_PE32;
237 SearchType2 = EFI_SECTION_TE;
238 }
239 //
240 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
241 // is true, TE will be searched first).
242 //
243 Status = PeiServicesFfsFindSectionData (
244 SearchType1,
245 FileHandle,
246 &Pe32Data
247 );
248 //
249 // If we didn't find a first exe section, try to find the second exe section.
250 //
251 if (EFI_ERROR (Status)) {
252 Status = PeiServicesFfsFindSectionData (
253 SearchType2,
254 FileHandle,
255 &Pe32Data
256 );
257 if (EFI_ERROR (Status)) {
258 //
259 // PEI core only carry the loader function fro TE and PE32 executables
260 // If this two section does not exist, just return.
261 //
262 return Status;
263 }
264 }
265
266 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
267
268 if (Private->PeiMemoryInstalled &&
269 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
270 //
271 // If memory is installed, perform the shadow operations
272 //
273 Status = LoadAndRelocatePeCoffImage (
274 Pe32Data,
275 &ImageAddress,
276 &ImageSize,
277 &ImageEntryPoint
278 );
279
280 if (EFI_ERROR (Status)) {
281 return Status;
282 }
283
284 //
285 // Got the entry point from the loaded Pe32Data
286 //
287 Pe32Data = (VOID *) ((UINTN) ImageAddress);
288 *EntryPoint = ImageEntryPoint;
289 } else {
290 //
291 // Retrieve the entry point from the PE/COFF or TE image header
292 //
293 ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data;
294 Status = PeCoffLoaderGetEntryPoint (Pe32Data, &EntryPointArg);
295 if (EFI_ERROR (Status)) {
296 return Status;
297 }
298 *EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) EntryPointArg;
299 }
300
301 Machine = PeCoffLoaderGetMachineType (Pe32Data);
302
303 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
304 return EFI_UNSUPPORTED;
305 }
306
307 if (ImageAddressArg != NULL) {
308 *ImageAddressArg = ImageAddress;
309 }
310
311 if (ImageSizeArg != NULL) {
312 *ImageSizeArg = ImageSize;
313 }
314
315 DEBUG_CODE_BEGIN ();
316 CHAR8 *AsciiString;
317 CHAR8 AsciiBuffer[512];
318 INT32 Index;
319 INT32 Index1;
320
321 //
322 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
323 //
324 if (Machine != IMAGE_FILE_MACHINE_IA64) {
325 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
326 } else {
327 //
328 // For IPF Image, the real entry point should be print.
329 //
330 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
331 }
332
333 //
334 // Print Module Name by PeImage PDB file name.
335 //
336 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
337
338 if (AsciiString != NULL) {
339 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
340 if (AsciiString[Index] == '\\') {
341 break;
342 }
343 }
344
345 if (Index != 0) {
346 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {
347 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];
348 }
349 AsciiBuffer [Index1] = '\0';
350 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
351 }
352 }
353
354 DEBUG_CODE_END ();
355
356 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
357
358 return EFI_SUCCESS;
359
360 }
361
362
363 /**
364 The wrapper function of PeiLoadImageLoadImage().
365
366 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
367 @param FileHandle - Pointer to the FFS file header of the image.
368 @param ImageAddressArg - Pointer to PE/TE image.
369 @param ImageSizeArg - Size of PE/TE image.
370 @param EntryPoint - Pointer to entry point of specified image file for output.
371 @param AuthenticationState - Pointer to attestation authentication state of image.
372
373 @return Status of PeiLoadImageLoadImage().
374
375 **/
376 EFI_STATUS
377 EFIAPI
378 PeiLoadImageLoadImageWrapper (
379 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
380 IN EFI_PEI_FILE_HANDLE FileHandle,
381 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
382 OUT UINT64 *ImageSizeArg, OPTIONAL
383 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
384 OUT UINT32 *AuthenticationState
385 )
386 {
387 return PeiLoadImageLoadImage (
388 GetPeiServicesTablePointer (),
389 FileHandle,
390 ImageAddressArg,
391 ImageSizeArg,
392 EntryPoint,
393 AuthenticationState
394 );
395 }
396
397 /**
398 Routine to load image file for subsequent execution by LoadFile Ppi.
399 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
400 XIP image format is used.
401
402 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
403 @param FileHandle - Pointer to the FFS file header of the image.
404 @param EntryPoint - Pointer to entry point of specified image file for output.
405 @param AuthenticationState - Pointer to attestation authentication state of image.
406
407 @retval EFI_SUCCESS - Image is successfully loaded.
408 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
409 @retval Others - Fail to load file.
410
411 **/
412 EFI_STATUS
413 PeiLoadImage (
414 IN EFI_PEI_SERVICES **PeiServices,
415 IN EFI_PEI_FILE_HANDLE FileHandle,
416 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
417 OUT UINT32 *AuthenticationState
418 )
419 {
420 EFI_STATUS PpiStatus;
421 EFI_STATUS Status;
422 UINTN Index;
423 EFI_PEI_LOAD_FILE_PPI *LoadFile;
424 EFI_PHYSICAL_ADDRESS ImageAddress;
425 UINT64 ImageSize;
426
427 //
428 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
429 // one at a time, until one reports EFI_SUCCESS.
430 //
431 Index = 0;
432 do {
433 PpiStatus = PeiServicesLocatePpi (
434 &gEfiPeiLoadFilePpiGuid,
435 Index,
436 NULL,
437 (VOID **)&LoadFile
438 );
439 if (!EFI_ERROR (PpiStatus)) {
440 Status = LoadFile->LoadFile (
441 LoadFile,
442 FileHandle,
443 &ImageAddress,
444 &ImageSize,
445 EntryPoint,
446 AuthenticationState
447 );
448 if (!EFI_ERROR (Status)) {
449 return Status;
450 }
451 }
452 Index++;
453 } while (!EFI_ERROR (PpiStatus));
454
455 //
456 // If no instances reports EFI_SUCCESS, then build-in support for
457 // the PE32+/TE XIP image format is used.
458 //
459 Status = PeiLoadImageLoadImage (
460 PeiServices,
461 FileHandle,
462 NULL,
463 NULL,
464 EntryPoint,
465 AuthenticationState
466 );
467 return Status;
468 }
469
470
471 /**
472
473 Install Pei Load File PPI.
474
475
476 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
477 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
478
479 **/
480 VOID
481 InitializeImageServices (
482 IN PEI_CORE_INSTANCE *PrivateData,
483 IN PEI_CORE_INSTANCE *OldCoreData
484 )
485 {
486 if (OldCoreData == NULL) {
487 //
488 // The first time we are XIP (running from FLASH). We need to remember the
489 // FLASH address so we can reinstall the memory version that runs faster
490 //
491 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
492 PeiServicesInstallPpi (PrivateData->XipLoadFile);
493 } else {
494 //
495 // 2nd time we are running from memory so replace the XIP version with the
496 // new memory version.
497 //
498 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
499 }
500 }
501
502
503