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