]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Core/Dxe/Image/Image.c
MdeModulePkg/DxeCore: invoke the emulator protocol for foreign images
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Image / Image.c
index 4e22aa6dc7e39506a6ae6bc49ab64b70b7100fbb..7ff1dfec5173ff5128895ccbdbbc2952d8a5491d 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
   Core image handling services to load and unload PeImage.\r
 \r
-Copyright (c) 2006 - 2017, 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 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -29,6 +23,15 @@ LOAD_PE32_IMAGE_PRIVATE_DATA  mLoadPe32PrivateData = {
   }\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
@@ -67,13 +70,14 @@ LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage  = {
   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
@@ -108,7 +112,7 @@ GetMachineTypeName (
   )\r
 {\r
   UINTN  Index;\r
-  \r
+\r
   for (Index = 0; Index < sizeof(mMachineTypeInfo)/sizeof(mMachineTypeInfo[0]); Index++) {\r
     if (mMachineTypeInfo[Index].MachineType == MachineType) {\r
       return mMachineTypeInfo[Index].MachineTypeName;\r
@@ -118,6 +122,61 @@ GetMachineTypeName (
   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
+  EMULATOR_ENTRY      *Entry;\r
+\r
+  EmuHandle = 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
+    Entry = AllocateZeroPool (sizeof (*Entry));\r
+    ASSERT (Entry != NULL);\r
+\r
+    Status = CoreHandleProtocol (\r
+               EmuHandle,\r
+               &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
+               (VOID **)&Entry->Emulator\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\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
@@ -138,7 +197,7 @@ CoreInitializeImageServices (
   UINT64                            DxeCoreImageLength;\r
   VOID                              *DxeCoreEntryPoint;\r
   EFI_PEI_HOB_POINTERS              DxeCoreHob;\r
\r
+\r
   //\r
   // Searching for image hob\r
   //\r
@@ -158,7 +217,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
@@ -192,6 +251,30 @@ CoreInitializeImageServices (
   gDxeCoreImageHandle = Image->Handle;\r
   gDxeCoreLoadedImage = &Image->Info;\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
   if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
     //\r
     // Export DXE Core PE Loader functionality for backward compatibility.\r
@@ -263,11 +346,11 @@ CoreReadImageFile (
 /**\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
+  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
@@ -278,23 +361,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
@@ -309,11 +392,11 @@ 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
+   //\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
@@ -321,17 +404,17 @@ CheckAndMarkFixLoadingMemoryUsageBitMap (
        //\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
@@ -358,10 +441,10 @@ 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
@@ -395,36 +478,79 @@ GetPeCoffImageFixLoadingAssignedAddress(
      }\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
+       // 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
+         // 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
          // 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 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
    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
@@ -473,16 +599,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
-      DEBUG ((EFI_D_ERROR, "Image type %s can't be loaded ", GetMachineTypeName(Image->ImageContext.Machine)));\r
-      DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));\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
@@ -541,17 +666,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
+          // 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
+\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
@@ -687,6 +812,16 @@ CoreLoadPeImage (
     if (EFI_ERROR(Status)) {\r
       goto Done;\r
     }\r
+  } else 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.\n"));\r
+      goto Done;\r
+    }\r
   }\r
 \r
   //\r
@@ -874,6 +1009,13 @@ CoreUnloadAndCloseImage (
     Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);\r
   }\r
 \r
+  if (Image->PeCoffEmu != NULL) {\r
+    //\r
+    // If the PE/COFF Emulator protocol exists we must unregister the image.\r
+    //\r
+    Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);\r
+  }\r
+\r
   //\r
   // Unload image, free Image->ImageContext->ModHandle\r
   //\r
@@ -1030,10 +1172,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
@@ -1145,7 +1287,7 @@ CoreLoadImageCommon (
     // 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
@@ -1417,10 +1559,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
@@ -1436,13 +1578,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
@@ -1457,16 +1595,15 @@ CoreLoadImage (
              EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION\r
              );\r
 \r
-  Handle = NULL; \r
+  Handle = NULL;\r
   if (!EFI_ERROR (Status)) {\r
     //\r
-    // ImageHandle will be valid only Status is success. \r
+    // ImageHandle will be valid only Status is success.\r
     //\r
     Handle = *ImageHandle;\r
   }\r
 \r
-  PERF_START (Handle, "LoadImage:", NULL, Tick);\r
-  PERF_END (Handle, "LoadImage:", NULL, 0);\r
+  PERF_LOAD_IMAGE_END (Handle);\r
 \r
   return Status;\r
 }\r
@@ -1503,10 +1640,10 @@ CoreLoadImage (
   @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
@@ -1526,13 +1663,9 @@ CoreLoadImageEx (
   )\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
            TRUE,\r
@@ -1547,16 +1680,15 @@ CoreLoadImageEx (
            Attribute\r
            );\r
 \r
-  Handle = NULL; \r
+  Handle = NULL;\r
   if (!EFI_ERROR (Status)) {\r
     //\r
-    // ImageHandle will be valid only Status is success. \r
+    // ImageHandle will be valid only Status is success.\r
     //\r
     Handle = *ImageHandle;\r
   }\r
 \r
-  PERF_START (Handle, "LoadImage:", NULL, Tick);\r
-  PERF_END (Handle, "LoadImage:", NULL, 0);\r
+  PERF_LOAD_IMAGE_END (Handle);\r
 \r
   return Status;\r
 }\r
@@ -1594,10 +1726,8 @@ CoreStartImage (
   LOADED_IMAGE_PRIVATE_DATA     *LastImage;\r
   UINT64                        HandleDatabaseKey;\r
   UINTN                         SetJumpFlag;\r
-  UINT64                        Tick;\r
   EFI_HANDLE                    Handle;\r
 \r
-  Tick = 0;\r
   Handle = ImageHandle;\r
 \r
   Image = CoreLoadedImageInfo (ImageHandle);\r
@@ -1611,7 +1741,8 @@ CoreStartImage (
   //\r
   // The image to be started must have the machine type supported by DxeCore.\r
   //\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
@@ -1621,9 +1752,7 @@ CoreStartImage (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  PERF_CODE (\r
-    Tick = GetPerformanceCounter ();\r
-  );\r
+  PERF_START_IMAGE_BEGIN (Handle);\r
 \r
 \r
   //\r
@@ -1647,8 +1776,7 @@ CoreStartImage (
     // 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 (NULL, "StartImage:", NULL, Tick);\r
-    PERF_END (NULL, "StartImage:", NULL, 0);\r
+    PERF_START_IMAGE_END (NULL);\r
 \r
     //\r
     // Pop the current start image context\r
@@ -1703,9 +1831,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
@@ -1755,8 +1891,7 @@ CoreStartImage (
   //\r
   // Done\r
   //\r
-  PERF_START (Handle, "StartImage:", NULL, Tick);\r
-  PERF_END (Handle, "StartImage:", NULL, 0);\r
+  PERF_START_IMAGE_END (Handle);\r
   return Status;\r
 }\r
 \r