}\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
NULL, // JumpContext\r
0, // Machine\r
NULL, // Ebc\r
+ NULL, // PeCoffEmu\r
NULL, // RuntimeData\r
NULL // LoadedImageDevicePath\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
+ 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
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
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
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
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
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
//\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