]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Image/Image.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / Image.c
index 56d93ade805d863a246260013c4b774ab1af0139..44b7f105a2f9dbf31c8339c006e189405a02926d 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   Core image handling services to load and unload PeImage.\r
 \r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -20,15 +14,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 LOADED_IMAGE_PRIVATE_DATA  *mCurrentImage = NULL;\r
 \r
-LOAD_PE32_IMAGE_PRIVATE_DATA  mLoadPe32PrivateData = {\r
-  LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE,\r
-  NULL,\r
-  {\r
-    CoreLoadImageEx,\r
-    CoreUnloadImageEx\r
-  }\r
-};\r
+typedef struct {\r
+  LIST_ENTRY                            Link;\r
+  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL  *Emulator;\r
+  UINT16                                MachineType;\r
+} EMULATOR_ENTRY;\r
 \r
+STATIC LIST_ENTRY                       mAvailableEmulators;\r
+STATIC EFI_EVENT                        mPeCoffEmuProtocolRegistrationEvent;\r
+STATIC VOID                             *mPeCoffEmuProtocolNotifyRegistration;\r
 \r
 //\r
 // This code is needed to build the Image handle for the DXE Core\r
@@ -66,17 +60,115 @@ LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage  = {
   NULL,                       // JumpBuffer\r
   NULL,                       // JumpContext\r
   0,                          // Machine\r
-  NULL,                       // Ebc\r
+  NULL,                       // PeCoffEmu\r
   NULL,                       // RuntimeData\r
   NULL                        // LoadedImageDevicePath\r
 };\r
 //\r
 // The field is define for Loading modules at fixed address feature to tracker the PEI code\r
 // memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page\r
-// available or not. \r
+// available or not.\r
 //\r
 GLOBAL_REMOVE_IF_UNREFERENCED    UINT64                *mDxeCodeMemoryRangeUsageBitMap=NULL;\r
 \r
