diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2020-02-26 20:43:43 +0100 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2020-03-04 09:26:45 +0000 |
commit | d55cfdc51f93b6622c3780d4cc2ba2769c154a15 (patch) | |
tree | c953daedf7f7a0923521b14747b3fc94afb7a820 /OvmfPkg/CompatImageLoaderDxe | |
parent | d8dd54f071cfd60a2dcf5426764a89cd91213420 (diff) | |
download | edk2-d55cfdc51f93b6622c3780d4cc2ba2769c154a15.tar.gz edk2-d55cfdc51f93b6622c3780d4cc2ba2769c154a15.tar.bz2 edk2-d55cfdc51f93b6622c3780d4cc2ba2769c154a15.zip |
OvmfPkg IA32: add support for loading X64 images
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>
Diffstat (limited to 'OvmfPkg/CompatImageLoaderDxe')
-rw-r--r-- | OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c | 143 | ||||
-rw-r--r-- | OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf | 37 |
2 files changed, 180 insertions, 0 deletions
diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c new file mode 100644 index 0000000000..41ddfbc517 --- /dev/null +++ b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c @@ -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);
+}
diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf new file mode 100644 index 0000000000..74f06c64bf --- /dev/null +++ b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf @@ -0,0 +1,37 @@ +## @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
+#
+##
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = CompatImageLoaderDxe
+ FILE_GUID = 1019f54a-2560-41b2-87b0-6750b98f3eff
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CompatImageLoaderDxeEntryPoint
+
+[Sources]
+ CompatImageLoaderDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ PeCoffLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
|