MdeModulePkg/EbcDxe: implement the PE/COFF emulator protocol
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Fri, 14 Sep 2018 18:55:36 +0000 (20:55 +0200)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Mon, 15 Apr 2019 01:37:33 +0000 (18:37 -0700)
Implement the new EDK2 PE/COFF image emulator protocol so that we can
remove the EBC specific handling in the DXE core and other places in
the core code.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
MdeModulePkg/Universal/EbcDxe/EbcInt.c
MdeModulePkg/Universal/EbcDxe/EbcInt.h

index 6e634e5..e942317 100644 (file)
@@ -84,6 +84,8 @@
   BaseMemoryLib\r
   DebugLib\r
   BaseLib\r
+  CacheMaintenanceLib\r
+  PeCoffLib\r
 \r
 [Protocols]\r
   gEfiDebugSupportProtocolGuid                  ## PRODUCES\r
@@ -93,6 +95,7 @@
   gEfiEbcSimpleDebuggerProtocolGuid             ## SOMETIMES_CONSUMES\r
   gEfiPciRootBridgeIoProtocolGuid               ## SOMETIMES_CONSUMES\r
   gEfiSimpleFileSystemProtocolGuid              ## SOMETIMES_CONSUMES\r
+  gEdkiiPeCoffImageEmulatorProtocolGuid         ## PRODUCES\r
 \r
 [Guids]\r
   gEfiFileInfoGuid                              ## SOMETIMES_CONSUMES ## GUID\r
index f1b740e..a38700d 100644 (file)
@@ -51,7 +51,9 @@
   MdeModulePkg/MdeModulePkg.dec\r
 \r
 [LibraryClasses]\r
+  CacheMaintenanceLib\r
   MemoryAllocationLib\r
+  PeCoffLib\r
   UefiBootServicesTableLib\r
   BaseMemoryLib\r
   UefiDriverEntryPoint\r
@@ -62,6 +64,7 @@
 [Protocols]\r
   gEfiDebugSupportProtocolGuid                  ## PRODUCES\r
   gEfiEbcProtocolGuid                           ## PRODUCES\r
+  gEdkiiPeCoffImageEmulatorProtocolGuid         ## PRODUCES\r
   gEfiEbcVmTestProtocolGuid                     ## SOMETIMES_PRODUCES\r
   gEfiEbcSimpleDebuggerProtocolGuid             ## SOMETIMES_CONSUMES\r
 \r
index a511e93..eced1d5 100644 (file)
@@ -343,6 +343,119 @@ UINTN                  mStackNum = 0;
 EFI_EVENT              mEbcPeriodicEvent;\r
 VM_CONTEXT             *mVmPtr = NULL;\r
 \r
