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