• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Pei Core Load Image Support
3 
4 Copyright (c) 2006 - 2016, 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 array to figure out if the memory range the image will be loaded in is available or not. If
143   memory range is available, the function will mark the corresponding 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 address 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 loading 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 loading 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               FixLoadingAddress;
232    UINT16                             Index;
233    UINTN                              Size;
234    UINT16                             NumberOfSections;
235    UINT64                             ValueInSectionHeader;
236 
237 
238    FixLoadingAddress = 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 loading 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 fields 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 running in memory
300            //
301            FixLoadingAddress = 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            FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(Private->LoadModuleAtFixAddressTopAddress + (INT64)ValueInSectionHeader);
308          }
309          //
310          // Check if the memory range is available.
311          //
312          Status = CheckAndMarkFixLoadingMemoryUsageBitMap (Private, FixLoadingAddress, (UINT32) ImageContext->ImageSize);
313          if (!EFI_ERROR(Status)) {
314            //
315            // The assigned address is valid. Return the specified loading address
316            //
317            ImageContext->ImageAddress = FixLoadingAddress;
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)FixLoadingAddress, 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                               IsPeiModule;
362   BOOLEAN                               IsRegisterForShadow;
363   EFI_FV_FILE_INFO                      FileInfo;
364 
365   Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
366 
367   ReturnStatus = EFI_SUCCESS;
368   IsXipImage   = FALSE;
369   ZeroMem (&ImageContext, sizeof (ImageContext));
370   ImageContext.Handle = Pe32Data;
371   Status              = GetImageReadFunction (&ImageContext);
372 
373   ASSERT_EFI_ERROR (Status);
374 
375   Status = PeCoffLoaderGetImageInfo (&ImageContext);
376   if (EFI_ERROR (Status)) {
377     return Status;
378   }
379 
380   //
381   // Initilize local IsS3Boot and IsRegisterForShadow variable
382   //
383   IsS3Boot = FALSE;
384   if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) {
385     IsS3Boot = TRUE;
386   }
387   IsRegisterForShadow = FALSE;
388   if ((Private->CurrentFileHandle == FileHandle)
389     && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW)) {
390     IsRegisterForShadow = TRUE;
391   }
392 
393   //
394   // XIP image that ImageAddress is same to Image handle.
395   //
396   if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
397     IsXipImage = TRUE;
398   }
399 
400   //
401   // Get file type first
402   //
403   Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo);
404   ASSERT_EFI_ERROR (Status);
405 
406   //
407   // Check whether the file type is PEI module.
408   //
409   IsPeiModule = FALSE;
410   if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE ||
411       FileInfo.FileType == EFI_FV_FILETYPE_PEIM ||
412       FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) {
413     IsPeiModule = TRUE;
414   }
415 
416   //
417   // When Image has no reloc section, it can't be relocated into memory.
418   //
419   if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
420       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
421     DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
422   }
423 
424   //
425   // Set default base address to current image address.
426   //
427   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
428 
429   //
430   // Allocate Memory for the image when memory is ready, and image is relocatable.
431   // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory.
432   // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory.
433   //
434   if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) ||
435       (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) {
436     //
437     // Allocate more buffer to avoid buffer overflow.
438     //
439     if (ImageContext.IsTeImage) {
440       AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
441     } else {
442       AlignImageSize = ImageContext.ImageSize;
443     }
444 
445     if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
446       AlignImageSize += ImageContext.SectionAlignment;
447     }
448 
449     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
450       Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private);
451       if (EFI_ERROR (Status)){
452         DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
453         //
454         // The PEIM is not assiged valid address, try to allocate page to load it.
455         //
456         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
457       }
458     } else {
459       ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize));
460     }
461     if (ImageContext.ImageAddress != 0) {
462       //
463       // Adjust the Image Address to make sure it is section alignment.
464       //
465       if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
466         ImageContext.ImageAddress =
467             (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) &
468             ~((UINTN)ImageContext.SectionAlignment - 1);
469       }
470       //
471       // Fix alignment requirement when Load IPF TeImage into memory.
472       // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
473       //
474       if (ImageContext.IsTeImage) {
475         ImageContext.ImageAddress = ImageContext.ImageAddress +
476                                     ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
477                                     sizeof (EFI_TE_IMAGE_HEADER);
478       }
479     } else {
480       //
481       // No enough memory resource.
482       //
483       if (IsXipImage) {
484         //
485         // XIP image can still be invoked.
486         //
487         ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
488         ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL;
489       } else {
490         //
491         // Non XIP image can't be loaded because no enough memory is allocated.
492         //
493         ASSERT (FALSE);
494         return EFI_OUT_OF_RESOURCES;
495       }
496     }
497   }
498 
499   //
500   // Load the image to our new buffer
501   //
502   Status = PeCoffLoaderLoadImage (&ImageContext);
503   if (EFI_ERROR (Status)) {
504     return Status;
505   }
506   //
507   // Relocate the image in our new buffer
508   //
509   Status = PeCoffLoaderRelocateImage (&ImageContext);
510   if (EFI_ERROR (Status)) {
511     return Status;
512   }
513 
514   //
515   // Flush the instruction cache so the image data is written before we execute it
516   //
517   if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) {
518     InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
519   }
520 
521   *ImageAddress = ImageContext.ImageAddress;
522   *ImageSize    = ImageContext.ImageSize;
523   *EntryPoint   = ImageContext.EntryPoint;
524 
525   return ReturnStatus;
526 }
527 
528 /**
529   Loads a PEIM into memory for subsequent execution. If there are compressed
530   images or images that need to be relocated into memory for performance reasons,
531   this service performs that transformation.
532 
533   @param PeiServices      An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
534   @param FileHandle       Pointer to the FFS file header of the image.
535   @param ImageAddressArg  Pointer to PE/TE image.
536   @param ImageSizeArg     Size of PE/TE image.
537   @param EntryPoint       Pointer to entry point of specified image file for output.
538   @param AuthenticationState - Pointer to attestation authentication state of image.
539 
540   @retval EFI_SUCCESS      Image is successfully loaded.
541   @retval EFI_NOT_FOUND    Fail to locate necessary PPI.
542   @retval EFI_UNSUPPORTED  Image Machine Type is not supported.
543   @retval EFI_WARN_BUFFER_TOO_SMALL
544                            There is not enough heap to allocate the requested size.
545                            This will not prevent the XIP image from being invoked.
546 
547 **/
548 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)549 PeiLoadImageLoadImage (
550   IN     CONST EFI_PEI_SERVICES       **PeiServices,
551   IN     EFI_PEI_FILE_HANDLE          FileHandle,
552   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
553   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
554   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
555   OUT    UINT32                       *AuthenticationState
556   )
557 {
558   EFI_STATUS                  Status;
559   VOID                        *Pe32Data;
560   EFI_PHYSICAL_ADDRESS        ImageAddress;
561   UINT64                      ImageSize;
562   EFI_PHYSICAL_ADDRESS        ImageEntryPoint;
563   UINT16                      Machine;
564   EFI_SECTION_TYPE            SearchType1;
565   EFI_SECTION_TYPE            SearchType2;
566 
567   *EntryPoint          = 0;
568   ImageSize            = 0;
569   *AuthenticationState = 0;
570 
571   if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
572     SearchType1 = EFI_SECTION_TE;
573     SearchType2 = EFI_SECTION_PE32;
574   } else {
575     SearchType1 = EFI_SECTION_PE32;
576     SearchType2 = EFI_SECTION_TE;
577   }
578 
579   //
580   // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
581   // is true, TE will be searched first).
582   //
583   Status = PeiServicesFfsFindSectionData3 (
584              SearchType1,
585              0,
586              FileHandle,
587              &Pe32Data,
588              AuthenticationState
589              );
590   //
591   // If we didn't find a first exe section, try to find the second exe section.
592   //
593   if (EFI_ERROR (Status)) {
594     Status = PeiServicesFfsFindSectionData3 (
595                SearchType2,
596                0,
597                FileHandle,
598                &Pe32Data,
599                AuthenticationState
600                );
601     if (EFI_ERROR (Status)) {
602       //
603       // PEI core only carry the loader function for TE and PE32 executables
604       // If this two section does not exist, just return.
605       //
606       return Status;
607     }
608   }
609 
610   //
611   // If memory is installed, perform the shadow operations
612   //
613   Status = LoadAndRelocatePeCoffImage (
614     FileHandle,
615     Pe32Data,
616     &ImageAddress,
617     &ImageSize,
618     &ImageEntryPoint
619   );
620 
621   ASSERT_EFI_ERROR (Status);
622 
623 
624   if (EFI_ERROR (Status)) {
625     return Status;
626   }
627 
628   //
629   // Got the entry point from the loaded Pe32Data
630   //
631   Pe32Data    = (VOID *) ((UINTN) ImageAddress);
632   *EntryPoint = ImageEntryPoint;
633 
634   Machine = PeCoffLoaderGetMachineType (Pe32Data);
635 
636   if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
637     if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
638       return EFI_UNSUPPORTED;
639     }
640   }
641 
642   if (ImageAddressArg != NULL) {
643     *ImageAddressArg = ImageAddress;
644   }
645 
646   if (ImageSizeArg != NULL) {
647     *ImageSizeArg = ImageSize;
648   }
649 
650   DEBUG_CODE_BEGIN ();
651     CHAR8                              *AsciiString;
652     CHAR8                              EfiFileName[512];
653     INT32                              Index;
654     INT32                              StartIndex;
655 
656     //
657     // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
658     //
659     if (Machine != EFI_IMAGE_MACHINE_IA64) {
660       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
661     } else {
662       //
663       // For IPF Image, the real entry point should be print.
664       //
665       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
666     }
667 
668     //
669     // Print Module Name by PeImage PDB file name.
670     //
671     AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
672 
673     if (AsciiString != NULL) {
674       StartIndex = 0;
675       for (Index = 0; AsciiString[Index] != 0; Index++) {
676         if (AsciiString[Index] == '\\' || AsciiString[Index] == '/') {
677           StartIndex = Index + 1;
678         }
679       }
680 
681       //
682       // Copy the PDB file name to our temporary string, and replace .pdb with .efi
683       // The PDB file name is limited in the range of 0~511.
684       // If the length is bigger than 511, trim the redudant characters to avoid overflow in array boundary.
685       //
686       for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
687         EfiFileName[Index] = AsciiString[Index + StartIndex];
688         if (EfiFileName[Index] == 0) {
689           EfiFileName[Index] = '.';
690         }
691         if (EfiFileName[Index] == '.') {
692           EfiFileName[Index + 1] = 'e';
693           EfiFileName[Index + 2] = 'f';
694           EfiFileName[Index + 3] = 'i';
695           EfiFileName[Index + 4] = 0;
696           break;
697         }
698       }
699 
700       if (Index == sizeof (EfiFileName) - 4) {
701         EfiFileName[Index] = 0;
702       }
703 
704       DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
705     }
706 
707   DEBUG_CODE_END ();
708 
709   DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
710 
711   return EFI_SUCCESS;
712 
713 }
714 
715 
716 /**
717   The wrapper function of PeiLoadImageLoadImage().
718 
719   @param This            - Pointer to EFI_PEI_LOAD_FILE_PPI.
720   @param FileHandle      - Pointer to the FFS file header of the image.
721   @param ImageAddressArg - Pointer to PE/TE image.
722   @param ImageSizeArg    - Size of PE/TE image.
723   @param EntryPoint      - Pointer to entry point of specified image file for output.
724   @param AuthenticationState - Pointer to attestation authentication state of image.
725 
726   @return Status of PeiLoadImageLoadImage().
727 
728 **/
729 EFI_STATUS
730 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)731 PeiLoadImageLoadImageWrapper (
732   IN     CONST EFI_PEI_LOAD_FILE_PPI  *This,
733   IN     EFI_PEI_FILE_HANDLE          FileHandle,
734   OUT    EFI_PHYSICAL_ADDRESS         *ImageAddressArg,  OPTIONAL
735   OUT    UINT64                       *ImageSizeArg,     OPTIONAL
736   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
737   OUT    UINT32                       *AuthenticationState
738   )
739 {
740   return PeiLoadImageLoadImage (
741            GetPeiServicesTablePointer (),
742            FileHandle,
743            ImageAddressArg,
744            ImageSizeArg,
745            EntryPoint,
746            AuthenticationState
747            );
748 }
749 
750 /**
751   Check whether the input image has the relocation.
752 
753   @param  Pe32Data   Pointer to the PE/COFF or TE image.
754 
755   @retval TRUE       Relocation is stripped.
756   @retval FALSE      Relocation is not stripped.
757 
758 **/
759 BOOLEAN
RelocationIsStrip(IN VOID * Pe32Data)760 RelocationIsStrip (
761   IN VOID  *Pe32Data
762   )
763 {
764   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
765   EFI_IMAGE_DOS_HEADER                 *DosHdr;
766 
767   ASSERT (Pe32Data != NULL);
768 
769   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
770   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
771     //
772     // DOS image header is present, so read the PE header after the DOS image header.
773     //
774     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
775   } else {
776     //
777     // DOS image header is not present, so PE header is at the image base.
778     //
779     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
780   }
781 
782   //
783   // Three cases with regards to relocations:
784   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
785   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
786   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
787   //   has no base relocs to apply
788   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
789   //
790   // Look at the file header to determine if relocations have been stripped, and
791   // save this info in the image context for later use.
792   //
793   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
794     if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
795       return TRUE;
796     } else {
797       return FALSE;
798     }
799   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
800     if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
801       return TRUE;
802     } else {
803       return FALSE;
804     }
805   }
806 
807   return FALSE;
808 }
809 
810 /**
811   Routine to load image file for subsequent execution by LoadFile Ppi.
812   If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
813   XIP image format is used.
814 
815   @param PeiServices     - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
816   @param FileHandle      - Pointer to the FFS file header of the image.
817   @param PeimState       - The dispatch state of the input PEIM handle.
818   @param EntryPoint      - Pointer to entry point of specified image file for output.
819   @param AuthenticationState - Pointer to attestation authentication state of image.
820 
821   @retval EFI_SUCCESS    - Image is successfully loaded.
822   @retval EFI_NOT_FOUND  - Fail to locate necessary PPI
823   @retval Others         - Fail to load file.
824 
825 **/
826 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)827 PeiLoadImage (
828   IN     CONST EFI_PEI_SERVICES       **PeiServices,
829   IN     EFI_PEI_FILE_HANDLE          FileHandle,
830   IN     UINT8                        PeimState,
831   OUT    EFI_PHYSICAL_ADDRESS         *EntryPoint,
832   OUT    UINT32                       *AuthenticationState
833   )
834 {
835   EFI_STATUS              PpiStatus;
836   EFI_STATUS              Status;
837   UINTN                   Index;
838   EFI_PEI_LOAD_FILE_PPI   *LoadFile;
839   EFI_PHYSICAL_ADDRESS    ImageAddress;
840   UINT64                  ImageSize;
841   BOOLEAN                 IsStrip;
842 
843   IsStrip = FALSE;
844   //
845   // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
846   // one at a time, until one reports EFI_SUCCESS.
847   //
848   Index = 0;
849   do {
850     PpiStatus = PeiServicesLocatePpi (
851                   &gEfiPeiLoadFilePpiGuid,
852                   Index,
853                   NULL,
854                   (VOID **)&LoadFile
855                   );
856     if (!EFI_ERROR (PpiStatus)) {
857       Status = LoadFile->LoadFile (
858                           LoadFile,
859                           FileHandle,
860                           &ImageAddress,
861                           &ImageSize,
862                           EntryPoint,
863                           AuthenticationState
864                           );
865       if (!EFI_ERROR (Status) || Status == EFI_WARN_BUFFER_TOO_SMALL) {
866         //
867         // The shadowed PEIM must be relocatable.
868         //
869         if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {
870           IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
871           ASSERT (!IsStrip);
872           if (IsStrip) {
873             return EFI_UNSUPPORTED;
874           }
875         }
876 
877         //
878         // The image to be started must have the machine type supported by PeiCore.
879         //
880         ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
881         if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
882           return EFI_UNSUPPORTED;
883         }
884         return EFI_SUCCESS;
885       }
886     }
887     Index++;
888   } while (!EFI_ERROR (PpiStatus));
889 
890   return PpiStatus;
891 }
892 
893 
894 /**
895 
896   Install Pei Load File PPI.
897 
898 
899   @param PrivateData     - Pointer to PEI_CORE_INSTANCE.
900   @param OldCoreData     - Pointer to PEI_CORE_INSTANCE.
901 
902 **/
903 VOID
InitializeImageServices(IN PEI_CORE_INSTANCE * PrivateData,IN PEI_CORE_INSTANCE * OldCoreData)904 InitializeImageServices (
905   IN  PEI_CORE_INSTANCE   *PrivateData,
906   IN  PEI_CORE_INSTANCE   *OldCoreData
907   )
908 {
909   if (OldCoreData == NULL) {
910     //
911     // The first time we are XIP (running from FLASH). We need to remember the
912     // FLASH address so we can reinstall the memory version that runs faster
913     //
914     PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
915     PeiServicesInstallPpi (PrivateData->XipLoadFile);
916   } else {
917     //
918     // 2nd time we are running from memory so replace the XIP version with the
919     // new memory version.
920     //
921     PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
922   }
923 }
924 
925 
926 
927 
928