+typedef struct {\r
+  UINT16  MachineType;\r
+  CHAR16  *MachineTypeName;\r
+} MACHINE_TYPE_INFO;\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO  mMachineTypeInfo[] = {\r
+  {EFI_IMAGE_MACHINE_IA32,           L"IA32"},\r
+  {EFI_IMAGE_MACHINE_IA64,           L"IA64"},\r
+  {EFI_IMAGE_MACHINE_X64,            L"X64"},\r
+  {EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM"},\r
+  {EFI_IMAGE_MACHINE_AARCH64,        L"AARCH64"}\r
+};\r
+\r
+UINT16 mDxeCoreImageMachineType = 0;\r
+\r
+/**\r
+ Return machine type name.\r
+\r
+ @param MachineType The machine type\r
+\r
+ @return machine type name\r
+**/\r
+CHAR16 *\r
+GetMachineTypeName (\r
+  UINT16 MachineType\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {\r
+    if (mMachineTypeInfo[Index].MachineType == MachineType) {\r
+      return mMachineTypeInfo[Index].MachineTypeName;\r
+    }\r
+  }\r
+\r
+  return L"<Unknown>";\r
+}\r
+\r
+/**\r
+  Notification event handler registered by CoreInitializeImageServices () to\r
+  keep track of which PE/COFF image emulators are available.\r
+\r
+  @param  Event          The Event that is being processed, not used.\r
+  @param  Context        Event Context, not used.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+PeCoffEmuProtocolNotify (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 BufferSize;\r
+  EFI_HANDLE                            EmuHandle;\r
+  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL  *Emulator;\r
+  EMULATOR_ENTRY                        *Entry;\r
+\r
+  EmuHandle = NULL;\r
+  Emulator  = NULL;\r
+\r
+  while (TRUE) {\r
+    BufferSize = sizeof (EmuHandle);\r
+    Status = CoreLocateHandle (\r
+               ByRegisterNotify,\r
+               NULL,\r
+               mPeCoffEmuProtocolNotifyRegistration,\r
+               &BufferSize,\r
+               &EmuHandle\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // If no more notification events exit\r
+      //\r
+      return;\r
+    }\r
+\r
+    Status = CoreHandleProtocol (\r
+               EmuHandle,\r
+               &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
+               (VOID **)&Emulator\r
+               );\r
+    if (EFI_ERROR (Status) || Emulator == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Entry = AllocateZeroPool (sizeof (*Entry));\r
+    ASSERT (Entry != NULL);\r
+\r
+    Entry->Emulator    = Emulator;\r
+    Entry->MachineType = Entry->Emulator->MachineType;\r
+\r
+    InsertTailList (&mAvailableEmulators, &Entry->Link);\r
+  }\r
+}\r
+\r
 /**\r
   Add the Image Services to EFI Boot Services Table and install the protocol\r
   interfaces for this image.\r
@@ -97,7 +189,7 @@ CoreInitializeImageServices (
   UINT64                            DxeCoreImageLength;\r
   VOID                              *DxeCoreEntryPoint;\r
   EFI_PEI_HOB_POINTERS              DxeCoreHob;\r
\r
+\r
   //\r
   // Searching for image hob\r
   //\r
@@ -117,7 +209,7 @@ CoreInitializeImageServices (
   DxeCoreImageLength      = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;\r
   DxeCoreEntryPoint       = (VOID *) (UINTN) DxeCoreHob.MemoryAllocationModule->EntryPoint;\r
   gDxeCoreFileName        = &DxeCoreHob.MemoryAllocationModule->ModuleName;\r
-  \r
+\r
   //\r
   // Initialize the fields for an internal driver\r
   //\r
@@ -147,20 +239,35 @@ CoreInitializeImageServices (
   //\r
   // Fill in DXE globals\r
   //\r
+  mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);\r
   gDxeCoreImageHandle = Image->Handle;\r
   gDxeCoreLoadedImage = &Image->Info;\r
 \r
-  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
-    //\r
-    // Export DXE Core PE Loader functionality for backward compatibility.\r
-    //\r
-    Status = CoreInstallProtocolInterface (\r
-               &mLoadPe32PrivateData.Handle,\r
-               &gEfiLoadPeImageProtocolGuid,\r
-               EFI_NATIVE_INTERFACE,\r
-               &mLoadPe32PrivateData.Pe32Image\r
-               );\r
-  }\r
+  //\r
+  // Create the PE/COFF emulator protocol registration event\r
+  //\r
+  Status = CoreCreateEvent (\r
+             EVT_NOTIFY_SIGNAL,\r
+             TPL_CALLBACK,\r
+             PeCoffEmuProtocolNotify,\r
+             NULL,\r
+             &mPeCoffEmuProtocolRegistrationEvent\r
+             );\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  //\r
+  // Register for protocol notifications on this event\r
+  //\r
+  Status = CoreRegisterProtocolNotify (\r
+             &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
+             mPeCoffEmuProtocolRegistrationEvent,\r
+             &mPeCoffEmuProtocolNotifyRegistration\r
+             );\r
+  ASSERT_EFI_ERROR(Status);\r
+\r
+  InitializeListHead (&mAvailableEmulators);\r
+\r
+  ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
 \r
   return Status;\r
 }\r
@@ -191,6 +298,14 @@ CoreReadImageFile (
   UINTN               EndPosition;\r
   IMAGE_FILE_HANDLE  *FHand;\r
 \r
+  if (UserHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MAX_ADDRESS - Offset < *ReadSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
   FHand = (IMAGE_FILE_HANDLE  *)UserHandle;\r
   ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);\r
 \r
@@ -209,13 +324,13 @@ CoreReadImageFile (
   return EFI_SUCCESS;\r
 }\r
 /**\r
-  To check memory usage bit map arry to figure out if the memory range the image will be loaded in is available or not. If \r
-  memory range is avaliable, the function will mark the correponding bits to 1 which indicates the memory range is used.\r
-  The function is only invoked when load modules at fixed address feature is enabled. \r
-  \r
-  @param  ImageBase                The base addres the image will be loaded at.\r
+  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\r
+  memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.\r
+  The function is only invoked when load modules at fixed address feature is enabled.\r
+\r
+  @param  ImageBase                The base address the image will be loaded at.\r
   @param  ImageSize                The size of the image\r
-  \r
+\r
   @retval EFI_SUCCESS              The memory range the image will be loaded in is available\r
   @retval EFI_NOT_FOUND            The memory range the image will be loaded in is not available\r
 **/\r
@@ -226,23 +341,23 @@ CheckAndMarkFixLoadingMemoryUsageBitMap (
   )\r
 {\r
    UINT32                             DxeCodePageNumber;\r
-   UINT64                             DxeCodeSize; \r
+   UINT64                             DxeCodeSize;\r
    EFI_PHYSICAL_ADDRESS               DxeCodeBase;\r
    UINTN                              BaseOffsetPageNumber;\r
    UINTN                              TopOffsetPageNumber;\r
    UINTN                              Index;\r
    //\r
    // The DXE code range includes RuntimeCodePage range and Boot time code range.\r
-   //  \r
+   //\r
    DxeCodePageNumber = PcdGet32(PcdLoadFixAddressRuntimeCodePageNumber);\r
    DxeCodePageNumber += PcdGet32(PcdLoadFixAddressBootTimeCodePageNumber);\r
    DxeCodeSize       = EFI_PAGES_TO_SIZE(DxeCodePageNumber);\r
    DxeCodeBase       =  gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;\r
-   \r
+\r
    //\r
-   // If the memory usage bit map is not initialized,  do it. Every bit in the array \r
+   // If the memory usage bit map is not initialized,  do it. Every bit in the array\r
    // indicate the status of the corresponding memory page, available or not\r
-   // \r
+   //\r
    if (mDxeCodeMemoryRangeUsageBitMap == NULL) {\r
      mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool(((DxeCodePageNumber/64) + 1)*sizeof(UINT64));\r
    }\r
@@ -257,39 +372,39 @@ CheckAndMarkFixLoadingMemoryUsageBitMap (
    //\r
    if (gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress <  ImageBase + ImageSize ||\r
        DxeCodeBase >  ImageBase) {\r
-     return EFI_NOT_FOUND;   \r
-   }   \r
+     return EFI_NOT_FOUND;\r
+   }\r
    //\r
    // Test if the memory is avalaible or not.\r
-   // \r
-   BaseOffsetPageNumber = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));\r
-   TopOffsetPageNumber  = (UINTN)EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));\r
+   //\r
+   BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - DxeCodeBase));\r
+   TopOffsetPageNumber  = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - DxeCodeBase));\r
    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
      if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {\r
        //\r
        // This page is already used.\r
        //\r
-       return EFI_NOT_FOUND;  \r
+       return EFI_NOT_FOUND;\r
      }\r
    }\r
