|
@@ -0,0 +1,143 @@
|
|
|
+/** @file
|
|
|
+ * PE/COFF emulator protocol implementation to start Linux kernel
|
|
|
+ * images from non-native firmware
|
|
|
+ *
|
|
|
+ * Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
|
|
|
+ *
|
|
|
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <PiDxe.h>
|
|
|
+
|
|
|
+#include <Library/BaseMemoryLib.h>
|
|
|
+#include <Library/DebugLib.h>
|
|
|
+#include <Library/PeCoffLib.h>
|
|
|
+#include <Library/UefiBootServicesTableLib.h>
|
|
|
+
|
|
|
+#include <Protocol/PeCoffImageEmulator.h>
|
|
|
+
|
|
|
+#pragma pack (1)
|
|
|
+typedef struct {
|
|
|
+ UINT8 Type;
|
|
|
+ UINT8 Size;
|
|
|
+ UINT16 MachineType;
|
|
|
+ UINT32 EntryPoint;
|
|
|
+} PE_COMPAT_TYPE1;
|
|
|
+#pragma pack ()
|
|
|
+
|
|
|
+STATIC
|
|
|
+BOOLEAN
|
|
|
+EFIAPI
|
|
|
+IsImageSupported (
|
|
|
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
|
|
|
+ IN UINT16 ImageType,
|
|
|
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
|
|
|
+ )
|
|
|
+{
|
|
|
+ return ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+EFI_IMAGE_ENTRY_POINT
|
|
|
+EFIAPI
|
|
|
+GetCompatEntryPoint (
|
|
|
+ IN EFI_PHYSICAL_ADDRESS ImageBase
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_IMAGE_DOS_HEADER *DosHdr;
|
|
|
+ UINTN PeCoffHeaderOffset;
|
|
|
+ EFI_IMAGE_NT_HEADERS32 *Pe32;
|
|
|
+ EFI_IMAGE_SECTION_HEADER *Section;
|
|
|
+ UINTN NumberOfSections;
|
|
|
+ PE_COMPAT_TYPE1 *PeCompat;
|
|
|
+ UINTN PeCompatEnd;
|
|
|
+
|
|
|
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
|
|
|
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
|
|
|
+ Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageBase + PeCoffHeaderOffset);
|
|
|
+
|
|
|
+ Section = (EFI_IMAGE_SECTION_HEADER *)((UINTN)&Pe32->OptionalHeader +
|
|
|
+ Pe32->FileHeader.SizeOfOptionalHeader);
|
|
|
+ NumberOfSections = (UINTN)Pe32->FileHeader.NumberOfSections;
|
|
|
+
|
|
|
+ while (NumberOfSections--) {
|
|
|
+ if (!CompareMem (Section->Name, ".compat", sizeof (Section->Name))) {
|
|
|
+ //
|
|
|
+ // Dereference the section contents to find the mixed mode entry point
|
|
|
+ //
|
|
|
+ PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)ImageBase + Section->VirtualAddress);
|
|
|
+ PeCompatEnd = (UINTN)(VOID *)PeCompat + Section->Misc.VirtualSize;
|
|
|
+
|
|
|
+ while (PeCompat->Type != 0 && (UINTN)(VOID *)PeCompat < PeCompatEnd) {
|
|
|
+ if (PeCompat->Type == 1 &&
|
|
|
+ PeCompat->Size >= sizeof (PE_COMPAT_TYPE1) &&
|
|
|
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCompat->MachineType)) {
|
|
|
+
|
|
|
+ return (EFI_IMAGE_ENTRY_POINT)((UINTN)ImageBase + PeCompat->EntryPoint);
|
|
|
+ }
|
|
|
+ PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)PeCompat + PeCompat->Size);
|
|
|
+ ASSERT ((UINTN)(VOID *)PeCompat < PeCompatEnd);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Section++;
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+RegisterImage (
|
|
|
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
|
|
|
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
|
|
|
+ IN UINT64 ImageSize,
|
|
|
+ IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
|
|
|
+ )
|
|
|
+{
|
|
|
+ EFI_IMAGE_ENTRY_POINT CompatEntryPoint;
|
|
|
+
|
|
|
+ CompatEntryPoint = GetCompatEntryPoint (ImageBase);
|
|
|
+ if (CompatEntryPoint == NULL) {
|
|
|
+ return EFI_UNSUPPORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ *EntryPoint = CompatEntryPoint;
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+UnregisterImage (
|
|
|
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
|
|
|
+ IN EFI_PHYSICAL_ADDRESS ImageBase
|
|
|
+ )
|
|
|
+{
|
|
|
+ return EFI_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mCompatLoaderPeCoffEmuProtocol = {
|
|
|
+ IsImageSupported,
|
|
|
+ RegisterImage,
|
|
|
+ UnregisterImage,
|
|
|
+ EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
|
|
|
+ EFI_IMAGE_MACHINE_X64
|
|
|
+};
|
|
|
+
|
|
|
+EFI_STATUS
|
|
|
+EFIAPI
|
|
|
+CompatImageLoaderDxeEntryPoint (
|
|
|
+ IN EFI_HANDLE ImageHandle,
|
|
|
+ IN EFI_SYSTEM_TABLE *SystemTable
|
|
|
+ )
|
|
|
+{
|
|
|
+ return gBS->InstallProtocolInterface (&ImageHandle,
|
|
|
+ &gEdkiiPeCoffImageEmulatorProtocolGuid,
|
|
|
+ EFI_NATIVE_INTERFACE,
|
|
|
+ &mCompatLoaderPeCoffEmuProtocol);
|
|
|
+}
|