]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Pei/Image/Image.c
Fix a bug:
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
CommitLineData
615c6dd0 1/** @file\r
b1f6a7c6 2 Pei Core Load Image Support\r
54ea99a7 3\r
cd5ebaa0
HT
4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
54ea99a7 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
192f6d4c 12\r
615c6dd0 13**/\r
192f6d4c 14\r
0d516397 15#include "PeiMain.h"\r
192f6d4c 16\r
b0d803fe 17\r
fe1e36e5 18EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {\r
b0d803fe 19 PeiLoadImageLoadImageWrapper\r
20};\r
21\r
22\r
fe1e36e5 23EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {\r
b0d803fe 24 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
25 &gEfiPeiLoadFilePpiGuid,\r
26 &mPeiLoadImagePpi\r
27};\r
28\r
b1f6a7c6 29/**\r
30\r
25973fc3 31 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.\r
32 The function is used for XIP code to have optimized memory copy.\r
b1f6a7c6 33\r
34 @param FileHandle - The handle to the PE/COFF file\r
35 @param FileOffset - The offset, in bytes, into the file to read\r
36 @param ReadSize - The number of bytes to read from the file starting at FileOffset\r
37 @param Buffer - A pointer to the buffer to read the data into.\r
38\r
39 @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
40\r
41**/\r
b0d803fe 42EFI_STATUS\r
43EFIAPI\r
44PeiImageRead (\r
45 IN VOID *FileHandle,\r
46 IN UINTN FileOffset,\r
ed299e3c 47 IN UINTN *ReadSize,\r
b0d803fe 48 OUT VOID *Buffer\r
49 )\r
b0d803fe 50{\r
a9bfd802
LG
51 CHAR8 *Destination8;\r
52 CHAR8 *Source8;\r
25973fc3 53 \r
54 Destination8 = Buffer;\r
55 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
56 if (Destination8 != Source8) {\r
57 CopyMem (Destination8, Source8, *ReadSize);\r
58 }\r
59\r
60 return EFI_SUCCESS;\r
61}\r
62\r
63/**\r
64\r
65 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file.\r
66 The function is implemented as PIC so as to support shadowing.\r
67\r
68 @param FileHandle - The handle to the PE/COFF file\r
69 @param FileOffset - The offset, in bytes, into the file to read\r
70 @param ReadSize - The number of bytes to read from the file starting at FileOffset\r
71 @param Buffer - A pointer to the buffer to read the data into.\r
72\r
73 @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
74\r
75**/\r
76EFI_STATUS\r
77EFIAPI\r
78PeiImageReadForShadow (\r
79 IN VOID *FileHandle,\r
80 IN UINTN FileOffset,\r
81 IN UINTN *ReadSize,\r
82 OUT VOID *Buffer\r
83 )\r
84{\r
4da30589 85 volatile CHAR8 *Destination8;\r
86 CHAR8 *Source8;\r
87 UINTN Length;\r
a9bfd802
LG
88\r
89 Destination8 = Buffer;\r
90 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
43ada17c 91 if (Destination8 != Source8) {\r
92 Length = *ReadSize;\r
93 while ((Length--) > 0) {\r
94 *(Destination8++) = *(Source8++);\r
95 }\r
a9bfd802
LG
96 }\r
97\r
b0d803fe 98 return EFI_SUCCESS;\r
99}\r
100\r
b1f6a7c6 101/**\r
b0d803fe 102\r
ed299e3c 103 Support routine to get the Image read file function.\r
b0d803fe 104\r
b1f6a7c6 105 @param ImageContext - The context of the image being loaded\r
b0d803fe 106\r
b1f6a7c6 107 @retval EFI_SUCCESS - If Image function location is found\r
b0d803fe 108\r
b1f6a7c6 109**/\r
110EFI_STATUS\r
111GetImageReadFunction (\r
112 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
113 )\r
b0d803fe 114{\r
43ada17c 115 PEI_CORE_INSTANCE *Private;\r
b0d803fe 116 VOID* MemoryBuffer;\r
117\r
43ada17c 118 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());\r
b0d803fe 119\r
f5050909 120 if (!Private->PeiMemoryInstalled || (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) || EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_IA64)) {\r
43ada17c 121 ImageContext->ImageRead = PeiImageRead;\r
122 } else {\r
25973fc3 123 if (Private->ShadowedImageRead == NULL) {\r
124 MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);\r
125 ASSERT (MemoryBuffer != NULL);\r
126 CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageReadForShadow, 0x400);\r
127 Private->ShadowedImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;\r
128 }\r
43ada17c 129\r
25973fc3 130 ImageContext->ImageRead = Private->ShadowedImageRead;\r
43ada17c 131 }\r
b0d803fe 132\r
133 return EFI_SUCCESS;\r
134}\r
54ea99a7 135/**\r
136 To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If \r
137 memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.\r
138 The function is only invoked when load modules at fixed address feature is enabled. \r
139 \r
140 @param Private Pointer to the private data passed in from caller\r
141 @param ImageBase The base addres the image will be loaded at.\r
142 @param ImageSize The size of the image\r
143 \r
144 @retval EFI_SUCCESS The memory range the image will be loaded in is available\r
145 @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available\r
146**/\r
147EFI_STATUS\r
148CheckAndMarkFixLoadingMemoryUsageBitMap (\r
149 IN PEI_CORE_INSTANCE *Private,\r
150 IN EFI_PHYSICAL_ADDRESS ImageBase,\r
151 IN UINT32 ImageSize\r
152 )\r
153{\r
154 UINT32 DxeCodePageNumber;\r
155 UINT64 ReservedCodeSize;\r
156 EFI_PHYSICAL_ADDRESS PeiCodeBase;\r
157 UINT32 BaseOffsetPageNumber;\r
158 UINT32 TopOffsetPageNumber;\r
159 UINT32 Index;\r
160 UINT64 *MemoryUsageBitMap;\r
161 \r
162\r
163 //\r
164 // The reserved code range includes RuntimeCodePage range, Boot time code range and PEI code range.\r
165 //\r
166 DxeCodePageNumber = PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
167 DxeCodePageNumber += PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
168 ReservedCodeSize = EFI_PAGES_TO_SIZE(DxeCodePageNumber + PcdGet32(PcdLoadFixAddressPeiCodePageNumber));\r
169 PeiCodeBase = Private->LoadModuleAtFixAddressTopAddress - ReservedCodeSize;\r
170 \r
171 //\r
172 // Test the memory range for loading the image in the PEI code range.\r
173 //\r
174 if ((Private->LoadModuleAtFixAddressTopAddress - EFI_PAGES_TO_SIZE(DxeCodePageNumber)) < (ImageBase + ImageSize) ||\r
175 (PeiCodeBase > ImageBase)) { \r
176 return EFI_NOT_FOUND; \r
177 }\r
178 \r
179 //\r
180 // Test if the memory is avalaible or not.\r
181 //\r
182 MemoryUsageBitMap = Private->PeiCodeMemoryRangeUsageBitMap; \r
183 BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - PeiCodeBase));\r
184 TopOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - PeiCodeBase));\r
185 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
186 if ((MemoryUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
187 //\r
188 // This page is already used.\r
189 //\r
190 return EFI_NOT_FOUND; \r
191 }\r
192 }\r
193 \r
194 //\r
195 // Being here means the memory range is available. So mark the bits for the memory range\r
196 // \r
197 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
198 MemoryUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
199 }\r
200 return EFI_SUCCESS; \r
201}\r
202/**\r
203\r
204 Get the fixed loadding address from image header assigned by build tool. This function only be called\r
205 when Loading module at Fixed address feature enabled.\r
206\r
207 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
208 image that needs to be examined by this function.\r
209 @param Private Pointer to the private data passed in from caller\r
210\r
211 @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .\r
212 @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.\r
b0d803fe 213\r
54ea99a7 214**/\r
215EFI_STATUS\r
216GetPeCoffImageFixLoadingAssignedAddress(\r
217 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
218 IN PEI_CORE_INSTANCE *Private\r
219 )\r
220{\r
221 UINTN SectionHeaderOffset;\r
222 EFI_STATUS Status;\r
223 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
224 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;\r
225 EFI_PHYSICAL_ADDRESS FixLoaddingAddress;\r
226 UINT16 Index;\r
227 UINTN Size;\r
228 UINT16 NumberOfSections;\r
229 UINT64 ValueInSectionHeader;\r
230 \r
231\r
232 FixLoaddingAddress = 0;\r
233 Status = EFI_NOT_FOUND;\r
234\r
235 //\r
236 // Get PeHeader pointer\r
237 //\r
238 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);\r
239 if (ImageContext->IsTeImage) {\r
240 //\r
241 // for TE image, the fix loadding address is saved in first section header that doesn't point\r
242 // to code section.\r
243 //\r
244 SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);\r
245 NumberOfSections = ImgHdr->Te.NumberOfSections;\r
246 } else {\r
247 SectionHeaderOffset = (UINTN)(\r
248 ImageContext->PeCoffHeaderOffset +\r
249 sizeof (UINT32) +\r
250 sizeof (EFI_IMAGE_FILE_HEADER) +\r
251 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
252 );\r
253 NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
254 }\r
255 //\r
256 // Get base address from the first section header that doesn't point to code section.\r
257 //\r
258 for (Index = 0; Index < NumberOfSections; Index++) {\r
259 //\r
260 // Read section header from file\r
261 //\r
262 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
263 Status = ImageContext->ImageRead (\r
264 ImageContext->Handle,\r
265 SectionHeaderOffset,\r
266 &Size,\r
267 &SectionHeader\r
268 );\r
269 if (EFI_ERROR (Status)) {\r
270 return Status;\r
271 }\r
272\r
273 Status = EFI_NOT_FOUND;\r
274\r
275 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
276 //\r
277 // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
278 // that doesn't point to code section in image header, as well as ImageBase field of image header. A notable thing is\r
279 // that for PEIM, the value in ImageBase field may not be equal to the value in PointerToRelocations & PointerToLineNumbers because\r
280 // for XIP PEIM, ImageBase field holds the image base address running on the Flash. And PointerToRelocations & PointerToLineNumbers\r
281 // hold the image base address when it is shadow to the memory. And there is an assumption that when the feature is enabled, if a\r
282 // module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers fields should NOT be Zero, or\r
283 // else, these 2 fileds should be set to Zero\r
284 //\r
285 ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
286 if (ValueInSectionHeader != 0) {\r
287 //\r
288 // Found first section header that doesn't point to code section.\r
289 //\r
852081fc 290 if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) > 0) {\r
54ea99a7 291 //\r
292 // When LMFA feature is configured as Load Module at Fixed Absolute Address mode, PointerToRelocations & PointerToLineNumbers field\r
293 // hold the absolute address of image base runing in memory\r
294 //\r
295 FixLoaddingAddress = ValueInSectionHeader;\r
296 } else {\r
297 //\r
298 // When LMFA feature is configured as Load Module at Fixed offset mode, PointerToRelocations & PointerToLineNumbers field\r
299 // hold the offset relative to a platform-specific top address.\r
300 //\r
301 FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);\r
302 }\r
303 //\r
304 // Check if the memory range is avaliable.\r
305 //\r
306 Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoaddingAddress, (UINT32) ImageContext->ImageSize);\r
307 if (!EFI_ERROR(Status)) {\r
308 //\r
309 // The assigned address is valid. Return the specified loadding address\r
310 //\r
311 ImageContext->ImageAddress = FixLoaddingAddress;\r
312 }\r
313 }\r
314 break;\r
315 }\r
316 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
317 }\r
852081fc 318 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status= %r \n", (VOID *)(UINTN)FixLoaddingAddress, Status));\r
54ea99a7 319 return Status;\r
320}\r
b1f6a7c6 321/**\r
322\r
323 Loads and relocates a PE/COFF image into memory.\r
341a658f 324 If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.\r
b1f6a7c6 325\r
326 @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
327 @param ImageAddress - The base address of the relocated PE/COFF image\r
328 @param ImageSize - The size of the relocated PE/COFF image\r
329 @param EntryPoint - The entry point of the relocated PE/COFF image\r
330\r
331 @retval EFI_SUCCESS The file was loaded and relocated\r
332 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file\r
333\r
334**/\r
b0d803fe 335EFI_STATUS\r
336LoadAndRelocatePeCoffImage (\r
b0d803fe 337 IN VOID *Pe32Data,\r
338 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
339 OUT UINT64 *ImageSize,\r
340 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
341 )\r
b0d803fe 342{\r
343 EFI_STATUS Status;\r
344 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
43ada17c 345 PEI_CORE_INSTANCE *Private;\r
346\r
347 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());\r
b0d803fe 348\r
b0d803fe 349 ZeroMem (&ImageContext, sizeof (ImageContext));\r
350 ImageContext.Handle = Pe32Data;\r
351 Status = GetImageReadFunction (&ImageContext);\r
352\r
353 ASSERT_EFI_ERROR (Status);\r
354\r
3d7b0992 355 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
b0d803fe 356 if (EFI_ERROR (Status)) {\r
357 return Status;\r
358 }\r
359 //\r
9626a87e
LG
360 // When Image has no reloc section, it can't be relocated into memory.\r
361 //\r
414bdfb6 362 if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
54ea99a7 363 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));\r
9626a87e 364 }\r
414bdfb6 365\r
341a658f
LG
366 //\r
367 // Set default base address to current image address.\r
368 //\r
369 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;\r
54ea99a7 370\r
9626a87e 371 //\r
341a658f 372 // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.\r
b0d803fe 373 //\r
bfd4a3f1 374 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
852081fc 375 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
54ea99a7 376 Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);\r
377 if (EFI_ERROR (Status)){\r
378 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));\r
379 //\r
380 // The PEIM is not assiged valid address, try to allocate page to load it.\r
381 //\r
382 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
383 }\r
384 } else {\r
385 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
386 }\r
43ada17c 387 ASSERT (ImageContext.ImageAddress != 0);\r
341a658f
LG
388 if (ImageContext.ImageAddress == 0) {\r
389 return EFI_OUT_OF_RESOURCES;\r
390 }\r
54ea99a7 391\r
43ada17c 392 //\r
393 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.\r
394 //\r
395 if (ImageContext.IsTeImage) {\r
54ea99a7 396 ImageContext.ImageAddress = ImageContext.ImageAddress +\r
43ada17c 397 ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -\r
398 sizeof (EFI_TE_IMAGE_HEADER);\r
399 }\r
4e844595 400 }\r
b0d803fe 401\r
402 //\r
403 // Load the image to our new buffer\r
404 //\r
3d7b0992 405 Status = PeCoffLoaderLoadImage (&ImageContext);\r
b0d803fe 406 if (EFI_ERROR (Status)) {\r
407 return Status;\r
408 }\r
409 //\r
410 // Relocate the image in our new buffer\r
411 //\r
3d7b0992 412 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
b0d803fe 413 if (EFI_ERROR (Status)) {\r
414 return Status;\r
415 }\r
416\r
417 //\r
418 // Flush the instruction cache so the image data is written before we execute it\r
419 //\r
341a658f 420 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
43ada17c 421 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
422 }\r
b0d803fe 423\r
424 *ImageAddress = ImageContext.ImageAddress;\r
425 *ImageSize = ImageContext.ImageSize;\r
426 *EntryPoint = ImageContext.EntryPoint;\r
427\r
428 return EFI_SUCCESS;\r
429}\r
430\r
b1f6a7c6 431/**\r
54ea99a7 432 Loads a PEIM into memory for subsequent execution. If there are compressed\r
433 images or images that need to be relocated into memory for performance reasons,\r
ed299e3c 434 this service performs that transformation.\r
b1f6a7c6 435\r
ed299e3c 436 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
b1f6a7c6 437 @param FileHandle Pointer to the FFS file header of the image.\r
438 @param ImageAddressArg Pointer to PE/TE image.\r
439 @param ImageSizeArg Size of PE/TE image.\r
440 @param EntryPoint Pointer to entry point of specified image file for output.\r
441 @param AuthenticationState - Pointer to attestation authentication state of image.\r
442\r
ed299e3c
LG
443 @retval EFI_SUCCESS Image is successfully loaded.\r
444 @retval EFI_NOT_FOUND Fail to locate necessary PPI.\r
445 @retval EFI_UNSUPPORTED Image Machine Type is not supported.\r
b1f6a7c6 446\r
447**/\r
b0d803fe 448EFI_STATUS\r
449PeiLoadImageLoadImage (\r
284c8400 450 IN CONST EFI_PEI_SERVICES **PeiServices,\r
b0d803fe 451 IN EFI_PEI_FILE_HANDLE FileHandle,\r
452 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL\r
453 OUT UINT64 *ImageSizeArg, OPTIONAL\r
454 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
455 OUT UINT32 *AuthenticationState\r
456 )\r
192f6d4c 457{\r
458 EFI_STATUS Status;\r
459 VOID *Pe32Data;\r
192f6d4c 460 EFI_PHYSICAL_ADDRESS ImageAddress;\r
461 UINT64 ImageSize;\r
462 EFI_PHYSICAL_ADDRESS ImageEntryPoint;\r
192f6d4c 463 UINT16 Machine;\r
3076397e 464 EFI_SECTION_TYPE SearchType1;\r
465 EFI_SECTION_TYPE SearchType2;\r
192f6d4c 466\r
3d7b0992
LG
467 *EntryPoint = 0;\r
468 ImageSize = 0;\r
b0d803fe 469 *AuthenticationState = 0;\r
192f6d4c 470\r
3076397e 471 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {\r
472 SearchType1 = EFI_SECTION_TE;\r
473 SearchType2 = EFI_SECTION_PE32;\r
474 } else {\r
475 SearchType1 = EFI_SECTION_PE32;\r
476 SearchType2 = EFI_SECTION_TE;\r
477 }\r
1b620adb 478\r
192f6d4c 479 //\r
54ea99a7 480 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst\r
3076397e 481 // is true, TE will be searched first).\r
192f6d4c 482 //\r
483 Status = PeiServicesFfsFindSectionData (\r
3076397e 484 SearchType1,\r
b0d803fe 485 FileHandle,\r
192f6d4c 486 &Pe32Data\r
487 );\r
488 //\r
3076397e 489 // If we didn't find a first exe section, try to find the second exe section.\r
192f6d4c 490 //\r
491 if (EFI_ERROR (Status)) {\r
492 Status = PeiServicesFfsFindSectionData (\r
3076397e 493 SearchType2,\r
b0d803fe 494 FileHandle,\r
495 &Pe32Data\r
192f6d4c 496 );\r
b0d803fe 497 if (EFI_ERROR (Status)) {\r
192f6d4c 498 //\r
b0d803fe 499 // PEI core only carry the loader function fro TE and PE32 executables\r
500 // If this two section does not exist, just return.\r
192f6d4c 501 //\r
b0d803fe 502 return Status;\r
503 }\r
504 }\r
54ea99a7 505\r
43ada17c 506 //\r
507 // If memory is installed, perform the shadow operations\r
508 //\r
509 Status = LoadAndRelocatePeCoffImage (\r
510 Pe32Data,\r
511 &ImageAddress,\r
512 &ImageSize,\r
513 &ImageEntryPoint\r
514 );\r
192f6d4c 515\r
43ada17c 516 ASSERT_EFI_ERROR (Status);\r
3d7b0992 517\r
43ada17c 518\r
519 if (EFI_ERROR (Status)) {\r
520 return Status;\r
192f6d4c 521 }\r
43ada17c 522\r
523 //\r
524 // Got the entry point from the loaded Pe32Data\r
525 //\r
526 Pe32Data = (VOID *) ((UINTN) ImageAddress);\r
527 *EntryPoint = ImageEntryPoint;\r
54ea99a7 528\r
3d7b0992 529 Machine = PeCoffLoaderGetMachineType (Pe32Data);\r
54ea99a7 530\r
192f6d4c 531 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {\r
8c519a56 532 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {\r
533 return EFI_UNSUPPORTED;\r
534 }\r
192f6d4c 535 }\r
536\r
b0d803fe 537 if (ImageAddressArg != NULL) {\r
538 *ImageAddressArg = ImageAddress;\r
539 }\r
540\r
541 if (ImageSizeArg != NULL) {\r
542 *ImageSizeArg = ImageSize;\r
543 }\r
54ea99a7 544\r
192f6d4c 545 DEBUG_CODE_BEGIN ();\r
3d7b0992
LG
546 CHAR8 *AsciiString;\r
547 CHAR8 AsciiBuffer[512];\r
548 INT32 Index;\r
549 INT32 Index1;\r
e98cd821
LG
550\r
551 //\r
552 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi\r
553 //\r
7cf02714 554 if (Machine != EFI_IMAGE_MACHINE_IA64) {\r
91136124 555 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));\r
e98cd821
LG
556 } else {\r
557 //\r
558 // For IPF Image, the real entry point should be print.\r
559 //\r
91136124 560 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));\r
e98cd821 561 }\r
54ea99a7 562\r
e98cd821
LG
563 //\r
564 // Print Module Name by PeImage PDB file name.\r
565 //\r
3d7b0992 566 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);\r
54ea99a7 567\r
3d7b0992 568 if (AsciiString != NULL) {\r
19ea58a1 569 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {\r
3d7b0992
LG
570 if (AsciiString[Index] == '\\') {\r
571 break;\r
572 }\r
192f6d4c 573 }\r
192f6d4c 574\r
3d7b0992
LG
575 if (Index != 0) {\r
576 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {\r
577 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];\r
192f6d4c 578 }\r
3d7b0992
LG
579 AsciiBuffer [Index1] = '\0';\r
580 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));\r
192f6d4c 581 }\r
582 }\r
3d7b0992 583\r
192f6d4c 584 DEBUG_CODE_END ();\r
585\r
586 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));\r
587\r
588 return EFI_SUCCESS;\r
b0d803fe 589\r
590}\r
591\r
592\r
b1f6a7c6 593/**\r
594 The wrapper function of PeiLoadImageLoadImage().\r
595\r
596 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.\r
597 @param FileHandle - Pointer to the FFS file header of the image.\r
598 @param ImageAddressArg - Pointer to PE/TE image.\r
599 @param ImageSizeArg - Size of PE/TE image.\r
600 @param EntryPoint - Pointer to entry point of specified image file for output.\r
601 @param AuthenticationState - Pointer to attestation authentication state of image.\r
602\r
603 @return Status of PeiLoadImageLoadImage().\r
604\r
605**/\r
b0d803fe 606EFI_STATUS\r
607EFIAPI\r
608PeiLoadImageLoadImageWrapper (\r
609 IN CONST EFI_PEI_LOAD_FILE_PPI *This,\r
610 IN EFI_PEI_FILE_HANDLE FileHandle,\r
611 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL\r
612 OUT UINT64 *ImageSizeArg, OPTIONAL\r
613 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
614 OUT UINT32 *AuthenticationState\r
615 )\r
b0d803fe 616{\r
617 return PeiLoadImageLoadImage (\r
618 GetPeiServicesTablePointer (),\r
619 FileHandle,\r
620 ImageAddressArg,\r
621 ImageSizeArg,\r
622 EntryPoint,\r
623 AuthenticationState\r
624 );\r
192f6d4c 625}\r
b0d803fe 626\r
341a658f
LG
627/**\r
628 Check whether the input image has the relocation.\r
629\r
630 @param Pe32Data Pointer to the PE/COFF or TE image.\r
631\r
632 @retval TRUE Relocation is stripped.\r
633 @retval FALSE Relocation is not stripped.\r
634\r
635**/\r
636BOOLEAN\r
637RelocationIsStrip (\r
638 IN VOID *Pe32Data\r
639 )\r
640{\r
641 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
642 EFI_IMAGE_DOS_HEADER *DosHdr;\r
643\r
644 ASSERT (Pe32Data != NULL);\r
645\r
646 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
647 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
648 //\r
649 // DOS image header is present, so read the PE header after the DOS image header.\r
650 //\r
651 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
652 } else {\r
653 //\r
654 // DOS image header is not present, so PE header is at the image base.\r
655 //\r
656 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
657 }\r
658\r
659 //\r
660 // Three cases with regards to relocations:\r
661 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
662 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
663 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
664 // has no base relocs to apply\r
665 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
666 //\r
667 // Look at the file header to determine if relocations have been stripped, and\r
668 // save this info in the image context for later use.\r
669 //\r
670 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
671 if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
672 return TRUE;\r
673 } else {\r
674 return FALSE;\r
675 }\r
676 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
677 if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {\r
678 return TRUE;\r
679 } else {\r
680 return FALSE;\r
681 }\r
682 }\r
683\r
684 return FALSE;\r
685}\r
686\r
b1f6a7c6 687/**\r
ed299e3c 688 Routine to load image file for subsequent execution by LoadFile Ppi.\r
54ea99a7 689 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE\r
ed299e3c 690 XIP image format is used.\r
b1f6a7c6 691\r
ed299e3c
LG
692 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
693 @param FileHandle - Pointer to the FFS file header of the image.\r
341a658f 694 @param PeimState - The dispatch state of the input PEIM handle.\r
ed299e3c
LG
695 @param EntryPoint - Pointer to entry point of specified image file for output.\r
696 @param AuthenticationState - Pointer to attestation authentication state of image.\r
b1f6a7c6 697\r
ed299e3c
LG
698 @retval EFI_SUCCESS - Image is successfully loaded.\r
699 @retval EFI_NOT_FOUND - Fail to locate necessary PPI\r
700 @retval Others - Fail to load file.\r
b1f6a7c6 701\r
702**/\r
b0d803fe 703EFI_STATUS\r
704PeiLoadImage (\r
6c7a807a 705 IN CONST EFI_PEI_SERVICES **PeiServices,\r
b0d803fe 706 IN EFI_PEI_FILE_HANDLE FileHandle,\r
341a658f 707 IN UINT8 PeimState,\r
b0d803fe 708 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
709 OUT UINT32 *AuthenticationState\r
710 )\r
b0d803fe 711{\r
712 EFI_STATUS PpiStatus;\r
713 EFI_STATUS Status;\r
714 UINTN Index;\r
715 EFI_PEI_LOAD_FILE_PPI *LoadFile;\r
716 EFI_PHYSICAL_ADDRESS ImageAddress;\r
717 UINT64 ImageSize;\r
341a658f 718 BOOLEAN IsStrip;\r
b0d803fe 719\r
341a658f 720 IsStrip = FALSE;\r
b0d803fe 721 //\r
722 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.\r
723 // one at a time, until one reports EFI_SUCCESS.\r
724 //\r
725 Index = 0;\r
726 do {\r
727 PpiStatus = PeiServicesLocatePpi (\r
728 &gEfiPeiLoadFilePpiGuid,\r
729 Index,\r
730 NULL,\r
731 (VOID **)&LoadFile\r
732 );\r
733 if (!EFI_ERROR (PpiStatus)) {\r
734 Status = LoadFile->LoadFile (\r
54ea99a7 735 LoadFile,\r
736 FileHandle,\r
737 &ImageAddress,\r
b0d803fe 738 &ImageSize,\r
739 EntryPoint,\r
740 AuthenticationState\r
741 );\r
742 if (!EFI_ERROR (Status)) {\r
341a658f
LG
743 //\r
744 // The shadowed PEIM must be relocatable.\r
745 //\r
746 if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {\r
747 IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);\r
748 ASSERT (!IsStrip);\r
749 if (IsStrip) {\r
750 return EFI_UNSUPPORTED;\r
751 }\r
752 }\r
753\r
db0b7ad5
LG
754 //\r
755 // The image to be started must have the machine type supported by PeiCore.\r
756 //\r
757 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));\r
919df8e6 758 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {\r
919df8e6
LG
759 return EFI_UNSUPPORTED;\r
760 }\r
b0d803fe 761 return Status;\r
762 }\r
763 }\r
764 Index++;\r
765 } while (!EFI_ERROR (PpiStatus));\r
766\r
8c519a56 767 return PpiStatus;\r
b0d803fe 768}\r
769\r
770\r
b1f6a7c6 771/**\r
b0d803fe 772\r
ed299e3c
LG
773 Install Pei Load File PPI.\r
774\r
775\r
776 @param PrivateData - Pointer to PEI_CORE_INSTANCE.\r
777 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.\r
b0d803fe 778\r
b1f6a7c6 779**/\r
780VOID\r
781InitializeImageServices (\r
782 IN PEI_CORE_INSTANCE *PrivateData,\r
783 IN PEI_CORE_INSTANCE *OldCoreData\r
784 )\r
b0d803fe 785{\r
b0d803fe 786 if (OldCoreData == NULL) {\r
787 //\r
788 // The first time we are XIP (running from FLASH). We need to remember the\r
789 // FLASH address so we can reinstall the memory version that runs faster\r
790 //\r
791 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;\r
792 PeiServicesInstallPpi (PrivateData->XipLoadFile);\r
793 } else {\r
794 //\r
54ea99a7 795 // 2nd time we are running from memory so replace the XIP version with the\r
796 // new memory version.\r
b0d803fe 797 //\r
54ea99a7 798 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);\r
b0d803fe 799 }\r
800}\r
801\r
802\r
803\r
341a658f 804\r