]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg IA32: add support for loading X64 images
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 26 Feb 2020 19:43:43 +0000 (20:43 +0100)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 4 Mar 2020 09:26:45 +0000 (09:26 +0000)
This is the UEFI counterpart to my Linux series which generalizes
mixed mode support into a feature that requires very little internal
knowledge about the architecture specifics of booting Linux on the
part of the bootloader or firmware.

Instead, we add a .compat PE/COFF header containing an array of
PE_COMPAT nodes containing <machine type, entrypoint> tuples that
describe alternate entrypoints into the image for different native
machine types, e.g., IA-32 in a 64-bit image so it can be booted
from IA-32 firmware.

This patch implements the PE/COFF emulator protocol to take this new
section into account, so that such images can simply be loaded via
LoadImage/StartImage, e.g., straight from the shell.

This feature is based on the EDK2 specific PE/COFF emulator protocol
that was introduced in commit 57df17fe26cd ("MdeModulePkg/DxeCore:
invoke the emulator protocol for foreign images", 2019-04-14).

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2564
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c [new file with mode: 0644]
OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf [new file with mode: 0644]
OvmfPkg/OvmfPkgIa32.dsc
OvmfPkg/OvmfPkgIa32.fdf

diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c
new file mode 100644 (file)
index 0000000..41ddfbc
--- /dev/null
@@ -0,0 +1,143 @@
+/** @file\r
+ *  PE/COFF emulator protocol implementation to start Linux kernel\r
+ *  images from non-native firmware\r
+ *\r
+ *  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
+ *\r
+ *  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+ *\r
+ */\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Protocol/PeCoffImageEmulator.h>\r
+\r
+#pragma pack (1)\r
+typedef struct {\r
+  UINT8   Type;\r
+  UINT8   Size;\r
+  UINT16  MachineType;\r
+  UINT32  EntryPoint;\r
+} PE_COMPAT_TYPE1;\r
+#pragma pack ()\r
+\r
+STATIC\r
+BOOLEAN\r
+EFIAPI\r
+IsImageSupported (\r
+  IN  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL    *This,\r
+  IN  UINT16                                  ImageType,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL                *DevicePath   OPTIONAL\r
+  )\r
+{\r
+  return ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
+}\r
+\r
+STATIC\r
+EFI_IMAGE_ENTRY_POINT\r
+EFIAPI\r
+GetCompatEntryPoint (\r
+  IN  EFI_PHYSICAL_ADDRESS              ImageBase\r
+  )\r
+{\r
+  EFI_IMAGE_DOS_HEADER                  *DosHdr;\r
+  UINTN                                 PeCoffHeaderOffset;\r
+  EFI_IMAGE_NT_HEADERS32                *Pe32;\r
+  EFI_IMAGE_SECTION_HEADER              *Section;\r
+  UINTN                                 NumberOfSections;\r
+  PE_COMPAT_TYPE1                       *PeCompat;\r
+  UINTN                                 PeCompatEnd;\r
+\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;\r
+  if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
+    return NULL;\r
+  }\r
+\r
+  PeCoffHeaderOffset = DosHdr->e_lfanew;\r
+  Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageBase + PeCoffHeaderOffset);\r
+\r
+  Section = (EFI_IMAGE_SECTION_HEADER *)((UINTN)&Pe32->OptionalHeader +\r
+                                         Pe32->FileHeader.SizeOfOptionalHeader);\r
+  NumberOfSections = (UINTN)Pe32->FileHeader.NumberOfSections;\r
+\r
+  while (NumberOfSections--) {\r
+    if (!CompareMem (Section->Name, ".compat", sizeof (Section->Name))) {\r
+      //\r
+      // Dereference the section contents to find the mixed mode entry point\r
+      //\r
+      PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)ImageBase + Section->VirtualAddress);\r
+      PeCompatEnd = (UINTN)(VOID *)PeCompat + Section->Misc.VirtualSize;\r
+\r
+      while (PeCompat->Type != 0 && (UINTN)(VOID *)PeCompat < PeCompatEnd) {\r
+        if (PeCompat->Type == 1 &&\r
+            PeCompat->Size >= sizeof (PE_COMPAT_TYPE1) &&\r
+            EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCompat->MachineType)) {\r
+\r
+          return (EFI_IMAGE_ENTRY_POINT)((UINTN)ImageBase + PeCompat->EntryPoint);\r
+        }\r
+        PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)PeCompat + PeCompat->Size);\r
+        ASSERT ((UINTN)(VOID *)PeCompat < PeCompatEnd);\r
+      }\r
+    }\r
+    Section++;\r
+  }\r
+  return NULL;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterImage (\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
+  EFI_IMAGE_ENTRY_POINT                           CompatEntryPoint;\r
+\r
+  CompatEntryPoint = GetCompatEntryPoint (ImageBase);\r
+  if (CompatEntryPoint == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  *EntryPoint = CompatEntryPoint;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+UnregisterImage (\r
+  IN  EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL    *This,\r
+  IN  EFI_PHYSICAL_ADDRESS                    ImageBase\r
+  )\r
+{\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mCompatLoaderPeCoffEmuProtocol = {\r
+  IsImageSupported,\r
+  RegisterImage,\r
+  UnregisterImage,\r
+  EDKII_PECOFF_IMAGE_EMULATOR_VERSION,\r
+  EFI_IMAGE_MACHINE_X64\r
+};\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+CompatImageLoaderDxeEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  return gBS->InstallProtocolInterface (&ImageHandle,\r
+                &gEdkiiPeCoffImageEmulatorProtocolGuid,\r
+                EFI_NATIVE_INTERFACE,\r
+                &mCompatLoaderPeCoffEmuProtocol);\r
+}\r
diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf
new file mode 100644 (file)
index 0000000..74f06c6
--- /dev/null
@@ -0,0 +1,37 @@
+## @file\r
+#  PE/COFF emulator protocol implementation to start Linux kernel\r
+#  images from non-native firmware\r
+#\r
+#  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
+#\r
+#  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 1.27\r
+  BASE_NAME                      = CompatImageLoaderDxe\r
+  FILE_GUID                      = 1019f54a-2560-41b2-87b0-6750b98f3eff\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = CompatImageLoaderDxeEntryPoint\r
+\r
+[Sources]\r
+  CompatImageLoaderDxe.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  DebugLib\r
+  PeCoffLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+\r
+[Protocols]\r
+  gEdkiiPeCoffImageEmulatorProtocolGuid   ## PRODUCES\r
+\r
+[Depex]\r
+  TRUE\r
index 76e52a3de120cd11a5543a1c335f5b0eb5531767..8d91903f8b4e5eae091204a40c65f06963432276 100644 (file)
@@ -33,6 +33,7 @@
   DEFINE SOURCE_DEBUG_ENABLE     = FALSE\r
   DEFINE TPM2_ENABLE             = FALSE\r
   DEFINE TPM2_CONFIG_ENABLE      = FALSE\r
+  DEFINE LOAD_X64_ON_IA32_ENABLE = FALSE\r
 \r
   #\r
   # Network definition\r
   SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf\r
 !endif\r
 !endif\r
+\r
+!if $(LOAD_X64_ON_IA32_ENABLE) == TRUE\r
+  OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf\r
+!endif\r
index 6c342823d206baa14f209672809a92abc81fd6b6..f57de4a26f9215f008af83af56a9fecb15eb6888 100644 (file)
@@ -354,6 +354,10 @@ INF  SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf
 !endif\r
 !endif\r
 \r
+!if $(LOAD_X64_ON_IA32_ENABLE) == TRUE\r
+INF  OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf\r
+!endif\r
+\r
 ################################################################################\r
 \r
 [FV.FVMAIN_COMPACT]\r