+/**\r
+  Check whether the emulator supports executing a certain PE/COFF image\r
+\r
+  @param[in] This         This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL\r
+                          structure\r
+  @param[in] ImageType    Whether the image is an application, a boot time\r
+                          driver or a runtime driver.\r
+  @param[in] DevicePath   Path to device where the image originated\r
+                          (e.g., a PCI option ROM)\r
+\r
+  @retval TRUE            The image is supported by the emulator\r
+  @retval FALSE           The image is not supported by the emulator.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+EbcIsImageSupported (\r
+  IN  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL    *This,\r
+  IN  UINT16                                  ImageType,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL                *DevicePath   OPTIONAL\r
+  )\r
+{\r
+  if (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION &&\r
+      ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) {\r
+    return FALSE;\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Register a supported PE/COFF image with the emulator. After this call\r
+  completes successfully, the PE/COFF image may be started as usual, and\r
+  it is the responsibility of the emulator implementation that any branch\r
+  into the code section of the image (including returns from functions called\r
+  from the foreign code) is executed as if it were running on the machine\r
+  type it was built for.\r
+\r
+  @param[in]      This          This pointer for\r
+                                EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure\r
+  @param[in]      ImageBase     The base address in memory of the PE/COFF image\r
+  @param[in]      ImageSize     The size in memory of the PE/COFF image\r
+  @param[in,out]  EntryPoint    The entry point of the PE/COFF image. Passed by\r
+                                reference so that the emulator may modify it.\r
+\r
+  @retval EFI_SUCCESS           The image was registered with the emulator and\r
+                                can be started as usual.\r
+  @retval other                 The image could not be registered.\r
+\r
+  If the PE/COFF machine type or image type are not supported by the emulator,\r
+  then ASSERT().\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EbcRegisterImage (\r
+  IN      EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL    *This,\r
+  IN      EFI_PHYSICAL_ADDRESS                    ImageBase,\r
+  IN      UINT64                                  ImageSize,\r
+  IN  OUT EFI_IMAGE_ENTRY_POINT                   *EntryPoint\r
+  )\r
+{\r
+  DEBUG_CODE_BEGIN ();\r
+    PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;\r
+    EFI_STATUS                    Status;\r
+\r
+    ZeroMem (&ImageContext, sizeof (ImageContext));\r
+\r
+    ImageContext.Handle    = (VOID *)(UINTN)ImageBase;\r
+    ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+    Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC);\r
+    ASSERT (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ||\r
+            ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER);\r
+  DEBUG_CODE_END ();\r
+\r
+  EbcRegisterICacheFlush (NULL,\r
+    (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);\r
+\r
+  return EbcCreateThunk (NULL, (VOID *)(UINTN)ImageBase,\r
+           (VOID *)(UINTN)*EntryPoint, (VOID **)EntryPoint);\r
+}\r
+\r
+/**\r
+  Unregister a PE/COFF image that has been registered with the emulator.\r
+  This should be done before the image is unloaded from memory.\r
+\r
+  @param[in] This         This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL\r
+                          structure\r
+  @param[in] ImageBase    The base address in memory of the PE/COFF image\r
+\r
+  @retval EFI_SUCCESS     The image was unregistered with the emulator.\r
+  @retval other           Image could not be unloaded.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EbcUnregisterImage (\r
+  IN  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL    *This,\r
+  IN  EFI_PHYSICAL_ADDRESS                    ImageBase\r
+  )\r
+{\r
+  return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase);\r
+}\r
+\r
+STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = {\r
+  EbcIsImageSupported,\r
+  EbcRegisterImage,\r
+  EbcUnregisterImage,\r
+  EDKII_PECOFF_IMAGE_EMULATOR_VERSION,\r
+  EFI_IMAGE_MACHINE_EBC\r
+};\r
 \r
 /**\r
   Initializes the VM EFI interface.  Allocates memory for the VM interface\r
@@ -431,11 +544,11 @@ InitializeEbcDriver (
   // Add the protocol so someone can locate us if we haven't already.\r
   //\r
   if (!Installed) {\r
-    Status = gBS->InstallProtocolInterface (\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
                     &ImageHandle,\r
-                    &gEfiEbcProtocolGuid,\r
-                    EFI_NATIVE_INTERFACE,\r
-                    EbcProtocol\r
+                    &gEfiEbcProtocolGuid, EbcProtocol,\r
+                    &gEdkiiPeCoffImageEmulatorProtocolGuid, &mPeCoffEmuProtocol,\r
+                    NULL\r
                     );\r
     if (EFI_ERROR (Status)) {\r
       FreePool (EbcProtocol);\r
index 1cab76c..16f5ed4 100644 (file)
@@ -17,9 +17,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Protocol/Ebc.h>\r
 #include <Protocol/EbcVmTest.h>\r
 #include <Protocol/EbcSimpleDebugger.h>\r
+#include <Protocol/PeCoffImageEmulator.h>\r
 \r
 #include <Library/BaseLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
 #include <Library/DebugLib.h>\r
+#include <Library/PeCoffLib.h>\r
 #include <Library/UefiDriverEntryPoint.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r