From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by mx.groups.io with SMTP id smtpd.web09.4030.1583244092050122130 for ; Tue, 03 Mar 2020 06:01:32 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@linaro.org header.s=google header.b=OWab0f/7; spf=pass (domain: linaro.org, ip: 209.85.128.67, mailfrom: ard.biesheuvel@linaro.org) Received: by mail-wm1-f67.google.com with SMTP id i9so1914615wml.4 for ; Tue, 03 Mar 2020 06:01:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=e838FAQWhDvX6JzXsV6e48sybVQa6Dc9p2r3uMYdWr4=; b=OWab0f/7ud5EjCE5Mei7jl1RsG9JSC+ZsvsLtk+fG2h7R8fVF8kLyTdZ4BAoT7fbd2 SKi8BV0uIL0SzQ4LwrKAEVD2aJEd5hNj8/Wz1/Mq86/ca5C0O2WLd/LSwfpE+UvvlcvW PCN5DQpf1OnZadZg83ZaMn3Bd4EUjoXmhEwoQ6LBjgZ690U/JCZU0vNAk4P6HlMO4cVo JvIntffZXFaHLnW265Kus3NKBbknQQ64KGuawYSynyY285OerABrD9NHN50wkPUJj7PO rFk72xHqVjSiQzhpksdsE0uwZ7ySD7Nlet9OKGOALFJSiEr/R5PjSKopiV6jnft+kDA2 /CBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=e838FAQWhDvX6JzXsV6e48sybVQa6Dc9p2r3uMYdWr4=; b=kOipL3pGT2H+GBTuC4YlXvkDkKdu1sNvInOZ3JACklS5otfnkG47m8gI4Gt6U2q1s2 ouVo+Np7cfrjqGobq7mpsrfvTWK+cAIKVqz0ypuLDhpsMAGPGtJ5BmUMkXN1+4dv7HZS 0mqDVSwH3Auqby8sHNDBDRF1qC+Vg0XDoCH15HhA6KMW0tJl5nxlW+9pK8+2iUigu+hC W4/VSshJbWazgfxmI4Qfv09JnNmcs8HnzFkpNTqqurKeI8xq5kTd+ovRhd8Cke55OINN XjWmiE3+AnsOHHOU+A+HnTBhLs7e1kD5CISyo19mjEox5LVZpKRHlFF1glXeGB91Jqb0 ERrg== X-Gm-Message-State: ANhLgQ0R9huPJ7dZQ7fFtxbO80jB2yF+8A3JUmJTEV/VFFvOIQ3gdDgj 0Af9WcKyAJ3P6gStbQPoV+aQeY41CFS/Lw== X-Google-Smtp-Source: ADFU+vuU3c9jNq0yEz4RQWcTTse7Dptzc7oJ15qfdZBnkCwHhidkoOd2IVBC2d7wmCtnpwdNWrtnDQ== X-Received: by 2002:a1c:df45:: with SMTP id w66mr4405683wmg.171.1583244090132; Tue, 03 Mar 2020 06:01:30 -0800 (PST) Return-Path: Received: from e123331-lin.home ([2a01:cb1d:112:6f00:816e:ff0d:fb69:f613]) by smtp.gmail.com with ESMTPSA id i10sm27575122wrn.53.2020.03.03.06.01.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2020 06:01:29 -0800 (PST) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: Ard Biesheuvel , lersek@redhat.com, leif@nuviainc.com, Liming Gao Subject: [PATCH v4 6/7] OvmfPkg IA32: add support for loading X64 images Date: Tue, 3 Mar 2020 15:01:16 +0100 Message-Id: <20200303140117.7288-7-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200303140117.7288-1-ard.biesheuvel@linaro.org> References: <20200303140117.7288-1-ard.biesheuvel@linaro.org> 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 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 Acked-by: Laszlo Ersek --- OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c | 143 ++++++++++++++++++++ OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf | 37 +++++ OvmfPkg/OvmfPkgIa32.dsc | 5 + OvmfPkg/OvmfPkgIa32.fdf | 4 + 4 files changed, 189 insertions(+) diff --git a/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c b/OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c new file mode 100644 index 000000000000..ae47917f1589 --- /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.
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + */ + +#include + +#include +#include +#include +#include + +#include + +#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; + VOID *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 = (UINT8 *)PeCompat + Section->Misc.VirtualSize; + + while (PeCompat->Type != 0 && (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 ((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 000000000000..74f06c64bfbf --- /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.
+# +# 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 diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 76e52a3de120..8d91903f8b4e 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -33,6 +33,7 @@ [Defines] DEFINE SOURCE_DEBUG_ENABLE = FALSE DEFINE TPM2_ENABLE = FALSE DEFINE TPM2_CONFIG_ENABLE = FALSE + DEFINE LOAD_X64_ON_IA32_ENABLE = FALSE # # Network definition @@ -932,3 +933,7 @@ [Components] SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf !endif !endif + +!if $(LOAD_X64_ON_IA32_ENABLE) == TRUE + OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf +!endif diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf index 6c342823d206..f57de4a26f92 100644 --- a/OvmfPkg/OvmfPkgIa32.fdf +++ b/OvmfPkg/OvmfPkgIa32.fdf @@ -354,6 +354,10 @@ [FV.DXEFV] !endif !endif +!if $(LOAD_X64_ON_IA32_ENABLE) == TRUE +INF OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf +!endif + ################################################################################ [FV.FVMAIN_COMPACT] -- 2.17.1