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