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