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