1 /** @file
2   Core image handling services to load and unload PeImage.
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "DxeMain.h"
10 #include "Image.h"
11 
12 //
13 // Module Globals
14 //
15 LOADED_IMAGE_PRIVATE_DATA  *mCurrentImage = NULL;
16 
17 typedef struct {
18   LIST_ENTRY                            Link;
19   EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL  *Emulator;
20   UINT16                                MachineType;
21 } EMULATOR_ENTRY;
22 
23 STATIC LIST_ENTRY                       mAvailableEmulators;
24 STATIC EFI_EVENT                        mPeCoffEmuProtocolRegistrationEvent;
25 STATIC VOID                             *mPeCoffEmuProtocolNotifyRegistration;
26 
27 //
28 // This code is needed to build the Image handle for the DXE Core
29 //
30 LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage  = {
31   LOADED_IMAGE_PRIVATE_DATA_SIGNATURE,            // Signature
32   NULL,                                           // Image handle
33   EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,    // Image type
34   TRUE,                                           // If entrypoint has been called
35   NULL, // EntryPoint
36   {
37     EFI_LOADED_IMAGE_INFORMATION_REVISION,        // Revision
38     NULL,                                         // Parent handle
39     NULL,                                         // System handle
40 
41     NULL,                                         // Device handle
42     NULL,                                         // File path
43     NULL,                                         // Reserved
44 
45     0,                                            // LoadOptionsSize
46     NULL,                                         // LoadOptions
47 
48     NULL,                                         // ImageBase
49     0,                                            // ImageSize
50     EfiBootServicesCode,                          // ImageCodeType
51     EfiBootServicesData                           // ImageDataType
52   },
53   (EFI_PHYSICAL_ADDRESS)0,    // ImageBasePage
54   0,                          // NumberOfPages
55   NULL,                       // FixupData
56   0,                          // Tpl
57   EFI_SUCCESS,                // Status
58   0,                          // ExitDataSize
59   NULL,                       // ExitData
60   NULL,                       // JumpBuffer
61   NULL,                       // JumpContext
62   0,                          // Machine
63   NULL,                       // PeCoffEmu
64   NULL,                       // RuntimeData
65   NULL                        // LoadedImageDevicePath
66 };
67 //
68 // The field is define for Loading modules at fixed address feature to tracker the PEI code
69 // memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
70 // available or not.
71 //
72 GLOBAL_REMOVE_IF_UNREFERENCED    UINT64                *mDxeCodeMemoryRangeUsageBitMap=NULL;
73 
74 typedef struct {
75   UINT16  MachineType;
76   CHAR16  *MachineTypeName;
77 } MACHINE_TYPE_INFO;
78 
79 GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO  mMachineTypeInfo[] = {
80   {EFI_IMAGE_MACHINE_IA32,           L"IA32"},
81   {EFI_IMAGE_MACHINE_IA64,           L"IA64"},
82   {EFI_IMAGE_MACHINE_X64,            L"X64"},
83   {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"},
84   {EFI_IMAGE_MACHINE_AARCH64,        L"AARCH64"}
85 };
86 
87 UINT16 mDxeCoreImageMachineType = 0;
88 
89 /**
90  Return machine type name.
91 
92  @param MachineType The machine type
93 
94  @return machine type name
95 **/
96 CHAR16 *
GetMachineTypeName(UINT16 MachineType)97 GetMachineTypeName (
98   UINT16 MachineType
99   )
100 {
101   UINTN  Index;
102 
103   for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {
104     if (mMachineTypeInfo[Index].MachineType == MachineType) {
105       return mMachineTypeInfo[Index].MachineTypeName;
106     }
107   }
108 
109   return L"<Unknown>";
110 }
111 
112 /**
113   Notification event handler registered by CoreInitializeImageServices () to
114   keep track of which PE/COFF image emulators are available.
115 
116   @param  Event          The Event that is being processed, not used.
117   @param  Context        Event Context, not used.
118 
119 **/
120 STATIC
121 VOID
122 EFIAPI
PeCoffEmuProtocolNotify(IN EFI_EVENT Event,IN VOID * Context)123 PeCoffEmuProtocolNotify (
124   IN  EFI_EVENT       Event,
125   IN  VOID            *Context
126   )
127 {
128   EFI_STATUS                            Status;
129   UINTN                                 BufferSize;
130   EFI_HANDLE                            EmuHandle;
131   EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL  *Emulator;
132   EMULATOR_ENTRY                        *Entry;
133 
134   EmuHandle = NULL;
135   Emulator  = NULL;
136 
137   while (TRUE) {
138     BufferSize = sizeof (EmuHandle);
139     Status = CoreLocateHandle (
140                ByRegisterNotify,
141                NULL,
142                mPeCoffEmuProtocolNotifyRegistration,
143                &BufferSize,
144                &EmuHandle
145                );
146     if (EFI_ERROR (Status)) {
147       //
148       // If no more notification events exit
149       //
150       return;
151     }
152 
153     Status = CoreHandleProtocol (
154                EmuHandle,
155                &gEdkiiPeCoffImageEmulatorProtocolGuid,
156                (VOID **)&Emulator
157                );
158     if (EFI_ERROR (Status) || Emulator == NULL) {
159       continue;
160     }
161 
162     Entry = AllocateZeroPool (sizeof (*Entry));
163     ASSERT (Entry != NULL);
164 
165     Entry->Emulator    = Emulator;
166     Entry->MachineType = Entry->Emulator->MachineType;
167 
168     InsertTailList (&mAvailableEmulators, &Entry->Link);
169   }
170 }
171 
172 /**
173   Add the Image Services to EFI Boot Services Table and install the protocol
174   interfaces for this image.
175 
176   @param  HobStart                The HOB to initialize
177 
178   @return Status code.
179 
180 **/
181 EFI_STATUS
CoreInitializeImageServices(IN VOID * HobStart)182 CoreInitializeImageServices (
183   IN  VOID *HobStart
184   )
185 {
186   EFI_STATUS                        Status;
187   LOADED_IMAGE_PRIVATE_DATA         *Image;
188   EFI_PHYSICAL_ADDRESS              DxeCoreImageBaseAddress;
189   UINT64                            DxeCoreImageLength;
190   VOID                              *DxeCoreEntryPoint;
191   EFI_PEI_HOB_POINTERS              DxeCoreHob;
192 
193   //
194   // Searching for image hob
195   //
196   DxeCoreHob.Raw          = HobStart;
197   while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
198     if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
199       //
200       // Find Dxe Core HOB
201       //
202       break;
203     }
204     DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
205   }
206   ASSERT (DxeCoreHob.Raw != NULL);
207 
208   DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
209   DxeCoreImageLength      = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
210   DxeCoreEntryPoint       = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;
211   gDxeCoreFileName        = &DxeCoreHob.MemoryAllocationModule->ModuleName;
212 
213   //
214   // Initialize the fields for an internal driver
215   //
216   Image = &mCorePrivateImage;
217 
218   Image->EntryPoint         = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
219   Image->ImageBasePage      = DxeCoreImageBaseAddress;
220   Image->NumberOfPages      = (UINTN)(EFI_SIZE_TO_PAGES((UINTN)(DxeCoreImageLength)));
221   Image->Tpl                = gEfiCurrentTpl;
222   Image->Info.SystemTable   = gDxeCoreST;
223   Image->Info.ImageBase     = (VOID *)(UINTN)DxeCoreImageBaseAddress;
224   Image->Info.ImageSize     = DxeCoreImageLength;
225 
226   //
227   // Install the protocol interfaces for this image
228   //
229   Status = CoreInstallProtocolInterface (
230              &Image->Handle,
231              &gEfiLoadedImageProtocolGuid,
232              EFI_NATIVE_INTERFACE,
233              &Image->Info
234              );
235   ASSERT_EFI_ERROR (Status);
236 
237   mCurrentImage = Image;
238 
239   //
240   // Fill in DXE globals
241   //
242   mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
243   gDxeCoreImageHandle = Image->Handle;
244   gDxeCoreLoadedImage = &Image->Info;
245 
246   //
247   // Create the PE/COFF emulator protocol registration event
248   //
249   Status = CoreCreateEvent (
250              EVT_NOTIFY_SIGNAL,
251              TPL_CALLBACK,
252              PeCoffEmuProtocolNotify,
253              NULL,
254              &mPeCoffEmuProtocolRegistrationEvent
255              );
256   ASSERT_EFI_ERROR(Status);
257 
258   //
259   // Register for protocol notifications on this event
260   //
261   Status = CoreRegisterProtocolNotify (
262              &gEdkiiPeCoffImageEmulatorProtocolGuid,
263              mPeCoffEmuProtocolRegistrationEvent,
264              &mPeCoffEmuProtocolNotifyRegistration
265              );
266   ASSERT_EFI_ERROR(Status);
267 
268   InitializeListHead (&mAvailableEmulators);
269 
270   ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
271 
272   return Status;
273 }
274 
275 /**
276   Read image file (specified by UserHandle) into user specified buffer with specified offset
277   and length.
278 
279   @param  UserHandle             Image file handle
280   @param  Offset                 Offset to the source file
281   @param  ReadSize               For input, pointer of size to read; For output,
282                                  pointer of size actually read.
283   @param  Buffer                 Buffer to write into
284 
285   @retval EFI_SUCCESS            Successfully read the specified part of file
286                                  into buffer.
287 
288 **/
289 EFI_STATUS
290 EFIAPI
CoreReadImageFile(IN VOID * UserHandle,IN UINTN Offset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)291 CoreReadImageFile (
292   IN     VOID    *UserHandle,
293   IN     UINTN   Offset,
294   IN OUT UINTN   *ReadSize,
295   OUT    VOID    *Buffer
296   )
297 {
298   UINTN               EndPosition;
299   IMAGE_FILE_HANDLE  *FHand;
300 
301   if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {
302     return EFI_INVALID_PARAMETER;
303   }
304 
305   if (MAX_ADDRESS - Offset < *ReadSize) {
306     return EFI_INVALID_PARAMETER;
307   }
308 
309   FHand = (IMAGE_FILE_HANDLE  *)UserHandle;
310   ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
311 
312   //
313   // Move data from our local copy of the file
314   //
315   EndPosition = Offset + *ReadSize;
316   if (EndPosition > FHand->SourceSize) {
317     *ReadSize = (UINT32)(FHand->SourceSize - Offset);
318   }
319   if (Offset >= FHand->SourceSize) {
320       *ReadSize = 0;
321   }
322 
323   CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
324   return EFI_SUCCESS;
325 }
326 /**
327   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
328   memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
329   The function is only invoked when load modules at fixed address feature is enabled.
330 
331   @param  ImageBase                The base address the image will be loaded at.
332   @param  ImageSize                The size of the image
333 
334   @retval EFI_SUCCESS              The memory range the image will be loaded in is available
335   @retval EFI_NOT_FOUND            The memory range the image will be loaded in is not available
336 **/
337 EFI_STATUS
CheckAndMarkFixLoadingMemoryUsageBitMap(IN EFI_PHYSICAL_ADDRESS ImageBase,IN UINTN ImageSize)338 CheckAndMarkFixLoadingMemoryUsageBitMap (
339   IN  EFI_PHYSICAL_ADDRESS          ImageBase,
340   IN  UINTN                         ImageSize
341   )
342 {
343    UINT32                             DxeCodePageNumber;
344    UINT64                             DxeCodeSize;
345    EFI_PHYSICAL_ADDRESS               DxeCodeBase;
346    UINTN                              BaseOffsetPageNumber;
347    UINTN                              TopOffsetPageNumber;
348    UINTN                              Index;
349    //
350    // The DXE code range includes RuntimeCodePage range and Boot time code range.
351    //
352    DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);
353    DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);
354    DxeCodeSize       = EFI_PAGES_TO_SIZE(DxeCodePageNumber);
355    DxeCodeBase       =  gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
356 
357    //
358    // If the memory usage bit map is not initialized,  do it. Every bit in the array
359    // indicate the status of the corresponding memory page, available or not
360    //
361    if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
362      mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));
363    }
364    //
365    // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
366    //
367    if (!gLoadFixedAddressCodeMemoryReady || mDxeCodeMemoryRangeUsageBitMap == NULL) {
368      return EFI_NOT_FOUND;
369    }
370    //
371    // Test the memory range for loading the image in the DXE code range.
372    //
373    if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress <  ImageBase + ImageSize ||
374        DxeCodeBase >  ImageBase) {
375      return EFI_NOT_FOUND;
376    }
377    //
378    // Test if the memory is avalaible or not.
379    //
380    BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));
381    TopOffsetPageNumber  = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));
382    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
383      if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
384        //
385        // This page is already used.
386        //
387        return EFI_NOT_FOUND;
388      }
389    }
390 
391    //
392    // Being here means the memory range is available.  So mark the bits for the memory range
393    //
394    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
395      mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
396    }
397    return  EFI_SUCCESS;
398 }
399 /**
400 
401   Get the fixed loading address from image header assigned by build tool. This function only be called
402   when Loading module at Fixed address feature enabled.
403 
404   @param  ImageContext              Pointer to the image context structure that describes the PE/COFF
405                                     image that needs to be examined by this function.
406   @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .
407   @retval EFI_NOT_FOUND             The image has no assigned fixed loading address.
408 
409 **/
410 EFI_STATUS
GetPeCoffImageFixLoadingAssignedAddress(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)411 GetPeCoffImageFixLoadingAssignedAddress(
412   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
413   )
414 {
415    UINTN                              SectionHeaderOffset;
416    EFI_STATUS                         Status;
417    EFI_IMAGE_SECTION_HEADER           SectionHeader;
418    EFI_IMAGE_OPTIONAL_HEADER_UNION    *ImgHdr;
419    UINT16                             Index;
420    UINTN                              Size;
421    UINT16                             NumberOfSections;
422    IMAGE_FILE_HANDLE                  *Handle;
423    UINT64                             ValueInSectionHeader;
424 
425 
426    Status = EFI_NOT_FOUND;
427 
428    //
429    // Get PeHeader pointer
430    //
431    Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;
432    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);
433    SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
434                          sizeof (UINT32) +
435                          sizeof (EFI_IMAGE_FILE_HEADER) +
436                          ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
437    NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
438 
439    //
440    // Get base address from the first section header that doesn't point to code section.
441    //
442    for (Index = 0; Index < NumberOfSections; Index++) {
443      //
444      // Read section header from file
445      //
446      Size = sizeof (EFI_IMAGE_SECTION_HEADER);
447      Status = ImageContext->ImageRead (
448                               ImageContext->Handle,
449                               SectionHeaderOffset,
450                               &Size,
451                               &SectionHeader
452                               );
453      if (EFI_ERROR (Status)) {
454        return Status;
455      }
456      if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
457        return EFI_NOT_FOUND;
458      }
459 
460      Status = EFI_NOT_FOUND;
461 
462      if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
463        //
464        // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
465        // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
466        // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
467        // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
468        //
469        ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
470        if (ValueInSectionHeader != 0) {
471          //
472          // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
473          // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
474          // relative to top address
475          //
476          if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {
477             ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
478          }
479          //
480          // Check if the memory range is available.
481          //
482          Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
483        }
484        break;
485      }
486      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
487    }
488    DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
489    return Status;
490 }
491 
492 /**
493   Decides whether a PE/COFF image can execute on this system, either natively
494   or via emulation/interpretation. In the latter case, the PeCoffEmu member
495   of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
496   to the emulator protocol that supports this image.
497 
498   @param[in, out]   Image         LOADED_IMAGE_PRIVATE_DATA struct pointer
499 
500   @retval           TRUE          The image is supported
501   @retval           FALSE         The image is not supported
502 
503 **/
504 STATIC
505 BOOLEAN
CoreIsImageTypeSupported(IN OUT LOADED_IMAGE_PRIVATE_DATA * Image)506 CoreIsImageTypeSupported (
507   IN OUT LOADED_IMAGE_PRIVATE_DATA  *Image
508   )
509 {
510   LIST_ENTRY                        *Link;
511   EMULATOR_ENTRY                    *Entry;
512 
513   for (Link = GetFirstNode (&mAvailableEmulators);
514        !IsNull (&mAvailableEmulators, Link);
515        Link = GetNextNode (&mAvailableEmulators, Link)) {
516 
517     Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
518     if (Entry->MachineType != Image->ImageContext.Machine) {
519       continue;
520     }
521 
522     if (Entry->Emulator->IsImageSupported (Entry->Emulator,
523                            Image->ImageContext.ImageType,
524                            Image->Info.FilePath)) {
525       Image->PeCoffEmu = Entry->Emulator;
526       return TRUE;
527     }
528   }
529 
530   return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
531          EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
532 }
533 
534 /**
535   Loads, relocates, and invokes a PE/COFF image
536 
537   @param  BootPolicy              If TRUE, indicates that the request originates
538                                   from the boot manager, and that the boot
539                                   manager is attempting to load FilePath as a
540                                   boot selection.
541   @param  Pe32Handle              The handle of PE32 image
542   @param  Image                   PE image to be loaded
543   @param  DstBuffer               The buffer to store the image
544   @param  EntryPoint              A pointer to the entry point
545   @param  Attribute               The bit mask of attributes to set for the load
546                                   PE image
547 
548   @retval EFI_SUCCESS             The file was loaded, relocated, and invoked
549   @retval EFI_OUT_OF_RESOURCES    There was not enough memory to load and
550                                   relocate the PE/COFF file
551   @retval EFI_INVALID_PARAMETER   Invalid parameter
552   @retval EFI_BUFFER_TOO_SMALL    Buffer for image is too small
553 
554 **/
555 EFI_STATUS
CoreLoadPeImage(IN BOOLEAN BootPolicy,IN VOID * Pe32Handle,IN LOADED_IMAGE_PRIVATE_DATA * Image,IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,OUT EFI_PHYSICAL_ADDRESS * EntryPoint OPTIONAL,IN UINT32 Attribute)556 CoreLoadPeImage (
557   IN BOOLEAN                     BootPolicy,
558   IN VOID                        *Pe32Handle,
559   IN LOADED_IMAGE_PRIVATE_DATA   *Image,
560   IN EFI_PHYSICAL_ADDRESS        DstBuffer    OPTIONAL,
561   OUT EFI_PHYSICAL_ADDRESS       *EntryPoint  OPTIONAL,
562   IN  UINT32                     Attribute
563   )
564 {
565   EFI_STATUS                Status;
566   BOOLEAN                   DstBufAlocated;
567   UINTN                     Size;
568 
569   ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
570 
571   Image->ImageContext.Handle    = Pe32Handle;
572   Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
573 
574   //
575   // Get information about the image being loaded
576   //
577   Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
578   if (EFI_ERROR (Status)) {
579     return Status;
580   }
581 
582   if (!CoreIsImageTypeSupported (Image)) {
583     //
584     // The PE/COFF loader can support loading image types that can be executed.
585     // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
586     //
587     DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",
588       GetMachineTypeName (Image->ImageContext.Machine),
589       GetMachineTypeName (mDxeCoreImageMachineType)));
590     return EFI_UNSUPPORTED;
591   }
592 
593   //
594   // Set EFI memory type based on ImageType
595   //
596   switch (Image->ImageContext.ImageType) {
597   case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
598     Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
599     Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
600     break;
601   case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
602     Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
603     Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
604     break;
605   case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
606   case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
607     Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
608     Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
609     break;
610   default:
611     Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
612     return EFI_UNSUPPORTED;
613   }
614 
615   //
616   // Allocate memory of the correct memory type aligned on the required image boundary
617   //
618   DstBufAlocated = FALSE;
619   if (DstBuffer == 0) {
620     //
621     // Allocate Destination Buffer as caller did not pass it in
622     //
623 
624     if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
625       Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
626     } else {
627       Size = (UINTN)Image->ImageContext.ImageSize;
628     }
629 
630     Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
631 
632     //
633     // If the image relocations have not been stripped, then load at any address.
634     // Otherwise load at the address at which it was linked.
635     //
636     // Memory below 1MB should be treated reserved for CSM and there should be
637     // no modules whose preferred load addresses are below 1MB.
638     //
639     Status = EFI_OUT_OF_RESOURCES;
640     //
641     // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
642     // a specified address.
643     //
644     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 ) {
645       Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
646 
647       if (EFI_ERROR (Status))  {
648           //
649           // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
650           //
651           DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
652 
653           Status = CoreAllocatePages (
654                      AllocateAnyPages,
655                      (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
656                      Image->NumberOfPages,
657                      &Image->ImageContext.ImageAddress
658                      );
659       }
660     } else {
661       if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {
662         Status = CoreAllocatePages (
663                    AllocateAddress,
664                    (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
665                    Image->NumberOfPages,
666                    &Image->ImageContext.ImageAddress
667                    );
668       }
669       if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
670         Status = CoreAllocatePages (
671                    AllocateAnyPages,
672                    (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),
673                    Image->NumberOfPages,
674                    &Image->ImageContext.ImageAddress
675                    );
676       }
677     }
678     if (EFI_ERROR (Status)) {
679       return Status;
680     }
681     DstBufAlocated = TRUE;
682   } else {
683     //
684     // Caller provided the destination buffer
685     //
686 
687     if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
688       //
689       // If the image relocations were stripped, and the caller provided a
690       // destination buffer address that does not match the address that the
691       // image is linked at, then the image cannot be loaded.
692       //
693       return EFI_INVALID_PARAMETER;
694     }
695 
696     if (Image->NumberOfPages != 0 &&
697         Image->NumberOfPages <
698         (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))) {
699       Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
700       return EFI_BUFFER_TOO_SMALL;
701     }
702 
703     Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
704     Image->ImageContext.ImageAddress = DstBuffer;
705   }
706 
707   Image->ImageBasePage = Image->ImageContext.ImageAddress;
708   if (!Image->ImageContext.IsTeImage) {
709     Image->ImageContext.ImageAddress =
710         (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
711         ~((UINTN)Image->ImageContext.SectionAlignment - 1);
712   }
713 
714   //
715   // Load the image from the file into the allocated memory
716   //
717   Status = PeCoffLoaderLoadImage (&Image->ImageContext);
718   if (EFI_ERROR (Status)) {
719     goto Done;
720   }
721 
722   //
723   // If this is a Runtime Driver, then allocate memory for the FixupData that
724   // is used to relocate the image when SetVirtualAddressMap() is called. The
725   // relocation is done by the Runtime AP.
726   //
727   if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
728     if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
729       Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
730       if (Image->ImageContext.FixupData == NULL) {
731         Status = EFI_OUT_OF_RESOURCES;
732         goto Done;
733       }
734     }
735   }
736 
737   //
738   // Relocate the image in memory
739   //
740   Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
741   if (EFI_ERROR (Status)) {
742     goto Done;
743   }
744 
745   //
746   // Flush the Instruction Cache
747   //
748   InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
749 
750   //
751   // Copy the machine type from the context to the image private data.
752   //
753   Image->Machine = Image->ImageContext.Machine;
754 
755   //
756   // Get the image entry point.
757   //
758   Image->EntryPoint   = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
759 
760   //
761   // Fill in the image information for the Loaded Image Protocol
762   //
763   Image->Type               = Image->ImageContext.ImageType;
764   Image->Info.ImageBase     = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
765   Image->Info.ImageSize     = Image->ImageContext.ImageSize;
766   Image->Info.ImageCodeType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType);
767   Image->Info.ImageDataType = (EFI_MEMORY_TYPE) (Image->ImageContext.ImageDataMemoryType);
768   if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
769     if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
770       //
771       // Make a list off all the RT images so we can let the RT AP know about them.
772       //
773       Image->RuntimeData = AllocateRuntimePool (sizeof(EFI_RUNTIME_IMAGE_ENTRY));
774       if (Image->RuntimeData == NULL) {
775         goto Done;
776       }
777       Image->RuntimeData->ImageBase      = Image->Info.ImageBase;
778       Image->RuntimeData->ImageSize      = (UINT64) (Image->Info.ImageSize);
779       Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
780       Image->RuntimeData->Handle         = Image->Handle;
781       InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
782       InsertImageRecord (Image->RuntimeData);
783     }
784   }
785 
786   //
787   // Fill in the entry point of the image if it is available
788   //
789   if (EntryPoint != NULL) {
790     *EntryPoint = Image->ImageContext.EntryPoint;
791   }
792 
793   //
794   // Print the load address and the PDB file name if it is available
795   //
796 
797   DEBUG_CODE_BEGIN ();
798 
799     UINTN Index;
800     UINTN StartIndex;
801     CHAR8 EfiFileName[256];
802 
803 
804     DEBUG ((DEBUG_INFO | DEBUG_LOAD,
805            "Loading driver at 0x%11p EntryPoint=0x%11p ",
806            (VOID *)(UINTN) Image->ImageContext.ImageAddress,
807            FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)));
808 
809 
810     //
811     // Print Module Name by Pdb file path.
812     // Windows and Unix style file path are all trimmed correctly.
813     //
814     if (Image->ImageContext.PdbPointer != NULL) {
815       StartIndex = 0;
816       for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
817         if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->ImageContext.PdbPointer[Index] == '/')) {
818           StartIndex = Index + 1;
819         }
820       }
821       //
822       // Copy the PDB file name to our temporary string, and replace .pdb with .efi
823       // The PDB file name is limited in the range of 0~255.
824       // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
825       //
826       for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
827         EfiFileName[Index] = Image->ImageContext.PdbPointer[Index + StartIndex];
828         if (EfiFileName[Index] == 0) {
829           EfiFileName[Index] = '.';
830         }
831         if (EfiFileName[Index] == '.') {
832           EfiFileName[Index + 1] = 'e';
833           EfiFileName[Index + 2] = 'f';
834           EfiFileName[Index + 3] = 'i';
835           EfiFileName[Index + 4] = 0;
836           break;
837         }
838       }
839 
840       if (Index == sizeof (EfiFileName) - 4) {
841         EfiFileName[Index] = 0;
842       }
843       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
844     }
845     DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
846 
847   DEBUG_CODE_END ();
848 
849   return EFI_SUCCESS;
850 
851 Done:
852 
853   //
854   // Free memory.
855   //
856 
857   if (DstBufAlocated) {
858     CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
859     Image->ImageContext.ImageAddress = 0;
860     Image->ImageBasePage = 0;
861   }
862 
863   if (Image->ImageContext.FixupData != NULL) {
864     CoreFreePool (Image->ImageContext.FixupData);
865   }
866 
867   return Status;
868 }
869 
870 
871 
872 /**
873   Get the image's private data from its handle.
874 
875   @param  ImageHandle             The image handle
876 
877   @return Return the image private data associated with ImageHandle.
878 
879 **/
880 LOADED_IMAGE_PRIVATE_DATA *
CoreLoadedImageInfo(IN EFI_HANDLE ImageHandle)881 CoreLoadedImageInfo (
882   IN EFI_HANDLE  ImageHandle
883   )
884 {
885   EFI_STATUS                 Status;
886   EFI_LOADED_IMAGE_PROTOCOL  *LoadedImage;
887   LOADED_IMAGE_PRIVATE_DATA  *Image;
888 
889   Status = CoreHandleProtocol (
890              ImageHandle,
891              &gEfiLoadedImageProtocolGuid,
892              (VOID **)&LoadedImage
893              );
894   if (!EFI_ERROR (Status)) {
895     Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
896   } else {
897     DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
898     Image = NULL;
899   }
900 
901   return Image;
902 }
903 
904 
905 /**
906   Unloads EFI image from memory.
907 
908   @param  Image                   EFI image
909   @param  FreePage                Free allocated pages
910 
911 **/
912 VOID
CoreUnloadAndCloseImage(IN LOADED_IMAGE_PRIVATE_DATA * Image,IN BOOLEAN FreePage)913 CoreUnloadAndCloseImage (
914   IN LOADED_IMAGE_PRIVATE_DATA  *Image,
915   IN BOOLEAN                    FreePage
916   )
917 {
918   EFI_STATUS                          Status;
919   UINTN                               HandleCount;
920   EFI_HANDLE                          *HandleBuffer;
921   UINTN                               HandleIndex;
922   EFI_GUID                            **ProtocolGuidArray;
923   UINTN                               ArrayCount;
924   UINTN                               ProtocolIndex;
925   EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
926   UINTN                               OpenInfoCount;
927   UINTN                               OpenInfoIndex;
928 
929   HandleBuffer = NULL;
930   ProtocolGuidArray = NULL;
931 
932   if (Image->Started) {
933     UnregisterMemoryProfileImage (Image);
934   }
935 
936   UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
937 
938   if (Image->PeCoffEmu != NULL) {
939     //
940     // If the PE/COFF Emulator protocol exists we must unregister the image.
941     //
942     Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
943   }
944 
945   //
946   // Unload image, free Image->ImageContext->ModHandle
947   //
948   PeCoffLoaderUnloadImage (&Image->ImageContext);
949 
950   //
951   // Free our references to the image handle
952   //
953   if (Image->Handle != NULL) {
954 
955     Status = CoreLocateHandleBuffer (
956                AllHandles,
957                NULL,
958                NULL,
959                &HandleCount,
960                &HandleBuffer
961                );
962     if (!EFI_ERROR (Status)) {
963       for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
964         Status = CoreProtocolsPerHandle (
965                    HandleBuffer[HandleIndex],
966                    &ProtocolGuidArray,
967                    &ArrayCount
968                    );
969         if (!EFI_ERROR (Status)) {
970           for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
971             Status = CoreOpenProtocolInformation (
972                        HandleBuffer[HandleIndex],
973                        ProtocolGuidArray[ProtocolIndex],
974                        &OpenInfo,
975                        &OpenInfoCount
976                        );
977             if (!EFI_ERROR (Status)) {
978               for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
979                 if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
980                   Status = CoreCloseProtocol (
981                              HandleBuffer[HandleIndex],
982                              ProtocolGuidArray[ProtocolIndex],
983                              Image->Handle,
984                              OpenInfo[OpenInfoIndex].ControllerHandle
985                              );
986                 }
987               }
988               if (OpenInfo != NULL) {
989                 CoreFreePool(OpenInfo);
990               }
991             }
992           }
993           if (ProtocolGuidArray != NULL) {
994             CoreFreePool(ProtocolGuidArray);
995           }
996         }
997       }
998       if (HandleBuffer != NULL) {
999         CoreFreePool (HandleBuffer);
1000       }
1001     }
1002 
1003     CoreRemoveDebugImageInfoEntry (Image->Handle);
1004 
1005     Status = CoreUninstallProtocolInterface (
1006                Image->Handle,
1007                &gEfiLoadedImageDevicePathProtocolGuid,
1008                Image->LoadedImageDevicePath
1009                );
1010 
1011     Status = CoreUninstallProtocolInterface (
1012                Image->Handle,
1013                &gEfiLoadedImageProtocolGuid,
1014                &Image->Info
1015                );
1016 
1017     if (Image->ImageContext.HiiResourceData != 0) {
1018       Status = CoreUninstallProtocolInterface (
1019                  Image->Handle,
1020                  &gEfiHiiPackageListProtocolGuid,
1021                  (VOID *) (UINTN) Image->ImageContext.HiiResourceData
1022                  );
1023     }
1024 
1025   }
1026 
1027   if (Image->RuntimeData != NULL) {
1028     if (Image->RuntimeData->Link.ForwardLink != NULL) {
1029       //
1030       // Remove the Image from the Runtime Image list as we are about to Free it!
1031       //
1032       RemoveEntryList (&Image->RuntimeData->Link);
1033       RemoveImageRecord (Image->RuntimeData);
1034     }
1035     CoreFreePool (Image->RuntimeData);
1036   }
1037 
1038   //
1039   // Free the Image from memory
1040   //
1041   if ((Image->ImageBasePage != 0) && FreePage) {
1042     CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
1043   }
1044 
1045   //
1046   // Done with the Image structure
1047   //
1048   if (Image->Info.FilePath != NULL) {
1049     CoreFreePool (Image->Info.FilePath);
1050   }
1051 
1052   if (Image->LoadedImageDevicePath != NULL) {
1053     CoreFreePool (Image->LoadedImageDevicePath);
1054   }
1055 
1056   if (Image->FixupData != NULL) {
1057     CoreFreePool (Image->FixupData);
1058   }
1059 
1060   CoreFreePool (Image);
1061 }
1062 
1063 
1064 /**
1065   Loads an EFI image into memory and returns a handle to the image.
1066 
1067   @param  BootPolicy              If TRUE, indicates that the request originates
1068                                   from the boot manager, and that the boot
1069                                   manager is attempting to load FilePath as a
1070                                   boot selection.
1071   @param  ParentImageHandle       The caller's image handle.
1072   @param  FilePath                The specific file path from which the image is
1073                                   loaded.
1074   @param  SourceBuffer            If not NULL, a pointer to the memory location
1075                                   containing a copy of the image to be loaded.
1076   @param  SourceSize              The size in bytes of SourceBuffer.
1077   @param  DstBuffer               The buffer to store the image
1078   @param  NumberOfPages           If not NULL, it inputs a pointer to the page
1079                                   number of DstBuffer and outputs a pointer to
1080                                   the page number of the image. If this number is
1081                                   not enough,  return EFI_BUFFER_TOO_SMALL and
1082                                   this parameter contains the required number.
1083   @param  ImageHandle             Pointer to the returned image handle that is
1084                                   created when the image is successfully loaded.
1085   @param  EntryPoint              A pointer to the entry point
1086   @param  Attribute               The bit mask of attributes to set for the load
1087                                   PE image
1088 
1089   @retval EFI_SUCCESS             The image was loaded into memory.
1090   @retval EFI_NOT_FOUND           The FilePath was not found.
1091   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
1092   @retval EFI_BUFFER_TOO_SMALL    The buffer is too small
1093   @retval EFI_UNSUPPORTED         The image type is not supported, or the device
1094                                   path cannot be parsed to locate the proper
1095                                   protocol for loading the file.
1096   @retval EFI_OUT_OF_RESOURCES    Image was not loaded due to insufficient
1097                                   resources.
1098   @retval EFI_LOAD_ERROR          Image was not loaded because the image format was corrupt or not
1099                                   understood.
1100   @retval EFI_DEVICE_ERROR        Image was not loaded because the device returned a read error.
1101   @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the
1102                                   image from being loaded. NULL is returned in *ImageHandle.
1103   @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a
1104                                   valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
1105                                   platform policy specifies that the image should not be started.
1106 
1107 **/
1108 EFI_STATUS
CoreLoadImageCommon(IN BOOLEAN BootPolicy,IN EFI_HANDLE ParentImageHandle,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN VOID * SourceBuffer OPTIONAL,IN UINTN SourceSize,IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,IN OUT UINTN * NumberOfPages OPTIONAL,OUT EFI_HANDLE * ImageHandle,OUT EFI_PHYSICAL_ADDRESS * EntryPoint OPTIONAL,IN UINT32 Attribute)1109 CoreLoadImageCommon (
1110   IN  BOOLEAN                          BootPolicy,
1111   IN  EFI_HANDLE                       ParentImageHandle,
1112   IN  EFI_DEVICE_PATH_PROTOCOL         *FilePath,
1113   IN  VOID                             *SourceBuffer       OPTIONAL,
1114   IN  UINTN                            SourceSize,
1115   IN  EFI_PHYSICAL_ADDRESS             DstBuffer           OPTIONAL,
1116   IN OUT UINTN                         *NumberOfPages      OPTIONAL,
1117   OUT EFI_HANDLE                       *ImageHandle,
1118   OUT EFI_PHYSICAL_ADDRESS             *EntryPoint         OPTIONAL,
1119   IN  UINT32                           Attribute
1120   )
1121 {
1122   LOADED_IMAGE_PRIVATE_DATA  *Image;
1123   LOADED_IMAGE_PRIVATE_DATA  *ParentImage;
1124   IMAGE_FILE_HANDLE          FHand;
1125   EFI_STATUS                 Status;
1126   EFI_STATUS                 SecurityStatus;
1127   EFI_HANDLE                 DeviceHandle;
1128   UINT32                     AuthenticationStatus;
1129   EFI_DEVICE_PATH_PROTOCOL   *OriginalFilePath;
1130   EFI_DEVICE_PATH_PROTOCOL   *HandleFilePath;
1131   EFI_DEVICE_PATH_PROTOCOL   *InputFilePath;
1132   EFI_DEVICE_PATH_PROTOCOL   *Node;
1133   UINTN                      FilePathSize;
1134   BOOLEAN                    ImageIsFromFv;
1135   BOOLEAN                    ImageIsFromLoadFile;
1136 
1137   SecurityStatus = EFI_SUCCESS;
1138 
1139   ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
1140   ParentImage = NULL;
1141 
1142   //
1143   // The caller must pass in a valid ParentImageHandle
1144   //
1145   if (ImageHandle == NULL || ParentImageHandle == NULL) {
1146     return EFI_INVALID_PARAMETER;
1147   }
1148 
1149   ParentImage = CoreLoadedImageInfo (ParentImageHandle);
1150   if (ParentImage == NULL) {
1151     DEBUG((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
1152     return EFI_INVALID_PARAMETER;
1153   }
1154 
1155   ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
1156   FHand.Signature  = IMAGE_FILE_HANDLE_SIGNATURE;
1157   OriginalFilePath = FilePath;
1158   InputFilePath    = FilePath;
1159   HandleFilePath   = FilePath;
1160   DeviceHandle     = NULL;
1161   Status           = EFI_SUCCESS;
1162   AuthenticationStatus = 0;
1163   ImageIsFromFv        = FALSE;
1164   ImageIsFromLoadFile  = FALSE;
1165 
1166   //
1167   // If the caller passed a copy of the file, then just use it
1168   //
1169   if (SourceBuffer != NULL) {
1170     FHand.Source     = SourceBuffer;
1171     FHand.SourceSize = SourceSize;
1172     Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
1173     if (EFI_ERROR (Status)) {
1174       DeviceHandle = NULL;
1175     }
1176     if (SourceSize > 0) {
1177       Status = EFI_SUCCESS;
1178     } else {
1179       Status = EFI_LOAD_ERROR;
1180     }
1181   } else {
1182     if (FilePath == NULL) {
1183       return EFI_INVALID_PARAMETER;
1184     }
1185 
1186     //
1187     // Try to get the image device handle by checking the match protocol.
1188     //
1189     Node   = NULL;
1190     Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
1191     if (!EFI_ERROR (Status)) {
1192       ImageIsFromFv = TRUE;
1193     } else {
1194       HandleFilePath = FilePath;
1195       Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
1196       if (EFI_ERROR (Status)) {
1197         if (!BootPolicy) {
1198           HandleFilePath = FilePath;
1199           Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
1200         }
1201         if (EFI_ERROR (Status)) {
1202           HandleFilePath = FilePath;
1203           Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
1204           if (!EFI_ERROR (Status)) {
1205             ImageIsFromLoadFile = TRUE;
1206             Node = HandleFilePath;
1207           }
1208         }
1209       }
1210     }
1211 
1212     //
1213     // Get the source file buffer by its device path.
1214     //
1215     FHand.Source = GetFileBufferByFilePath (
1216                       BootPolicy,
1217                       FilePath,
1218                       &FHand.SourceSize,
1219                       &AuthenticationStatus
1220                       );
1221     if (FHand.Source == NULL) {
1222       Status = EFI_NOT_FOUND;
1223     } else {
1224       FHand.FreeBuffer = TRUE;
1225       if (ImageIsFromLoadFile) {
1226         //
1227         // LoadFile () may cause the device path of the Handle be updated.
1228         //
1229         OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
1230       }
1231     }
1232   }
1233 
1234   if (EFI_ERROR (Status)) {
1235     Image = NULL;
1236     goto Done;
1237   }
1238 
1239   if (gSecurity2 != NULL) {
1240     //
1241     // Verify File Authentication through the Security2 Architectural Protocol
1242     //
1243     SecurityStatus = gSecurity2->FileAuthentication (
1244                                   gSecurity2,
1245                                   OriginalFilePath,
1246                                   FHand.Source,
1247                                   FHand.SourceSize,
1248                                   BootPolicy
1249                                   );
1250     if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
1251       //
1252       // When Security2 is installed, Security Architectural Protocol must be published.
1253       //
1254       ASSERT (gSecurity != NULL);
1255 
1256       //
1257       // Verify the Authentication Status through the Security Architectural Protocol
1258       // Only on images that have been read using Firmware Volume protocol.
1259       //
1260       SecurityStatus = gSecurity->FileAuthenticationState (
1261                                     gSecurity,
1262                                     AuthenticationStatus,
1263                                     OriginalFilePath
1264                                     );
1265     }
1266   } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
1267     //
1268     // Verify the Authentication Status through the Security Architectural Protocol
1269     //
1270     SecurityStatus = gSecurity->FileAuthenticationState (
1271                                   gSecurity,
1272                                   AuthenticationStatus,
1273                                   OriginalFilePath
1274                                   );
1275   }
1276 
1277   //
1278   // Check Security Status.
1279   //
1280   if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
1281     if (SecurityStatus == EFI_ACCESS_DENIED) {
1282       //
1283       // Image was not loaded because the platform policy prohibits the image from being loaded.
1284       // It's the only place we could meet EFI_ACCESS_DENIED.
1285       //
1286       *ImageHandle = NULL;
1287     }
1288     Status = SecurityStatus;
1289     Image = NULL;
1290     goto Done;
1291   }
1292 
1293   //
1294   // Allocate a new image structure
1295   //
1296   Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));
1297   if (Image == NULL) {
1298     Status = EFI_OUT_OF_RESOURCES;
1299     goto Done;
1300   }
1301 
1302   //
1303   // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
1304   //
1305   FilePath = OriginalFilePath;
1306   if (DeviceHandle != NULL) {
1307     Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
1308     if (!EFI_ERROR (Status)) {
1309       FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
1310       FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
1311     }
1312   }
1313   //
1314   // Initialize the fields for an internal driver
1315   //
1316   Image->Signature         = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
1317   Image->Info.SystemTable  = gDxeCoreST;
1318   Image->Info.DeviceHandle = DeviceHandle;
1319   Image->Info.Revision     = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
1320   Image->Info.FilePath     = DuplicateDevicePath (FilePath);
1321   Image->Info.ParentHandle = ParentImageHandle;
1322 
1323 
1324   if (NumberOfPages != NULL) {
1325     Image->NumberOfPages = *NumberOfPages ;
1326   } else {
1327     Image->NumberOfPages = 0 ;
1328   }
1329 
1330   //
1331   // Install the protocol interfaces for this image
1332   // don't fire notifications yet
1333   //
1334   Status = CoreInstallProtocolInterfaceNotify (
1335              &Image->Handle,
1336              &gEfiLoadedImageProtocolGuid,
1337              EFI_NATIVE_INTERFACE,
1338              &Image->Info,
1339              FALSE
1340              );
1341   if (EFI_ERROR (Status)) {
1342     goto Done;
1343   }
1344 
1345   //
1346   // Load the image.  If EntryPoint is Null, it will not be set.
1347   //
1348   Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
1349   if (EFI_ERROR (Status)) {
1350     if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
1351       if (NumberOfPages != NULL) {
1352         *NumberOfPages = Image->NumberOfPages;
1353       }
1354     }
1355     goto Done;
1356   }
1357 
1358   if (NumberOfPages != NULL) {
1359     *NumberOfPages = Image->NumberOfPages;
1360   }
1361 
1362   //
1363   // Register the image in the Debug Image Info Table if the attribute is set
1364   //
1365   if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
1366     CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
1367   }
1368 
1369   //
1370   //Reinstall loaded image protocol to fire any notifications
1371   //
1372   Status = CoreReinstallProtocolInterface (
1373              Image->Handle,
1374              &gEfiLoadedImageProtocolGuid,
1375              &Image->Info,
1376              &Image->Info
1377              );
1378   if (EFI_ERROR (Status)) {
1379     goto Done;
1380   }
1381 
1382   //
1383   // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
1384   // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
1385   //
1386   if (OriginalFilePath != NULL) {
1387     Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
1388   }
1389 
1390   //
1391   // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
1392   //
1393   Status = CoreInstallProtocolInterface (
1394             &Image->Handle,
1395             &gEfiLoadedImageDevicePathProtocolGuid,
1396             EFI_NATIVE_INTERFACE,
1397             Image->LoadedImageDevicePath
1398             );
1399   if (EFI_ERROR (Status)) {
1400     goto Done;
1401   }
1402 
1403   //
1404   // Install HII Package List Protocol onto the image handle
1405   //
1406   if (Image->ImageContext.HiiResourceData != 0) {
1407     Status = CoreInstallProtocolInterface (
1408                &Image->Handle,
1409                &gEfiHiiPackageListProtocolGuid,
1410                EFI_NATIVE_INTERFACE,
1411                (VOID *) (UINTN) Image->ImageContext.HiiResourceData
1412                );
1413     if (EFI_ERROR (Status)) {
1414       goto Done;
1415     }
1416   }
1417   ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
1418 
1419   //
1420   // Success.  Return the image handle
1421   //
1422   *ImageHandle = Image->Handle;
1423 
1424 Done:
1425   //
1426   // All done accessing the source file
1427   // If we allocated the Source buffer, free it
1428   //
1429   if (FHand.FreeBuffer) {
1430     CoreFreePool (FHand.Source);
1431   }
1432   if (OriginalFilePath != InputFilePath) {
1433     CoreFreePool (OriginalFilePath);
1434   }
1435 
1436   //
1437   // There was an error.  If there's an Image structure, free it
1438   //
1439   if (EFI_ERROR (Status)) {
1440     if (Image != NULL) {
1441       CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
1442       Image = NULL;
1443     }
1444   } else if (EFI_ERROR (SecurityStatus)) {
1445     Status = SecurityStatus;
1446   }
1447 
1448   //
1449   // Track the return status from LoadImage.
1450   //
1451   if (Image != NULL) {
1452     Image->LoadImageStatus = Status;
1453   }
1454 
1455   return Status;
1456 }
1457 
1458 
1459 
1460 
1461 /**
1462   Loads an EFI image into memory and returns a handle to the image.
1463 
1464   @param  BootPolicy              If TRUE, indicates that the request originates
1465                                   from the boot manager, and that the boot
1466                                   manager is attempting to load FilePath as a
1467                                   boot selection.
1468   @param  ParentImageHandle       The caller's image handle.
1469   @param  FilePath                The specific file path from which the image is
1470                                   loaded.
1471   @param  SourceBuffer            If not NULL, a pointer to the memory location
1472                                   containing a copy of the image to be loaded.
1473   @param  SourceSize              The size in bytes of SourceBuffer.
1474   @param  ImageHandle             Pointer to the returned image handle that is
1475                                   created when the image is successfully loaded.
1476 
1477   @retval EFI_SUCCESS             The image was loaded into memory.
1478   @retval EFI_NOT_FOUND           The FilePath was not found.
1479   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
1480   @retval EFI_UNSUPPORTED         The image type is not supported, or the device
1481                                   path cannot be parsed to locate the proper
1482                                   protocol for loading the file.
1483   @retval EFI_OUT_OF_RESOURCES    Image was not loaded due to insufficient
1484                                   resources.
1485   @retval EFI_LOAD_ERROR          Image was not loaded because the image format was corrupt or not
1486                                   understood.
1487   @retval EFI_DEVICE_ERROR        Image was not loaded because the device returned a read error.
1488   @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the
1489                                   image from being loaded. NULL is returned in *ImageHandle.
1490   @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a
1491                                   valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
1492                                   platform policy specifies that the image should not be started.
1493 
1494 **/
1495 EFI_STATUS
1496 EFIAPI
CoreLoadImage(IN BOOLEAN BootPolicy,IN EFI_HANDLE ParentImageHandle,IN EFI_DEVICE_PATH_PROTOCOL * FilePath,IN VOID * SourceBuffer OPTIONAL,IN UINTN SourceSize,OUT EFI_HANDLE * ImageHandle)1497 CoreLoadImage (
1498   IN BOOLEAN                    BootPolicy,
1499   IN EFI_HANDLE                 ParentImageHandle,
1500   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath,
1501   IN VOID                       *SourceBuffer   OPTIONAL,
1502   IN UINTN                      SourceSize,
1503   OUT EFI_HANDLE                *ImageHandle
1504   )
1505 {
1506   EFI_STATUS    Status;
1507   EFI_HANDLE    Handle;
1508 
1509   PERF_LOAD_IMAGE_BEGIN (NULL);
1510 
1511   Status = CoreLoadImageCommon (
1512              BootPolicy,
1513              ParentImageHandle,
1514              FilePath,
1515              SourceBuffer,
1516              SourceSize,
1517              (EFI_PHYSICAL_ADDRESS) (UINTN) NULL,
1518              NULL,
1519              ImageHandle,
1520              NULL,
1521              EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
1522              );
1523 
1524   Handle = NULL;
1525   if (!EFI_ERROR (Status)) {
1526     //
1527     // ImageHandle will be valid only Status is success.
1528     //
1529     Handle = *ImageHandle;
1530   }
1531 
1532   PERF_LOAD_IMAGE_END (Handle);
1533 
1534   return Status;
1535 }
1536 
1537 /**
1538   Transfer control to a loaded image's entry point.
1539 
1540   @param  ImageHandle             Handle of image to be started.
1541   @param  ExitDataSize            Pointer of the size to ExitData
1542   @param  ExitData                Pointer to a pointer to a data buffer that
1543                                   includes a Null-terminated string,
1544                                   optionally followed by additional binary data.
1545                                   The string is a description that the caller may
1546                                   use to further indicate the reason for the
1547                                   image's exit.
1548 
1549   @retval EFI_INVALID_PARAMETER   Invalid parameter
1550   @retval EFI_OUT_OF_RESOURCES    No enough buffer to allocate
1551   @retval EFI_SECURITY_VIOLATION  The current platform policy specifies that the image should not be started.
1552   @retval EFI_SUCCESS             Successfully transfer control to the image's
1553                                   entry point.
1554 
1555 **/
1556 EFI_STATUS
1557 EFIAPI
CoreStartImage(IN EFI_HANDLE ImageHandle,OUT UINTN * ExitDataSize,OUT CHAR16 ** ExitData OPTIONAL)1558 CoreStartImage (
1559   IN EFI_HANDLE  ImageHandle,
1560   OUT UINTN      *ExitDataSize,
1561   OUT CHAR16     **ExitData  OPTIONAL
1562   )
1563 {
1564   EFI_STATUS                    Status;
1565   LOADED_IMAGE_PRIVATE_DATA     *Image;
1566   LOADED_IMAGE_PRIVATE_DATA     *LastImage;
1567   UINT64                        HandleDatabaseKey;
1568   UINTN                         SetJumpFlag;
1569   EFI_HANDLE                    Handle;
1570 
1571   Handle = ImageHandle;
1572 
1573   Image = CoreLoadedImageInfo (ImageHandle);
1574   if (Image == NULL  ||  Image->Started) {
1575     return EFI_INVALID_PARAMETER;
1576   }
1577   if (EFI_ERROR (Image->LoadImageStatus)) {
1578     return Image->LoadImageStatus;
1579   }
1580 
1581   //
1582   // The image to be started must have the machine type supported by DxeCore.
1583   //
1584   if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
1585       Image->PeCoffEmu == NULL) {
1586     //
1587     // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
1588     // But it can not be started.
1589     //
1590     DEBUG ((EFI_D_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine)));
1591     DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));
1592     return EFI_UNSUPPORTED;
1593   }
1594 
1595   if (Image->PeCoffEmu != NULL) {
1596     Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,
1597                                  Image->ImageBasePage,
1598                                  EFI_PAGES_TO_SIZE (Image->NumberOfPages),
1599                                  &Image->EntryPoint);
1600     if (EFI_ERROR (Status)) {
1601       DEBUG ((DEBUG_LOAD | DEBUG_ERROR,
1602         "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
1603           Status));
1604       return Status;
1605     }
1606   }
1607 
1608   PERF_START_IMAGE_BEGIN (Handle);
1609 
1610 
1611   //
1612   // Push the current start image context, and
1613   // link the current image to the head.   This is the
1614   // only image that can call Exit()
1615   //
1616   HandleDatabaseKey = CoreGetHandleDatabaseKey ();
1617   LastImage         = mCurrentImage;
1618   mCurrentImage     = Image;
1619   Image->Tpl        = gEfiCurrentTpl;
1620 
1621   //
1622   // Set long jump for Exit() support
1623   // JumpContext must be aligned on a CPU specific boundary.
1624   // Overallocate the buffer and force the required alignment
1625   //
1626   Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1627   if (Image->JumpBuffer == NULL) {
1628     //
1629     // Image may be unloaded after return with failure,
1630     // then ImageHandle may be invalid, so use NULL handle to record perf log.
1631     //
1632     PERF_START_IMAGE_END (NULL);
1633 
1634     //
1635     // Pop the current start image context
1636     //
1637     mCurrentImage = LastImage;
1638 
1639     return EFI_OUT_OF_RESOURCES;
1640   }
1641   Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
1642 
1643   SetJumpFlag = SetJump (Image->JumpContext);
1644   //
1645   // The initial call to SetJump() must always return 0.
1646   // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
1647   //
1648   if (SetJumpFlag == 0) {
1649     RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
1650     //
1651     // Call the image's entry point
1652     //
1653     Image->Started = TRUE;
1654     Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
1655 
1656     //
1657     // Add some debug information if the image returned with error.
1658     // This make the user aware and check if the driver image have already released
1659     // all the resource in this situation.
1660     //
1661     DEBUG_CODE_BEGIN ();
1662       if (EFI_ERROR (Image->Status)) {
1663         DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
1664       }
1665     DEBUG_CODE_END ();
1666 
1667     //
1668     // If the image returns, exit it through Exit()
1669     //
1670     CoreExit (ImageHandle, Image->Status, 0, NULL);
1671   }
1672 
1673   //
1674   // Image has completed.  Verify the tpl is the same
1675   //
1676   ASSERT (Image->Tpl == gEfiCurrentTpl);
1677   CoreRestoreTpl (Image->Tpl);
1678 
1679   CoreFreePool (Image->JumpBuffer);
1680 
1681   //
1682   // Pop the current start image context
1683   //
1684   mCurrentImage = LastImage;
1685 
1686   //
1687   // UEFI Specification - StartImage() - EFI 1.10 Extension
1688   // To maintain compatibility with UEFI drivers that are written to the EFI
1689   // 1.02 Specification, StartImage() must monitor the handle database before
1690   // and after each image is started. If any handles are created or modified
1691   // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
1692   // be called with the Recursive parameter set to TRUE for each of the newly
1693   // created or modified handles before StartImage() returns.
1694   //
1695   if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1696     CoreConnectHandlesByKey (HandleDatabaseKey);
1697   }
1698 
1699   //
1700   // Handle the image's returned ExitData
1701   //
1702   DEBUG_CODE_BEGIN ();
1703     if (Image->ExitDataSize != 0 || Image->ExitData != NULL) {
1704 
1705       DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
1706       if (Image->ExitData != NULL) {
1707         DEBUG ((DEBUG_LOAD, " (%hs)", Image->ExitData));
1708       }
1709       DEBUG ((DEBUG_LOAD, "\n"));
1710     }
1711   DEBUG_CODE_END ();
1712 
1713   //
1714   //  Return the exit data to the caller
1715   //
1716   if (ExitData != NULL && ExitDataSize != NULL) {
1717     *ExitDataSize = Image->ExitDataSize;
1718     *ExitData     = Image->ExitData;
1719   } else {
1720     //
1721     // Caller doesn't want the exit data, free it
1722     //
1723     CoreFreePool (Image->ExitData);
1724     Image->ExitData = NULL;
1725   }
1726 
1727   //
1728   // Save the Status because Image will get destroyed if it is unloaded.
1729   //
1730   Status = Image->Status;
1731 
1732   //
1733   // If the image returned an error, or if the image is an application
1734   // unload it
1735   //
1736   if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1737     CoreUnloadAndCloseImage (Image, TRUE);
1738     //
1739     // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
1740     //
1741     Handle = NULL;
1742   }
1743 
1744   //
1745   // Done
1746   //
1747   PERF_START_IMAGE_END (Handle);
1748   return Status;
1749 }
1750 
1751 /**
1752   Terminates the currently loaded EFI image and returns control to boot services.
1753 
1754   @param  ImageHandle             Handle that identifies the image. This
1755                                   parameter is passed to the image on entry.
1756   @param  Status                  The image's exit code.
1757   @param  ExitDataSize            The size, in bytes, of ExitData. Ignored if
1758                                   ExitStatus is EFI_SUCCESS.
1759   @param  ExitData                Pointer to a data buffer that includes a
1760                                   Null-terminated Unicode string, optionally
1761                                   followed by additional binary data. The string
1762                                   is a description that the caller may use to
1763                                   further indicate the reason for the image's
1764                                   exit.
1765 
1766   @retval EFI_INVALID_PARAMETER   Image handle is NULL or it is not current
1767                                   image.
1768   @retval EFI_SUCCESS             Successfully terminates the currently loaded
1769                                   EFI image.
1770   @retval EFI_ACCESS_DENIED       Should never reach there.
1771   @retval EFI_OUT_OF_RESOURCES    Could not allocate pool
1772 
1773 **/
1774 EFI_STATUS
1775 EFIAPI
CoreExit(IN EFI_HANDLE ImageHandle,IN EFI_STATUS Status,IN UINTN ExitDataSize,IN CHAR16 * ExitData OPTIONAL)1776 CoreExit (
1777   IN EFI_HANDLE  ImageHandle,
1778   IN EFI_STATUS  Status,
1779   IN UINTN       ExitDataSize,
1780   IN CHAR16      *ExitData  OPTIONAL
1781   )
1782 {
1783   LOADED_IMAGE_PRIVATE_DATA  *Image;
1784   EFI_TPL                    OldTpl;
1785 
1786   //
1787   // Prevent possible reentrance to this function
1788   // for the same ImageHandle
1789   //
1790   OldTpl = CoreRaiseTpl (TPL_NOTIFY);
1791 
1792   Image = CoreLoadedImageInfo (ImageHandle);
1793   if (Image == NULL) {
1794     Status = EFI_INVALID_PARAMETER;
1795     goto Done;
1796   }
1797 
1798   if (!Image->Started) {
1799     //
1800     // The image has not been started so just free its resources
1801     //
1802     CoreUnloadAndCloseImage (Image, TRUE);
1803     Status = EFI_SUCCESS;
1804     goto Done;
1805   }
1806 
1807   //
1808   // Image has been started, verify this image can exit
1809   //
1810   if (Image != mCurrentImage) {
1811     DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
1812     Status = EFI_INVALID_PARAMETER;
1813     goto Done;
1814   }
1815 
1816   //
1817   // Set status
1818   //
1819   Image->Status = Status;
1820 
1821   //
1822   // If there's ExitData info, move it
1823   //
1824   if (ExitData != NULL) {
1825     Image->ExitDataSize = ExitDataSize;
1826     Image->ExitData = AllocatePool (Image->ExitDataSize);
1827     if (Image->ExitData == NULL) {
1828       Status = EFI_OUT_OF_RESOURCES;
1829       goto Done;
1830     }
1831     CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
1832   }
1833 
1834   CoreRestoreTpl (OldTpl);
1835   //
1836   // return to StartImage
1837   //
1838   LongJump (Image->JumpContext, (UINTN)-1);
1839 
1840   //
1841   // If we return from LongJump, then it is an error
1842   //
1843   ASSERT (FALSE);
1844   Status = EFI_ACCESS_DENIED;
1845 Done:
1846   CoreRestoreTpl (OldTpl);
1847   return Status;
1848 }
1849 
1850 
1851 
1852 
1853 /**
1854   Unloads an image.
1855 
1856   @param  ImageHandle             Handle that identifies the image to be
1857                                   unloaded.
1858 
1859   @retval EFI_SUCCESS             The image has been unloaded.
1860   @retval EFI_UNSUPPORTED         The image has been started, and does not support
1861                                   unload.
1862   @retval EFI_INVALID_PARAMPETER  ImageHandle is not a valid image handle.
1863 
1864 **/
1865 EFI_STATUS
1866 EFIAPI
CoreUnloadImage(IN EFI_HANDLE ImageHandle)1867 CoreUnloadImage (
1868   IN EFI_HANDLE  ImageHandle
1869   )
1870 {
1871   EFI_STATUS                 Status;
1872   LOADED_IMAGE_PRIVATE_DATA  *Image;
1873 
1874   Image = CoreLoadedImageInfo (ImageHandle);
1875   if (Image == NULL ) {
1876     //
1877     // The image handle is not valid
1878     //
1879     Status = EFI_INVALID_PARAMETER;
1880     goto Done;
1881   }
1882 
1883   if (Image->Started) {
1884     //
1885     // The image has been started, request it to unload.
1886     //
1887     Status = EFI_UNSUPPORTED;
1888     if (Image->Info.Unload != NULL) {
1889       Status = Image->Info.Unload (ImageHandle);
1890     }
1891 
1892   } else {
1893     //
1894     // This Image hasn't been started, thus it can be unloaded
1895     //
1896     Status = EFI_SUCCESS;
1897   }
1898 
1899 
1900   if (!EFI_ERROR (Status)) {
1901     //
1902     // if the Image was not started or Unloaded O.K. then clean up
1903     //
1904     CoreUnloadAndCloseImage (Image, TRUE);
1905   }
1906 
1907 Done:
1908   return Status;
1909 }
1910