-   \r
+\r
    //\r
    // Being here means the memory range is available.  So mark the bits for the memory range\r
-   // \r
+   //\r
    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {\r
      mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));\r
    }\r
-   return  EFI_SUCCESS;   \r
+   return  EFI_SUCCESS;\r
 }\r
 /**\r
 \r
-  Get the fixed loadding address from image header assigned by build tool. This function only be called\r
+  Get the fixed loading address from image header assigned by build tool. This function only be called\r
   when Loading module at Fixed address feature enabled.\r
 \r
   @param  ImageContext              Pointer to the image context structure that describes the PE/COFF\r
                                     image that needs to be examined by this function.\r
   @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .\r
-  @retval EFI_NOT_FOUND             The image has no assigned fixed loadding address.\r
+  @retval EFI_NOT_FOUND             The image has no assigned fixed loading address.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -306,21 +421,19 @@ GetPeCoffImageFixLoadingAssignedAddress(
    UINT16                             NumberOfSections;\r
    IMAGE_FILE_HANDLE                  *Handle;\r
    UINT64                             ValueInSectionHeader;\r
-                             \r
+\r
 \r
    Status = EFI_NOT_FOUND;\r
\r
+\r
    //\r
    // Get PeHeader pointer\r
    //\r
    Handle = (IMAGE_FILE_HANDLE*)ImageContext->Handle;\r
    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )Handle->Source + ImageContext->PeCoffHeaderOffset);\r
-   SectionHeaderOffset = (UINTN)(\r
-                                 ImageContext->PeCoffHeaderOffset +\r
-                                 sizeof (UINT32) +\r
-                                 sizeof (EFI_IMAGE_FILE_HEADER) +\r
-                                 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader\r
-                                 );\r
+   SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +\r
+                         sizeof (UINT32) +\r
+                         sizeof (EFI_IMAGE_FILE_HEADER) +\r
+                         ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;\r
    NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;\r
 \r
    //\r
@@ -340,38 +453,84 @@ GetPeCoffImageFixLoadingAssignedAddress(
      if (EFI_ERROR (Status)) {\r
        return Status;\r
      }\r
-     \r
+     if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {\r
+       return EFI_NOT_FOUND;\r
+     }\r
+\r
      Status = EFI_NOT_FOUND;\r
-     \r
+\r
      if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {\r
        //\r
        // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header\r
-       // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an \r
-       // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations  \r
-       // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fileds should be set to Zero\r
+       // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an\r
+       // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations\r
+       // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero\r
        //\r
        ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);\r
        if (ValueInSectionHeader != 0) {\r
          //\r
-         // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext \r
-         // hold the spcified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset\r
+         // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext\r
+         // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset\r
          // relative to top address\r
          //\r
          if ((INT64)PcdGet64(PcdLoadModuleAtFixAddressEnable) < 0) {\r
-                ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;\r
+            ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;\r
          }\r
          //\r
-         // Check if the memory range is avaliable.\r
+         // Check if the memory range is available.\r
          //\r
          Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));\r
        }\r
-       break; \r
+       break;\r
      }\r
      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
    }\r
-   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));\r
+   DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));\r
    return Status;\r
 }\r
+\r
+/**\r
+  Decides whether a PE/COFF image can execute on this system, either natively\r
+  or via emulation/interpretation. In the latter case, the PeCoffEmu member\r
+  of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer\r
+  to the emulator protocol that supports this image.\r
+\r
+  @param[in, out]   Image         LOADED_IMAGE_PRIVATE_DATA struct pointer\r
+\r
+  @retval           TRUE          The image is supported\r
+  @retval           FALSE         The image is not supported\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+CoreIsImageTypeSupported (\r
+  IN OUT LOADED_IMAGE_PRIVATE_DATA  *Image\r
+  )\r
+{\r
+  LIST_ENTRY                        *Link;\r
+  EMULATOR_ENTRY                    *Entry;\r
+\r
+  for (Link = GetFirstNode (&mAvailableEmulators);\r
+       !IsNull (&mAvailableEmulators, Link);\r
+       Link = GetNextNode (&mAvailableEmulators, Link)) {\r
+\r
+    Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);\r
+    if (Entry->MachineType != Image->ImageContext.Machine) {\r
+      continue;\r
+    }\r
+\r
+    if (Entry->Emulator->IsImageSupported (Entry->Emulator,\r
+                           Image->ImageContext.ImageType,\r
+                           Image->Info.FilePath)) {\r
+      Image->PeCoffEmu = Entry->Emulator;\r
+      return TRUE;\r
+    }\r
+  }\r
+\r
+  return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||\r
+         EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);\r
+}\r
+\r
 /**\r
   Loads, relocates, and invokes a PE/COFF image\r
 \r
@@ -420,14 +579,15 @@ CoreLoadPeImage (
     return Status;\r
   }\r
 \r
-  if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {\r
-    if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine)) {\r
-      //\r
-      // The PE/COFF loader can support loading image types that can be executed.\r
-      // If we loaded an image type that we can not execute return EFI_UNSUPORTED.\r
-      //\r
-      return EFI_UNSUPPORTED;\r
-    }\r
+  if (!CoreIsImageTypeSupported (Image)) {\r
+    //\r
+    // The PE/COFF loader can support loading image types that can be executed.\r
+    // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",\r
+      GetMachineTypeName (Image->ImageContext.Machine),\r
+      GetMachineTypeName (mDxeCoreImageMachineType)));\r
+    return EFI_UNSUPPORTED;\r
   }\r
 \r
   //\r
@@ -453,7 +613,7 @@ CoreLoadPeImage (
   }\r
 \r
   //\r
-  // Allocate memory of the correct memory type aligned on the required image boundry\r
+  // Allocate memory of the correct memory type aligned on the required image boundary\r
   //\r
   DstBufAlocated = FALSE;\r
   if (DstBuffer == 0) {\r
@@ -486,17 +646,17 @@ CoreLoadPeImage (
 \r
       if (EFI_ERROR (Status))  {\r
           //\r
-         // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.\r
-         //\r
-          DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));\r
-        \r
+          // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.\r
+          //\r
+          DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));\r
+\r
           Status = CoreAllocatePages (\r
                      AllocateAnyPages,\r
                      (EFI_MEMORY_TYPE) (Image->ImageContext.ImageCodeMemoryType),\r
                      Image->NumberOfPages,\r
                      &Image->ImageContext.ImageAddress\r
-                     );         \r
-      } \r
+                     );\r
+      }\r
     } else {\r
       if (Image->ImageContext.ImageAddress >= 0x100000 || Image->ImageContext.RelocationsStripped) {\r
         Status = CoreAllocatePages (\r
@@ -588,51 +748,14 @@ CoreLoadPeImage (
   InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);\r
 \r
   //\r
-  // Copy the machine type from the context to the image private data. This\r
-  // is needed during image unload to know if we should call an EBC protocol\r
-  // to unload the image.\r
+  // Copy the machine type from the context to the image private data.\r
   //\r
   Image->Machine = Image->ImageContext.Machine;\r
 \r
   //\r
-  // Get the image entry point. If it's an EBC image, then call into the\r
-  // interpreter to create a thunk for the entry point and use the returned\r
-  // value for the entry point.\r
+  // Get the image entry point.\r
   //\r
   Image->EntryPoint   = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;\r
-  if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {\r
-    //\r
-    // Locate the EBC interpreter protocol\r
-    //\r
-    Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, (VOID **)&Image->Ebc);\r
-    if (EFI_ERROR(Status) || Image->Ebc == NULL) {\r
-      DEBUG ((DEBUG_LOAD | DEBUG_ERROR, "CoreLoadPeImage: There is no EBC interpreter for an EBC image.\n"));\r
-      goto Done;\r
-    }\r
-\r
-    //\r
-    // Register a callback for flushing the instruction cache so that created\r
-    // thunks can be flushed.\r
-    //\r
-    Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);\r
-    if (EFI_ERROR(Status)) {\r
-      goto Done;\r
-    }\r
-\r
-    //\r
-    // Create a thunk for the image's entry point. This will be the new\r
-    // entry point for the image.\r
-    //\r
-    Status = Image->Ebc->CreateThunk (\r
-                           Image->Ebc,\r
-                           Image->Handle,\r
-                           (VOID *)(UINTN) Image->ImageContext.EntryPoint,\r
-                           (VOID **) &Image->EntryPoint\r
-                           );\r
-    if (EFI_ERROR(Status)) {\r
-      goto Done;\r
-    }\r
-  }\r
 \r
   //\r
   // Fill in the image information for the Loaded Image Protocol\r
@@ -656,6 +779,7 @@ CoreLoadPeImage (
       Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;\r
       Image->RuntimeData->Handle         = Image->Handle;\r
       InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);\r
+      InsertImageRecord (Image->RuntimeData);\r
     }\r
   }\r
 \r
@@ -732,6 +856,8 @@ Done:
 \r
   if (DstBufAlocated) {\r
     CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);\r
+    Image->ImageContext.ImageAddress = 0;\r
+    Image->ImageBasePage = 0;\r
   }\r
 \r
   if (Image->ImageContext.FixupData != NULL) {\r
@@ -800,11 +926,20 @@ CoreUnloadAndCloseImage (
   UINTN                               OpenInfoCount;\r
   UINTN                               OpenInfoIndex;\r
 \r
-  if (Image->Ebc != NULL) {\r
+  HandleBuffer = NULL;\r
+  ProtocolGuidArray = NULL;\r
+\r
+  if (Image->Started) {\r
+    UnregisterMemoryProfileImage (Image);\r
+  }\r
+\r
+  UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
+\r
+  if (Image->PeCoffEmu != NULL) {\r
     //\r
-    // If EBC protocol exists we must perform cleanups for this image.\r
+    // If the PE/COFF Emulator protocol exists we must unregister the image.\r
     //\r
-    Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);\r
+    Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);\r
   }\r
 \r
   //\r
@@ -895,6 +1030,7 @@ CoreUnloadAndCloseImage (
       // Remove the Image from the Runtime Image list as we are about to Free it!\r
       //\r
       RemoveEntryList (&Image->RuntimeData->Link);\r
+      RemoveImageRecord (Image->RuntimeData);\r
     }\r
     CoreFreePool (Image->RuntimeData);\r
   }\r
@@ -962,10 +1098,10 @@ CoreUnloadAndCloseImage (
   @retval EFI_LOAD_ERROR          Image was not loaded because the image format was corrupt or not\r
                                   understood.\r
   @retval EFI_DEVICE_ERROR        Image was not loaded because the device returned a read error.\r
-  @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the \r
+  @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the\r
                                   image from being loaded. NULL is returned in *ImageHandle.\r
-  @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a \r
-                                  valid EFI_LOADED_IMAGE_PROTOCOL. However, the current \r
+  @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a\r
+                                  valid EFI_LOADED_IMAGE_PROTOCOL. However, the current\r
                                   platform policy specifies that the image should not be started.\r
 \r
 **/\r
