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