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