]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Pei/Image/Image.c
Clean up DEC files:
[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
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
351\r
352 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());\r
b0d803fe 353\r
b0d803fe 354 ZeroMem (&ImageContext, sizeof (ImageContext));\r
355 ImageContext.Handle = Pe32Data;\r
356 Status = GetImageReadFunction (&ImageContext);\r
357\r
358 ASSERT_EFI_ERROR (Status);\r
359\r
3d7b0992 360 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
b0d803fe 361 if (EFI_ERROR (Status)) {\r
362 return Status;\r
363 }\r
364 //\r
9626a87e
LG
365 // When Image has no reloc section, it can't be relocated into memory.\r
366 //\r
414bdfb6 367 if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
54ea99a7 368 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 369 }\r
414bdfb6 370\r
341a658f
LG
371 //\r
372 // Set default base address to current image address.\r
373 //\r
374 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;\r
54ea99a7 375\r
9626a87e 376 //\r
341a658f 377 // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.\r
b0d803fe 378 //\r
bfd4a3f1 379 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
852081fc 380 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {\r
54ea99a7 381 Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);\r
382 if (EFI_ERROR (Status)){\r
383 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));\r
384 //\r
385 // The PEIM is not assiged valid address, try to allocate page to load it.\r
386 //\r
387 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
388 }\r
389 } else {\r
390 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
391 }\r
43ada17c 392 ASSERT (ImageContext.ImageAddress != 0);\r
341a658f
LG
393 if (ImageContext.ImageAddress == 0) {\r
394 return EFI_OUT_OF_RESOURCES;\r
395 }\r
54ea99a7 396\r
43ada17c 397 //\r
398 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.\r
399 //\r
400 if (ImageContext.IsTeImage) {\r
54ea99a7 401 ImageContext.ImageAddress = ImageContext.ImageAddress +\r
43ada17c 402 ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -\r
403 sizeof (EFI_TE_IMAGE_HEADER);\r
404 }\r
4e844595 405 }\r
b0d803fe 406\r
407 //\r
408 // Load the image to our new buffer\r
409 //\r
3d7b0992 410 Status = PeCoffLoaderLoadImage (&ImageContext);\r
b0d803fe 411 if (EFI_ERROR (Status)) {\r
412 return Status;\r
413 }\r
414 //\r
415 // Relocate the image in our new buffer\r
416 //\r
3d7b0992 417 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
b0d803fe 418 if (EFI_ERROR (Status)) {\r
419 return Status;\r
420 }\r
421\r
422 //\r
423 // Flush the instruction cache so the image data is written before we execute it\r
424 //\r
341a658f 425 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {\r
43ada17c 426 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
427 }\r
b0d803fe 428\r
429 *ImageAddress = ImageContext.ImageAddress;\r
430 *ImageSize = ImageContext.ImageSize;\r
431 *EntryPoint = ImageContext.EntryPoint;\r
432\r
433 return EFI_SUCCESS;\r
434}\r
435\r
b1f6a7c6 436/**\r
54ea99a7 437 Loads a PEIM into memory for subsequent execution. If there are compressed\r
438 images or images that need to be relocated into memory for performance reasons,\r
ed299e3c 439 this service performs that transformation.\r
b1f6a7c6 440\r
ed299e3c 441 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
b1f6a7c6 442 @param FileHandle Pointer to the FFS file header of the image.\r
443 @param ImageAddressArg Pointer to PE/TE image.\r
444 @param ImageSizeArg Size of PE/TE image.\r
445 @param EntryPoint Pointer to entry point of specified image file for output.\r
446 @param AuthenticationState - Pointer to attestation authentication state of image.\r
447\r
ed299e3c
LG
448 @retval EFI_SUCCESS Image is successfully loaded.\r
449 @retval EFI_NOT_FOUND Fail to locate necessary PPI.\r
450 @retval EFI_UNSUPPORTED Image Machine Type is not supported.\r
b1f6a7c6 451\r
452**/\r
b0d803fe 453EFI_STATUS\r
454PeiLoadImageLoadImage (\r
284c8400 455 IN CONST EFI_PEI_SERVICES **PeiServices,\r
b0d803fe 456 IN EFI_PEI_FILE_HANDLE FileHandle,\r
457 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL\r
458 OUT UINT64 *ImageSizeArg, OPTIONAL\r
459 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
460 OUT UINT32 *AuthenticationState\r
461 )\r
192f6d4c 462{\r
463 EFI_STATUS Status;\r
464 VOID *Pe32Data;\r
192f6d4c 465 EFI_PHYSICAL_ADDRESS ImageAddress;\r
466 UINT64 ImageSize;\r
467 EFI_PHYSICAL_ADDRESS ImageEntryPoint;\r
192f6d4c 468 UINT16 Machine;\r
3076397e 469 EFI_SECTION_TYPE SearchType1;\r
470 EFI_SECTION_TYPE SearchType2;\r
192f6d4c 471\r
3d7b0992
LG
472 *EntryPoint = 0;\r
473 ImageSize = 0;\r
b0d803fe 474 *AuthenticationState = 0;\r
192f6d4c 475\r
3076397e 476 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {\r
477 SearchType1 = EFI_SECTION_TE;\r
478 SearchType2 = EFI_SECTION_PE32;\r
479 } else {\r
480 SearchType1 = EFI_SECTION_PE32;\r
481 SearchType2 = EFI_SECTION_TE;\r
482 }\r
1b620adb 483\r
192f6d4c 484 //\r
54ea99a7 485 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst\r
3076397e 486 // is true, TE will be searched first).\r
192f6d4c 487 //\r
488 Status = PeiServicesFfsFindSectionData (\r
3076397e 489 SearchType1,\r
b0d803fe 490 FileHandle,\r
192f6d4c 491 &Pe32Data\r
492 );\r
493 //\r
3076397e 494 // If we didn't find a first exe section, try to find the second exe section.\r
192f6d4c 495 //\r
496 if (EFI_ERROR (Status)) {\r
497 Status = PeiServicesFfsFindSectionData (\r
3076397e 498 SearchType2,\r
b0d803fe 499 FileHandle,\r
500 &Pe32Data\r
192f6d4c 501 );\r
b0d803fe 502 if (EFI_ERROR (Status)) {\r
192f6d4c 503 //\r
b0d803fe 504 // PEI core only carry the loader function fro TE and PE32 executables\r
505 // If this two section does not exist, just return.\r
192f6d4c 506 //\r
b0d803fe 507 return Status;\r
508 }\r
509 }\r
54ea99a7 510\r
43ada17c 511 //\r
512 // If memory is installed, perform the shadow operations\r
513 //\r
514 Status = LoadAndRelocatePeCoffImage (\r
515 Pe32Data,\r
516 &ImageAddress,\r
517 &ImageSize,\r
518 &ImageEntryPoint\r
519 );\r
192f6d4c 520\r
43ada17c 521 ASSERT_EFI_ERROR (Status);\r
3d7b0992 522\r
43ada17c 523\r
524 if (EFI_ERROR (Status)) {\r
525 return Status;\r
192f6d4c 526 }\r
43ada17c 527\r
528 //\r
529 // Got the entry point from the loaded Pe32Data\r
530 //\r
531 Pe32Data = (VOID *) ((UINTN) ImageAddress);\r
532 *EntryPoint = ImageEntryPoint;\r
54ea99a7 533\r
3d7b0992 534 Machine = PeCoffLoaderGetMachineType (Pe32Data);\r
54ea99a7 535\r
192f6d4c 536 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {\r
8c519a56 537 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {\r
538 return EFI_UNSUPPORTED;\r
539 }\r
192f6d4c 540 }\r
541\r
b0d803fe 542 if (ImageAddressArg != NULL) {\r
543 *ImageAddressArg = ImageAddress;\r
544 }\r
545\r
546 if (ImageSizeArg != NULL) {\r
547 *ImageSizeArg = ImageSize;\r
548 }\r
54ea99a7 549\r
192f6d4c 550 DEBUG_CODE_BEGIN ();\r
3d7b0992
LG
551 CHAR8 *AsciiString;\r
552 CHAR8 AsciiBuffer[512];\r
553 INT32 Index;\r
554 INT32 Index1;\r
e98cd821
LG
555\r
556 //\r
557 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi\r
558 //\r
7cf02714 559 if (Machine != EFI_IMAGE_MACHINE_IA64) {\r
91136124 560 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));\r
e98cd821
LG
561 } else {\r
562 //\r
563 // For IPF Image, the real entry point should be print.\r
564 //\r
91136124 565 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 566 }\r
54ea99a7 567\r
e98cd821
LG
568 //\r
569 // Print Module Name by PeImage PDB file name.\r
570 //\r
3d7b0992 571 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);\r
54ea99a7 572\r
3d7b0992 573 if (AsciiString != NULL) {\r
19ea58a1 574 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {\r
3d7b0992
LG
575 if (AsciiString[Index] == '\\') {\r
576 break;\r
577 }\r
192f6d4c 578 }\r
192f6d4c 579\r
3d7b0992
LG
580 if (Index != 0) {\r
581 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {\r
582 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];\r
192f6d4c 583 }\r
3d7b0992
LG
584 AsciiBuffer [Index1] = '\0';\r
585 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));\r
192f6d4c 586 }\r
587 }\r
3d7b0992 588\r
192f6d4c 589 DEBUG_CODE_END ();\r
590\r
591 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));\r
592\r
593 return EFI_SUCCESS;\r
b0d803fe 594\r
595}\r
596\r
597\r
b1f6a7c6 598/**\r
599 The wrapper function of PeiLoadImageLoadImage().\r
600\r
601 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.\r
602 @param FileHandle - Pointer to the FFS file header of the image.\r
603 @param ImageAddressArg - Pointer to PE/TE image.\r
604 @param ImageSizeArg - Size of PE/TE image.\r
605 @param EntryPoint - Pointer to entry point of specified image file for output.\r
606 @param AuthenticationState - Pointer to attestation authentication state of image.\r
607\r
608 @return Status of PeiLoadImageLoadImage().\r
609\r
610**/\r
b0d803fe 611EFI_STATUS\r
612EFIAPI\r
613PeiLoadImageLoadImageWrapper (\r
614 IN CONST EFI_PEI_LOAD_FILE_PPI *This,\r
615 IN EFI_PEI_FILE_HANDLE FileHandle,\r
616 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL\r
617 OUT UINT64 *ImageSizeArg, OPTIONAL\r
618 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
619 OUT UINT32 *AuthenticationState\r
620 )\r
b0d803fe 621{\r
622 return PeiLoadImageLoadImage (\r
623 GetPeiServicesTablePointer (),\r
624 FileHandle,\r
625 ImageAddressArg,\r
626 ImageSizeArg,\r
627 EntryPoint,\r
628 AuthenticationState\r
629 );\r
192f6d4c 630}\r
b0d803fe 631\r
341a658f
LG
632/**\r
633 Check whether the input image has the relocation.\r
634\r
635 @param Pe32Data Pointer to the PE/COFF or TE image.\r
636\r
637 @retval TRUE Relocation is stripped.\r
638 @retval FALSE Relocation is not stripped.\r
639\r
640**/\r
641BOOLEAN\r
642RelocationIsStrip (\r
643 IN VOID *Pe32Data\r
644 )\r
645{\r
646 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
647 EFI_IMAGE_DOS_HEADER *DosHdr;\r
648\r
649 ASSERT (Pe32Data != NULL);\r
650\r
651 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
652 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
653 //\r
654 // DOS image header is present, so read the PE header after the DOS image header.\r
655 //\r
656 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
657 } else {\r
658 //\r
659 // DOS image header is not present, so PE header is at the image base.\r
660 //\r
661 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
662 }\r
663\r
664 //\r
665 // Three cases with regards to relocations:\r
666 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
667 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
668 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
669 // has no base relocs to apply\r
670 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
671 //\r
672 // Look at the file header to determine if relocations have been stripped, and\r
673 // save this info in the image context for later use.\r
674 //\r
675 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
676 if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {\r
677 return TRUE;\r
678 } else {\r
679 return FALSE;\r
680 }\r
681 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
682 if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {\r
683 return TRUE;\r
684 } else {\r
685 return FALSE;\r
686 }\r
687 }\r
688\r
689 return FALSE;\r
690}\r
691\r
b1f6a7c6 692/**\r
ed299e3c 693 Routine to load image file for subsequent execution by LoadFile Ppi.\r
54ea99a7 694 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE\r
ed299e3c 695 XIP image format is used.\r
b1f6a7c6 696\r
ed299e3c
LG
697 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
698 @param FileHandle - Pointer to the FFS file header of the image.\r
341a658f 699 @param PeimState - The dispatch state of the input PEIM handle.\r
ed299e3c
LG
700 @param EntryPoint - Pointer to entry point of specified image file for output.\r
701 @param AuthenticationState - Pointer to attestation authentication state of image.\r
b1f6a7c6 702\r
ed299e3c
LG
703 @retval EFI_SUCCESS - Image is successfully loaded.\r
704 @retval EFI_NOT_FOUND - Fail to locate necessary PPI\r
705 @retval Others - Fail to load file.\r
b1f6a7c6 706\r
707**/\r
b0d803fe 708EFI_STATUS\r
709PeiLoadImage (\r
6c7a807a 710 IN CONST EFI_PEI_SERVICES **PeiServices,\r
b0d803fe 711 IN EFI_PEI_FILE_HANDLE FileHandle,\r
341a658f 712 IN UINT8 PeimState,\r
b0d803fe 713 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,\r
714 OUT UINT32 *AuthenticationState\r
715 )\r
b0d803fe 716{\r
717 EFI_STATUS PpiStatus;\r
718 EFI_STATUS Status;\r
719 UINTN Index;\r
720 EFI_PEI_LOAD_FILE_PPI *LoadFile;\r
721 EFI_PHYSICAL_ADDRESS ImageAddress;\r
722 UINT64 ImageSize;\r
341a658f 723 BOOLEAN IsStrip;\r
b0d803fe 724\r
341a658f 725 IsStrip = FALSE;\r
b0d803fe 726 //\r
727 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.\r
728 // one at a time, until one reports EFI_SUCCESS.\r
729 //\r
730 Index = 0;\r
731 do {\r
732 PpiStatus = PeiServicesLocatePpi (\r
733 &gEfiPeiLoadFilePpiGuid,\r
734 Index,\r
735 NULL,\r
736 (VOID **)&LoadFile\r
737 );\r
738 if (!EFI_ERROR (PpiStatus)) {\r
739 Status = LoadFile->LoadFile (\r
54ea99a7 740 LoadFile,\r
741 FileHandle,\r
742 &ImageAddress,\r
b0d803fe 743 &ImageSize,\r
744 EntryPoint,\r
745 AuthenticationState\r
746 );\r
747 if (!EFI_ERROR (Status)) {\r
341a658f
LG
748 //\r
749 // The shadowed PEIM must be relocatable.\r
750 //\r
751 if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {\r
752 IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);\r
753 ASSERT (!IsStrip);\r
754 if (IsStrip) {\r
755 return EFI_UNSUPPORTED;\r
756 }\r
757 }\r
758\r
db0b7ad5
LG
759 //\r
760 // The image to be started must have the machine type supported by PeiCore.\r
761 //\r
762 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));\r
919df8e6 763 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {\r
919df8e6
LG
764 return EFI_UNSUPPORTED;\r
765 }\r
b0d803fe 766 return Status;\r
767 }\r
768 }\r
769 Index++;\r
770 } while (!EFI_ERROR (PpiStatus));\r
771\r
8c519a56 772 return PpiStatus;\r
b0d803fe 773}\r
774\r
775\r
b1f6a7c6 776/**\r
b0d803fe 777\r
ed299e3c
LG
778 Install Pei Load File PPI.\r
779\r
780\r
781 @param PrivateData - Pointer to PEI_CORE_INSTANCE.\r
782 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.\r
b0d803fe 783\r
b1f6a7c6 784**/\r
785VOID\r
786InitializeImageServices (\r
787 IN PEI_CORE_INSTANCE *PrivateData,\r
788 IN PEI_CORE_INSTANCE *OldCoreData\r
789 )\r
b0d803fe 790{\r
b0d803fe 791 if (OldCoreData == NULL) {\r
792 //\r
793 // The first time we are XIP (running from FLASH). We need to remember the\r
794 // FLASH address so we can reinstall the memory version that runs faster\r
795 //\r
796 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;\r
797 PeiServicesInstallPpi (PrivateData->XipLoadFile);\r
798 } else {\r
799 //\r
54ea99a7 800 // 2nd time we are running from memory so replace the XIP version with the\r
801 // new memory version.\r
b0d803fe 802 //\r
54ea99a7 803 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);\r
b0d803fe 804 }\r
805}\r
806\r
807\r
808\r
341a658f 809\r