@@ -992,7 +1128,11 @@ CoreLoadImageCommon (
   UINT32                     AuthenticationStatus;\r
   EFI_DEVICE_PATH_PROTOCOL   *OriginalFilePath;\r
   EFI_DEVICE_PATH_PROTOCOL   *HandleFilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL   *InputFilePath;\r
+  EFI_DEVICE_PATH_PROTOCOL   *Node;\r
   UINTN                      FilePathSize;\r
+  BOOLEAN                    ImageIsFromFv;\r
+  BOOLEAN                    ImageIsFromLoadFile;\r
 \r
   SecurityStatus = EFI_SUCCESS;\r
 \r
@@ -1015,17 +1155,24 @@ CoreLoadImageCommon (
   ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));\r
   FHand.Signature  = IMAGE_FILE_HANDLE_SIGNATURE;\r
   OriginalFilePath = FilePath;\r
+  InputFilePath    = FilePath;\r
   HandleFilePath   = FilePath;\r
   DeviceHandle     = NULL;\r
   Status           = EFI_SUCCESS;\r
   AuthenticationStatus = 0;\r
+  ImageIsFromFv        = FALSE;\r
+  ImageIsFromLoadFile  = FALSE;\r
+\r
   //\r
   // If the caller passed a copy of the file, then just use it\r
   //\r
   if (SourceBuffer != NULL) {\r
     FHand.Source     = SourceBuffer;\r
     FHand.SourceSize = SourceSize;\r
-    CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+    Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      DeviceHandle = NULL;\r
+    }\r
     if (SourceSize > 0) {\r
       Status = EFI_SUCCESS;\r
     } else {\r
@@ -1035,11 +1182,38 @@ CoreLoadImageCommon (
     if (FilePath == NULL) {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
+\r
+    //\r
+    // Try to get the image device handle by checking the match protocol.\r
+    //\r
+    Node   = NULL;\r
+    Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+    if (!EFI_ERROR (Status)) {\r
+      ImageIsFromFv = TRUE;\r
+    } else {\r
+      HandleFilePath = FilePath;\r
+      Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+      if (EFI_ERROR (Status)) {\r
+        if (!BootPolicy) {\r
+          HandleFilePath = FilePath;\r
+          Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+        }\r
+        if (EFI_ERROR (Status)) {\r
+          HandleFilePath = FilePath;\r
+          Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+          if (!EFI_ERROR (Status)) {\r
+            ImageIsFromLoadFile = TRUE;\r
+            Node = HandleFilePath;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
     //\r
     // Get the source file buffer by its device path.\r
     //\r
     FHand.Source = GetFileBufferByFilePath (\r
-                      BootPolicy, \r
+                      BootPolicy,\r
                       FilePath,\r
                       &FHand.SourceSize,\r
                       &AuthenticationStatus\r
@@ -1047,65 +1221,82 @@ CoreLoadImageCommon (
     if (FHand.Source == NULL) {\r
       Status = EFI_NOT_FOUND;\r
     } else {\r
-      //\r
-      // Try to get the image device handle by checking the match protocol.\r
-      //\r
       FHand.FreeBuffer = TRUE;\r
-      Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
-      if (EFI_ERROR (Status)) {\r
-        HandleFilePath = FilePath;\r
-        Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);\r
-        if (EFI_ERROR (Status)) {\r
-          if (!BootPolicy) {\r
-            HandleFilePath = FilePath;\r
-            Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
-          }\r
-          if (EFI_ERROR (Status)) {\r
-            HandleFilePath = FilePath;\r
-            Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);\r
-          }\r
-        }\r
+      if (ImageIsFromLoadFile) {\r
+        //\r
+        // LoadFile () may cause the device path of the Handle be updated.\r
+        //\r
+        OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);\r
       }\r
     }\r
   }\r
 \r
-  if (Status == EFI_ALREADY_STARTED) {\r
+  if (EFI_ERROR (Status)) {\r
     Image = NULL;\r
     goto Done;\r
-  } else if (EFI_ERROR (Status)) {\r
-    return Status;\r
   }\r
 \r
-  //\r
-  // Verify the Authentication Status through the Security Architectural Protocol\r
-  //\r
-  if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {\r
+  if (gSecurity2 != NULL) {\r
+    //\r
+    // Verify File Authentication through the Security2 Architectural Protocol\r
+    //\r
+    SecurityStatus = gSecurity2->FileAuthentication (\r
+                                  gSecurity2,\r
+                                  OriginalFilePath,\r
+                                  FHand.Source,\r
+                                  FHand.SourceSize,\r
+                                  BootPolicy\r
+                                  );\r
+    if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {\r
+      //\r
+      // When Security2 is installed, Security Architectural Protocol must be published.\r
+      //\r
+      ASSERT (gSecurity != NULL);\r
+\r
+      //\r
+      // Verify the Authentication Status through the Security Architectural Protocol\r
+      // Only on images that have been read using Firmware Volume protocol.\r
+      //\r
+      SecurityStatus = gSecurity->FileAuthenticationState (\r
+                                    gSecurity,\r
+                                    AuthenticationStatus,\r
+                                    OriginalFilePath\r
+                                    );\r
+    }\r
+  } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {\r
+    //\r
+    // Verify the Authentication Status through the Security Architectural Protocol\r
+    //\r
     SecurityStatus = gSecurity->FileAuthenticationState (\r
                                   gSecurity,\r
                                   AuthenticationStatus,\r
                                   OriginalFilePath\r
                                   );\r
-    if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
-      if (SecurityStatus == EFI_ACCESS_DENIED) {\r
-        //\r
-        // Image was not loaded because the platform policy prohibits the image from being loaded.\r
-        // It's the only place we could meet EFI_ACCESS_DENIED.\r
-        //\r
-        *ImageHandle = NULL;\r
-      }\r
-      Status = SecurityStatus;\r
-      Image = NULL;\r
-      goto Done;\r
-    }\r
   }\r
 \r
+  //\r
+  // Check Security Status.\r
+  //\r
+  if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
+    if (SecurityStatus == EFI_ACCESS_DENIED) {\r
+      //\r
+      // Image was not loaded because the platform policy prohibits the image from being loaded.\r
+      // It's the only place we could meet EFI_ACCESS_DENIED.\r
+      //\r
+      *ImageHandle = NULL;\r
+    }\r
+    Status = SecurityStatus;\r
+    Image = NULL;\r
+    goto Done;\r
+  }\r
 \r
   //\r
   // Allocate a new image structure\r
   //\r
   Image = AllocateZeroPool (sizeof(LOADED_IMAGE_PRIVATE_DATA));\r
   if (Image == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
   }\r
 \r
   //\r
@@ -1223,6 +1414,7 @@ CoreLoadImageCommon (
       goto Done;\r
     }\r
   }\r
+  ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);\r
 \r
   //\r
   // Success.  Return the image handle\r
@@ -1237,6 +1429,9 @@ Done:
   if (FHand.FreeBuffer) {\r
     CoreFreePool (FHand.Source);\r
   }\r
+  if (OriginalFilePath != InputFilePath) {\r
+    CoreFreePool (OriginalFilePath);\r
+  }\r
 \r
   //\r
   // There was an error.  If there's an Image structure, free it\r
@@ -1244,11 +1439,19 @@ Done:
   if (EFI_ERROR (Status)) {\r
     if (Image != NULL) {\r
       CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));\r
+      Image = NULL;\r
     }\r
   } else if (EFI_ERROR (SecurityStatus)) {\r
     Status = SecurityStatus;\r
   }\r
 \r
+  //\r
+  // Track the return status from LoadImage.\r
+  //\r
+  if (Image != NULL) {\r
+    Image->LoadImageStatus = Status;\r
+  }\r
+\r
   return Status;\r
 }\r
 \r
@@ -1282,10 +1485,10 @@ Done:
   @retval EFI_LOAD_ERROR          Image was not loaded because the image format was corrupt or not\r
                                   understood.\r
   @retval EFI_DEVICE_ERROR        Image was not loaded because the device returned a read error.\r
-  @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the \r
+  @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the\r
                                   image from being loaded. NULL is returned in *ImageHandle.\r
-  @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a \r
-                                  valid EFI_LOADED_IMAGE_PROTOCOL. However, the current \r
+  @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a\r
+                                  valid EFI_LOADED_IMAGE_PROTOCOL. However, the current\r
                                   platform policy specifies that the image should not be started.\r
 \r
 **/\r
@@ -1301,12 +1504,9 @@ CoreLoadImage (
   )\r
 {\r
   EFI_STATUS    Status;\r
-  UINT64        Tick;\r
+  EFI_HANDLE    Handle;\r
 \r
-  Tick = 0;\r
-  PERF_CODE (\r
-    Tick = GetPerformanceCounter ();\r
-  );\r
+  PERF_LOAD_IMAGE_BEGIN (NULL);\r
 \r
   Status = CoreLoadImageCommon (\r
              BootPolicy,\r
@@ -1321,81 +1521,19 @@ CoreLoadImage (
              EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION\r
              );\r
 \r
-  PERF_START (*ImageHandle, "LoadImage:", NULL, Tick);\r
-  PERF_END (*ImageHandle, "LoadImage:", NULL, 0);\r
-\r
-  return Status;\r
-}\r
-\r
-\r
-\r
-/**\r
-  Loads an EFI image into memory and returns a handle to the image with extended parameters.\r
-\r
-  @param  This                    Calling context\r
-  @param  ParentImageHandle       The caller's image handle.\r
-  @param  FilePath                The specific file path from which the image is\r
-                                  loaded.\r
-  @param  SourceBuffer            If not NULL, a pointer to the memory location\r
-                                  containing a copy of the image to be loaded.\r
-  @param  SourceSize              The size in bytes of SourceBuffer.\r
-  @param  DstBuffer               The buffer to store the image.\r
-  @param  NumberOfPages           For input, specifies the space size of the\r
-                                  image by caller if not NULL. For output,\r
-                                  specifies the actual space size needed.\r
-  @param  ImageHandle             Image handle for output.\r
-  @param  EntryPoint              Image entry point for output.\r
-  @param  Attribute               The bit mask of attributes to set for the load\r
-                                  PE image.\r
+  Handle = NULL;\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // ImageHandle will be valid only Status is success.\r
+    //\r
+    Handle = *ImageHandle;\r
+  }\r
 \r
-  @retval EFI_SUCCESS             The image was loaded into memory.\r
-  @retval EFI_NOT_FOUND           The FilePath was not found.\r
-  @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.\r
-  @retval EFI_UNSUPPORTED         The image type is not supported, or the device\r
-                                  path cannot be parsed to locate the proper\r
-                                  protocol for loading the file.\r
-  @retval EFI_OUT_OF_RESOURCES    Image was not loaded due to insufficient\r
-                                  resources.\r
-  @retval EFI_LOAD_ERROR          Image was not loaded because the image format was corrupt or not\r
-                                  understood.\r
-  @retval EFI_DEVICE_ERROR        Image was not loaded because the device returned a read error.\r
-  @retval EFI_ACCESS_DENIED       Image was not loaded because the platform policy prohibits the \r
-                                  image from being loaded. NULL is returned in *ImageHandle.\r
-  @retval EFI_SECURITY_VIOLATION  Image was loaded and an ImageHandle was created with a \r
-                                  valid EFI_LOADED_IMAGE_PROTOCOL. However, the current \r
-                                  platform policy specifies that the image should not be started.\r
+  PERF_LOAD_IMAGE_END (Handle);\r
 \r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreLoadImageEx (\r
-  IN  EFI_PE32_IMAGE_PROTOCOL          *This,\r
-  IN  EFI_HANDLE                       ParentImageHandle,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL         *FilePath,\r
-  IN  VOID                             *SourceBuffer       OPTIONAL,\r
-  IN  UINTN                            SourceSize,\r
-  IN  EFI_PHYSICAL_ADDRESS             DstBuffer           OPTIONAL,\r
-  OUT UINTN                            *NumberOfPages      OPTIONAL,\r
-  OUT EFI_HANDLE                       *ImageHandle,\r
-  OUT EFI_PHYSICAL_ADDRESS             *EntryPoint         OPTIONAL,\r
-  IN  UINT32                           Attribute\r
-  )\r
-{\r
-  return CoreLoadImageCommon (\r
-           TRUE,\r
-           ParentImageHandle,\r
-           FilePath,\r
-           SourceBuffer,\r
-           SourceSize,\r
-           DstBuffer,\r
-           NumberOfPages,\r
-           ImageHandle,\r
-           EntryPoint,\r
-           Attribute\r
-           );\r
+  return Status;\r
 }\r
 \r
-\r
 /**\r
   Transfer control to a loaded image's entry point.\r
 \r
@@ -1410,6 +1548,7 @@ CoreLoadImageEx (
 \r
   @retval EFI_INVALID_PARAMETER   Invalid parameter\r
   @retval EFI_OUT_OF_RESOURCES    No enough buffer to allocate\r
+  @retval EFI_SECURITY_VIOLATION  The current platform policy specifies that the image should not be started.\r
   @retval EFI_SUCCESS             Successfully transfer control to the image's\r
                                   entry point.\r
 \r
@@ -1427,24 +1566,46 @@ CoreStartImage (
   LOADED_IMAGE_PRIVATE_DATA     *LastImage;\r
   UINT64                        HandleDatabaseKey;\r
   UINTN                         SetJumpFlag;\r
+  EFI_HANDLE                    Handle;\r
+\r
+  Handle = ImageHandle;\r
 \r
   Image = CoreLoadedImageInfo (ImageHandle);\r
   if (Image == NULL  ||  Image->Started) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+  if (EFI_ERROR (Image->LoadImageStatus)) {\r
+    return Image->LoadImageStatus;\r
+  }\r
 \r
   //\r
   // The image to be started must have the machine type supported by DxeCore.\r
   //\r
-  ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine));\r
-  if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine)) {\r
+  if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&\r
+      Image->PeCoffEmu == NULL) {\r
+    //\r
+    // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED\r
+    // But it can not be started.\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName(Image->Machine)));\r
+    DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  //\r
-  // Don't profile Objects or invalid start requests\r
-  //\r
-  PERF_START (ImageHandle, "StartImage:", NULL, 0);\r
+  if (Image->PeCoffEmu != NULL) {\r
+    Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,\r
+                                 Image->ImageBasePage,\r
+                                 EFI_PAGES_TO_SIZE (Image->NumberOfPages),\r
+                                 &Image->EntryPoint);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_LOAD | DEBUG_ERROR,\r
+        "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",\r
+          Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  PERF_START_IMAGE_BEGIN (Handle);\r
 \r
 \r
   //\r
@@ -1464,7 +1625,17 @@ CoreStartImage (
   //\r
   Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
   if (Image->JumpBuffer == NULL) {\r
-    PERF_END (ImageHandle, "StartImage:", NULL, 0);\r
+    //\r
+    // Image may be unloaded after return with failure,\r
+    // then ImageHandle may be invalid, so use NULL handle to record perf log.\r
+    //\r
+    PERF_START_IMAGE_END (NULL);\r
+\r
+    //\r
+    // Pop the current start image context\r
+    //\r
+    mCurrentImage = LastImage;\r
+\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
   Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);\r
@@ -1475,6 +1646,7 @@ CoreStartImage (
   // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().\r
   //\r
   if (SetJumpFlag == 0) {\r
+    RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));\r
     //\r
     // Call the image's entry point\r
     //\r
@@ -1512,9 +1684,17 @@ CoreStartImage (
   mCurrentImage = LastImage;\r
 \r
   //\r
-  // Go connect any handles that were created or modified while the image executed.\r
+  // UEFI Specification - StartImage() - EFI 1.10 Extension\r
+  // To maintain compatibility with UEFI drivers that are written to the EFI\r
+  // 1.02 Specification, StartImage() must monitor the handle database before\r
+  // and after each image is started. If any handles are created or modified\r
+  // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must\r
+  // be called with the Recursive parameter set to TRUE for each of the newly\r
+  // created or modified handles before StartImage() returns.\r
   //\r
-  CoreConnectHandlesByKey (HandleDatabaseKey);\r
+  if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
+    CoreConnectHandlesByKey (HandleDatabaseKey);\r
+  }\r
 \r
   //\r
   // Handle the image's returned ExitData\r
@@ -1555,12 +1735,16 @@ CoreStartImage (
   //\r
   if (EFI_ERROR (Image->Status) || Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
     CoreUnloadAndCloseImage (Image, TRUE);\r
+    //\r
+    // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.\r
+    //\r
+    Handle = NULL;\r
   }\r
 \r
   //\r
   // Done\r
   //\r
-  PERF_END (ImageHandle, "StartImage:", NULL, 0);\r
+  PERF_START_IMAGE_END (Handle);\r
   return Status;\r
 }\r
 \r
@@ -1673,7 +1857,7 @@ Done:
                                   unloaded.\r
 \r
   @retval EFI_SUCCESS             The image has been unloaded.\r
-  @retval EFI_UNSUPPORTED         The image has been sarted, and does not support\r
+  @retval EFI_UNSUPPORTED         The image has been started, and does not support\r
                                   unload.\r
   @retval EFI_INVALID_PARAMPETER  ImageHandle is not a valid image handle.\r
 \r
@@ -1723,26 +1907,3 @@ CoreUnloadImage (
 Done:\r
   return Status;\r
 }\r
-\r
-\r
-\r
-/**\r
-  Unload the specified image.\r
-\r
-  @param  This                    Indicates the calling context.\r
-  @param  ImageHandle             The specified image handle.\r
-\r
-  @retval EFI_INVALID_PARAMETER   Image handle is NULL.\r
-  @retval EFI_UNSUPPORTED         Attempt to unload an unsupported image.\r
-  @retval EFI_SUCCESS             Image successfully unloaded.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-CoreUnloadImageEx (\r
-  IN EFI_PE32_IMAGE_PROTOCOL  *This,\r
-  IN EFI_HANDLE                         ImageHandle\r
-  )\r
-{\r
-  return CoreUnloadImage (ImageHandle);\r
-}\r