summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-03-10 16:50:55 +0100
committerArd Biesheuvel <ard.biesheuvel@linaro.org>2019-04-14 18:37:12 -0700
commit57df17fe26cd2b25c4c463edf3a3d8b83263f51b (patch)
treec0f6bc1d6023ff3055dcf99ed9b2e41b9b02dc5c
parentf72f81777b399ad23b8c1d0d13b3ca4b91104da1 (diff)
downloadedk2-57df17fe26cd2b25c4c463edf3a3d8b83263f51b.tar.gz
edk2-57df17fe26cd2b25c4c463edf3a3d8b83263f51b.tar.bz2
edk2-57df17fe26cd2b25c4c463edf3a3d8b83263f51b.zip
MdeModulePkg/DxeCore: invoke the emulator protocol for foreign images
When encountering PE/COFF images that cannot be supported natively, attempt to locate an instance of the PE/COFF image emulator protocol, and if it supports the image, proceed with loading it and register it with the emulator. 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>
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.h3
-rw-r--r--MdeModulePkg/Core/Dxe/DxeMain.inf1
-rw-r--r--MdeModulePkg/Core/Dxe/Image/Image.c171
3 files changed, 164 insertions, 11 deletions
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.h b/MdeModulePkg/Core/Dxe/DxeMain.h
index 966c2857af..bbb424bdb0 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.h
+++ b/MdeModulePkg/Core/Dxe/DxeMain.h
@@ -47,6 +47,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Protocol/TcgService.h>
#include <Protocol/HiiPackageList.h>
#include <Protocol/SmmBase2.h>
+#include <Protocol/PeCoffImageEmulator.h>
#include <Guid/MemoryTypeInformation.h>
#include <Guid/FirmwareFileSystem2.h>
#include <Guid/FirmwareFileSystem3.h>
@@ -222,6 +223,8 @@ typedef struct {
UINT16 Machine;
/// EBC Protocol pointer
EFI_EBC_PROTOCOL *Ebc;
+ /// PE/COFF Image Emulator Protocol pointer
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *PeCoffEmu;
/// Runtime image list
EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
/// Pointer to Loaded Image Device Path Protocol
diff --git a/MdeModulePkg/Core/Dxe/DxeMain.inf b/MdeModulePkg/Core/Dxe/DxeMain.inf
index 113b09a4f3..d4b3912b5e 100644
--- a/MdeModulePkg/Core/Dxe/DxeMain.inf
+++ b/MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -156,6 +156,7 @@
gEfiHiiPackageListProtocolGuid ## SOMETIMES_PRODUCES
gEfiEbcProtocolGuid ## SOMETIMES_CONSUMES
gEfiSmmBase2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## SOMETIMES_CONSUMES
# Arch Protocols
gEfiBdsArchProtocolGuid ## CONSUMES
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c
index 0d0ba5be85..7ff1dfec51 100644
--- a/MdeModulePkg/Core/Dxe/Image/Image.c
+++ b/MdeModulePkg/Core/Dxe/Image/Image.c
@@ -23,6 +23,15 @@ LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = {
}
};
+typedef struct {
+ LIST_ENTRY Link;
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
+ UINT16 MachineType;
+} EMULATOR_ENTRY;
+
+STATIC LIST_ENTRY mAvailableEmulators;
+STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
+STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
//
// This code is needed to build the Image handle for the DXE Core
@@ -61,6 +70,7 @@ LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
NULL, // JumpContext
0, // Machine
NULL, // Ebc
+ NULL, // PeCoffEmu
NULL, // RuntimeData
NULL // LoadedImageDevicePath
};
@@ -113,6 +123,61 @@ GetMachineTypeName (
}
/**
+ Notification event handler registered by CoreInitializeImageServices () to
+ keep track of which PE/COFF image emulators are available.
+
+ @param Event The Event that is being processed, not used.
+ @param Context Event Context, not used.
+
+**/
+STATIC
+VOID
+EFIAPI
+PeCoffEmuProtocolNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE EmuHandle;
+ EMULATOR_ENTRY *Entry;
+
+ EmuHandle = NULL;
+
+ while (TRUE) {
+ BufferSize = sizeof (EmuHandle);
+ Status = CoreLocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mPeCoffEmuProtocolNotifyRegistration,
+ &BufferSize,
+ &EmuHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exit
+ //
+ return;
+ }
+
+ Entry = AllocateZeroPool (sizeof (*Entry));
+ ASSERT (Entry != NULL);
+
+ Status = CoreHandleProtocol (
+ EmuHandle,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ (VOID **)&Entry->Emulator
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Entry->MachineType = Entry->Emulator->MachineType;
+
+ InsertTailList (&mAvailableEmulators, &Entry->Link);
+ }
+}
+
+/**
Add the Image Services to EFI Boot Services Table and install the protocol
interfaces for this image.
@@ -186,6 +251,30 @@ CoreInitializeImageServices (
gDxeCoreImageHandle = Image->Handle;
gDxeCoreLoadedImage = &Image->Info;
+ //
+ // Create the PE/COFF emulator protocol registration event
+ //
+ Status = CoreCreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ PeCoffEmuProtocolNotify,
+ NULL,
+ &mPeCoffEmuProtocolRegistrationEvent
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = CoreRegisterProtocolNotify (
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
+ mPeCoffEmuProtocolRegistrationEvent,
+ &mPeCoffEmuProtocolNotifyRegistration
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ InitializeListHead (&mAvailableEmulators);
+
if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
//
// Export DXE Core PE Loader functionality for backward compatibility.
@@ -419,6 +508,49 @@ GetPeCoffImageFixLoadingAssignedAddress(
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));
return Status;
}
+
+/**
+ Decides whether a PE/COFF image can execute on this system, either natively
+ or via emulation/interpretation. In the latter case, the PeCoffEmu member
+ of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
+ to the emulator protocol that supports this image.
+
+ @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
+
+ @retval TRUE The image is supported
+ @retval FALSE The image is not supported
+
+**/
+STATIC
+BOOLEAN
+CoreIsImageTypeSupported (
+ IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
+ )
+{
+ LIST_ENTRY *Link;
+ EMULATOR_ENTRY *Entry;
+
+ for (Link = GetFirstNode (&mAvailableEmulators);
+ !IsNull (&mAvailableEmulators, Link);
+ Link = GetNextNode (&mAvailableEmulators, Link)) {
+
+ Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
+ if (Entry->MachineType != Image->ImageContext.Machine) {
+ continue;
+ }
+
+ if (Entry->Emulator->IsImageSupported (Entry->Emulator,
+ Image->ImageContext.ImageType,
+ Image->Info.FilePath)) {
+ Image->PeCoffEmu = Entry->Emulator;
+ return TRUE;
+ }
+ }
+
+ return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
+ EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
+}
+
/**
Loads, relocates, and invokes a PE/COFF image
@@ -467,16 +599,15 @@ CoreLoadPeImage (
return Status;
}
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
- if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
- //
- // The PE/COFF loader can support loading image types that can be executed.
- // If we loaded an image type that we can not execute return EFI_UNSUPORTED.
- //
- DEBUG ((EFI_D_ERROR, "Image type %s can't be loaded ", GetMachineTypeName(Image->ImageContext.Machine)));
- DEBUG ((EFI_D_ERROR, "on %s UEFI system.\n", GetMachineTypeName(mDxeCoreImageMachineType)));
- return EFI_UNSUPPORTED;
- }
+ if (!CoreIsImageTypeSupported (Image)) {
+ //
+ // The PE/COFF loader can support loading image types that can be executed.
+ // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
+ //
+ DEBUG ((DEBUG_ERROR, "Image type %s can't be loaded on %s UEFI system.\n",
+ GetMachineTypeName (Image->ImageContext.Machine),
+ GetMachineTypeName (mDxeCoreImageMachineType)));
+ return EFI_UNSUPPORTED;
}
//
@@ -681,6 +812,16 @@ CoreLoadPeImage (
if (EFI_ERROR(Status)) {
goto Done;
}
+ } else if (Image->PeCoffEmu != NULL) {
+ Status = Image->PeCoffEmu->RegisterImage (Image->PeCoffEmu,
+ Image->ImageBasePage,
+ EFI_PAGES_TO_SIZE (Image->NumberOfPages),
+ &Image->EntryPoint);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_LOAD | DEBUG_ERROR,
+ "CoreLoadPeImage: Failed to register foreign image with emulator.\n"));
+ goto Done;
+ }
}
//
@@ -868,6 +1009,13 @@ CoreUnloadAndCloseImage (
Image->Ebc->UnloadImage (Image->Ebc, Image->Handle);
}
+ if (Image->PeCoffEmu != NULL) {
+ //
+ // If the PE/COFF Emulator protocol exists we must unregister the image.
+ //
+ Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
+ }
+
//
// Unload image, free Image->ImageContext->ModHandle
//
@@ -1593,7 +1741,8 @@ CoreStartImage (
//
// The image to be started must have the machine type supported by DxeCore.
//
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine)) {
+ if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
+ Image->PeCoffEmu == NULL) {
//
// Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
// But it can not be started.