From nobody Tue Feb 10 00:59:14 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+55391+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+55391+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1583315577; cv=none; d=zohomail.com; s=zohoarc; b=LDri+3mLgBflljIZqaK4F9tQ/5WUnR1xjllF2+LDmHltbmLiY8gkvH6P/Tp3OlisjI9KOdgwj8KSS1UYPhf1l5oi0gm3HiQOniGvVcVtdRMb36GybMlyP0RUmDRXh9bbmQ34S7zz7rj99IRFlvZ39GQn7IZnO74zg0e8PBvhBfo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1583315577; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=t0bPh+jxq2dAFond7t8OkzWwcm16Ul85UQ1V9A+4D/o=; b=jEAsMLm5bby0Utkw0DYx5FHMi3Ae4AL1blcnseqok69Ni18APnxvxzg4c8MsLbiqRwdrpVDbzhgtAT3Vk+k5YYQvUNqgZYV+SR/bQffipBdmG65f8k7thszQCfxaxliIkNKmEyKw70M4ZORR3/qTS1h8MFPcCIZvyOhGUQGN19w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+55391+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1583315577854987.7706389914704; Wed, 4 Mar 2020 01:52:57 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id 1LWCYY1788612xwSqKXdYeJE; Wed, 04 Mar 2020 01:52:56 -0800 X-Received: from mail-wr1-f65.google.com (mail-wr1-f65.google.com [209.85.221.65]) by mx.groups.io with SMTP id smtpd.web10.9183.1583315575826252510 for ; Wed, 04 Mar 2020 01:52:56 -0800 X-Received: by mail-wr1-f65.google.com with SMTP id r7so1577721wro.2 for ; Wed, 04 Mar 2020 01:52:55 -0800 (PST) X-Gm-Message-State: TKvFf8wL2lIERHpIL1RSKqSqx1787277AA= X-Google-Smtp-Source: ADFU+vtUSXqQoPKvao+FFuLD+3+kHhj3XtBKN+eJ4nav19hg5cstDmmWR0AEJtRjl58ZHEsj3macOA== X-Received: by 2002:adf:f4c9:: with SMTP id h9mr3336638wrp.168.1583315573645; Wed, 04 Mar 2020 01:52:53 -0800 (PST) X-Received: from e123331-lin.home ([2a01:cb1d:112:6f00:816e:ff0d:fb69:f613]) by smtp.gmail.com with ESMTPSA id v16sm20781095wrp.84.2020.03.04.01.52.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 04 Mar 2020 01:52:52 -0800 (PST) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: lersek@redhat.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Date: Wed, 4 Mar 2020 10:52:29 +0100 Message-Id: <20200304095233.21046-11-ard.biesheuvel@linaro.org> In-Reply-To: <20200304095233.21046-1-ard.biesheuvel@linaro.org> References: <20200304095233.21046-1-ard.biesheuvel@linaro.org> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@linaro.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1583315576; bh=QJbdBDwfptuujzIO1DLbC7GKBXxBU7N86tipYzG8iwk=; h=Cc:Content-Type:Date:From:Reply-To:Subject:To; b=c0bXz/LnyUFwpG9kMmQ+Tuh7Seq/Ei9DL56rO+tjQpHqDJHrf9FBI/fkMqqv3VU4+4t TXox9Af13fOgaZsr5/MWYh1x9vKztRInkUn9BlfHfWdFHf5tFntHN5LXoYqsHiOnJdNd5 laMlyBLeLuxLhcPzAKYryy7qzRHeoeoJYrc= X-ZohoMail-DKIM: pass (identity @groups.io) Implement another version of QemuLoadImageLib that uses LoadImage and StartImage, but falls back to the legacy Linux loader code if that fails. The logic in the legacy fallback routines is identical to the current QEMU linux loader for X64 and IA32. Note the use of a LoadedImage pseudo-protocol for the legacy loaded image: this makes it possible to expose the LoadImage/StartImage abstraction for the legacy loader, using the EFI paradigm of identifying loaded image solely by a handle. The pseudo-protocol record type and the use of CR() is to get DEBUG coverage for the code that deals with these handles. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2566 Signed-off-by: Ard Biesheuvel --- OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c | 564 ++++++++= ++++++++++++ OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf | 42 ++ 2 files changed, 606 insertions(+) diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/Ov= mfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c new file mode 100644 index 000000000000..da7a90d9c829 --- /dev/null +++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c @@ -0,0 +1,564 @@ +/** @file + X86 specific implementation of QemuLoadImageLib library class interface + with support for loading mixed mode images and non-EFI stub images + + Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+ Copyright (c) 2020, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack (1) +typedef struct { + EFI_DEVICE_PATH_PROTOCOL FilePathHeader; + CHAR16 FilePath[ARRAY_SIZE (L"kernel")]; +} KERNEL_FILE_DEVPATH; + +typedef struct { + VENDOR_DEVICE_PATH VenMediaNode; + KERNEL_FILE_DEVPATH FileNode; + EFI_DEVICE_PATH_PROTOCOL EndNode; +} KERNEL_VENMEDIA_FILE_DEVPATH; +#pragma pack () + +STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath =3D { + { + { + MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP, + { sizeof (VENDOR_DEVICE_PATH) } + }, + QEMU_KERNEL_LOADER_FS_MEDIA_GUID + }, { + { + MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP, + { sizeof (KERNEL_FILE_DEVPATH) } + }, + L"kernel", + }, { + END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL) } + } +}; + +typedef struct { + VOID *SetupBuf; + VOID *KernelBuf; + CHAR8 *CommandLine; + VOID *InitrdData; + UINTN SetupSize; + UINTN KernelInitialSize; + UINTN InitrdSize; + UINTN CommandLineSize; +} QEMU_LEGACY_LOADED_IMAGE; + +STATIC +VOID +FreeLegacyImage ( + IN QEMU_LEGACY_LOADED_IMAGE *LoadedImage + ) +{ + if (LoadedImage->SetupBuf !=3D NULL) { + FreePages (LoadedImage->SetupBuf, + EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)); + } + if (LoadedImage->KernelBuf !=3D NULL) { + FreePages (LoadedImage->KernelBuf, + EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)); + } + if (LoadedImage->CommandLine !=3D NULL) { + FreePages (LoadedImage->CommandLine, + EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize)); + } + if (LoadedImage->InitrdData !=3D NULL) { + FreePages (LoadedImage->InitrdData, + EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)); + } +} + +STATIC +EFI_STATUS +QemuLoadLegacyImage ( + OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + UINTN KernelSize; + UINTN SetupSize; + QEMU_LEGACY_LOADED_IMAGE *LoadedImage; + + QemuFwCfgSelectItem (QemuFwCfgItemKernelSize); + KernelSize =3D (UINTN)QemuFwCfgRead32 (); + + QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize); + SetupSize =3D (UINTN)QemuFwCfgRead32 (); + + if (KernelSize =3D=3D 0 || SetupSize =3D=3D 0) { + DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n")); + return EFI_NOT_FOUND; + } + + LoadedImage =3D AllocateZeroPool (sizeof (*LoadedImage)); + if (LoadedImage =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + LoadedImage->SetupSize =3D SetupSize; + LoadedImage->SetupBuf =3D LoadLinuxAllocateKernelSetupPages ( + EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)); + if (LoadedImage->SetupBuf =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeImageDesc; + } + + DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize= )); + DEBUG ((DEBUG_INFO, "Reading kernel setup image ...")); + QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData); + QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf); + DEBUG ((DEBUG_INFO, " [done]\n")); + + Status =3D LoadLinuxCheckKernelSetup (LoadedImage->SetupBuf, + LoadedImage->SetupSize); + if (EFI_ERROR (Status)) { + goto FreeImage; + } + + Status =3D LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf); + if (EFI_ERROR (Status)) { + goto FreeImage; + } + + LoadedImage->KernelInitialSize =3D LoadLinuxGetKernelSize ( + LoadedImage->SetupBuf, KernelSize); + if (LoadedImage->KernelInitialSize =3D=3D 0) { + Status =3D EFI_UNSUPPORTED; + goto FreeImage; + } + + LoadedImage->KernelBuf =3D LoadLinuxAllocateKernelPages ( + LoadedImage->SetupBuf, + EFI_SIZE_TO_PAGES (LoadedImage->KernelInitial= Size) + ); + if (LoadedImage->KernelBuf =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n")); + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeImage; + } + + DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize)); + DEBUG ((DEBUG_INFO, "Reading kernel image ...")); + QemuFwCfgSelectItem (QemuFwCfgItemKernelData); + QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf); + DEBUG ((DEBUG_INFO, " [done]\n")); + + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize); + LoadedImage->CommandLineSize =3D (UINTN)QemuFwCfgRead32 (); + + if (LoadedImage->CommandLineSize > 0) { + LoadedImage->CommandLine =3D LoadLinuxAllocateCommandLinePages ( + EFI_SIZE_TO_PAGES ( + LoadedImage->CommandLineSize)); + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData); + QemuFwCfgReadBytes (LoadedImage->CommandLineSize, LoadedImage->Command= Line); + } + + Status =3D LoadLinuxSetCommandLine (LoadedImage->SetupBuf, + LoadedImage->CommandLine); + if (EFI_ERROR (Status)) { + goto FreeImage; + } + + QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize); + LoadedImage->InitrdSize =3D (UINTN)QemuFwCfgRead32 (); + + if (LoadedImage->InitrdSize > 0) { + LoadedImage->InitrdData =3D LoadLinuxAllocateInitrdPages ( + LoadedImage->SetupBuf, + EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize= )); + DEBUG ((DEBUG_INFO, "Initrd size: 0x%x\n", + (UINT32)LoadedImage->InitrdSize)); + DEBUG ((DEBUG_INFO, "Reading initrd image ...")); + QemuFwCfgSelectItem (QemuFwCfgItemInitrdData); + QemuFwCfgReadBytes (LoadedImage->InitrdSize, LoadedImage->InitrdData); + DEBUG ((DEBUG_INFO, " [done]\n")); + } + + Status =3D LoadLinuxSetInitrd (LoadedImage->SetupBuf, LoadedImage->Initr= dData, + LoadedImage->InitrdSize); + if (EFI_ERROR (Status)) { + goto FreeImage; + } + + *ImageHandle =3D NULL; + Status =3D gBS->InstallProtocolInterface (ImageHandle, + &gX86QemuKernelLoadedImageGuid, EFI_NATIVE_INTERFACE, + LoadedImage); + if (EFI_ERROR (Status)) { + goto FreeImage; + } + return EFI_SUCCESS; + +FreeImage: + FreeLegacyImage (LoadedImage); +FreeImageDesc: + FreePool (LoadedImage); + return Status; +} + +STATIC +EFI_STATUS +QemuStartLegacyImage ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + QEMU_LEGACY_LOADED_IMAGE *LoadedImage; + + Status =3D gBS->OpenProtocol (ImageHandle, + &gX86QemuKernelLoadedImageGuid, + (VOID **)&LoadedImage, + gImageHandle, // AgentHandle + NULL, // ControllerHandle + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf); +} + +STATIC +EFI_STATUS +QemuUnloadLegacyImage ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + QEMU_LEGACY_LOADED_IMAGE *LoadedImage; + + Status =3D gBS->OpenProtocol (ImageHandle, + &gX86QemuKernelLoadedImageGuid, + (VOID **)&LoadedImage, + gImageHandle, // AgentHandle + NULL, // ControllerHandle + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + Status =3D gBS->UninstallProtocolInterface (ImageHandle, + &gX86QemuKernelLoadedImageGuid, ImageHandle); + ASSERT_EFI_ERROR (Status); + + FreeLegacyImage (LoadedImage); + FreePool (LoadedImage); + return EFI_SUCCESS; +} + +/** + Download the kernel, the initial ramdisk, and the kernel command line fr= om + QEMU's fw_cfg. The kernel will be instructed via its command line to load + the initrd from the same Simple FileSystem where the kernel was loaded f= rom. + + @param[out] ImageHandle The image handle that was allocated for + loading the image + + @retval EFI_SUCCESS The image was loaded successfully. + @retval EFI_NOT_FOUND Kernel image was not found. + @retval EFI_OUT_OF_RESOURCES Memory allocation failed. + @retval EFI_PROTOCOL_ERROR Unterminated kernel command line. + + @return Error codes from any of the underlying + functions. +**/ +EFI_STATUS +EFIAPI +QemuLoadKernelImage ( + OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE KernelImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage; + UINTN CommandLineSize; + CHAR8 *CommandLine; + UINTN InitrdSize; + + // + // Load the image. This should call back into the QEMU EFI loader file s= ystem. + // + Status =3D gBS->LoadImage ( + FALSE, // BootPolicy: exact match req= uired + gImageHandle, // ParentImageHandle + (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath, + NULL, // SourceBuffer + 0, // SourceSize + &KernelImageHandle + ); + switch (Status) { + case EFI_SUCCESS: + break; + + case EFI_NOT_FOUND: + // + // The image does not exist - no -kernel image was supplied via the + // command line so no point in invoking the legacy fallback + // + return EFI_NOT_FOUND; + + case EFI_SECURITY_VIOLATION: + // + // We are running with UEFI secure boot enabled, and the image failed = to + // authenticate. For compatibility reasons, we fall back to the legacy + // loader in this case. Since the image has been loaded, we need to un= load + // it before proceeding + // + gBS->UnloadImage (KernelImageHandle); + // + // Fall through + // + case EFI_UNSUPPORTED: + // + // The image is not natively supported or cross-type supported. Let's = try + // loading it using the loader that parses the bzImage metadata direct= ly. + // + Status =3D QemuLoadLegacyImage (&KernelImageHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: QemuLoadLegacyImage(): %r\n", __FUNCTION__, + Status)); + return Status; + } + *ImageHandle =3D KernelImageHandle; + return EFI_SUCCESS; + + default: + DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status)); + return Status; + } + + // + // Construct the kernel command line. + // + Status =3D gBS->OpenProtocol ( + KernelImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&KernelLoadedImage, + gImageHandle, // AgentHandle + NULL, // ControllerHandle + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + ASSERT_EFI_ERROR (Status); + + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize); + CommandLineSize =3D (UINTN)QemuFwCfgRead32 (); + + if (CommandLineSize =3D=3D 0) { + KernelLoadedImage->LoadOptionsSize =3D 0; + } else { + CommandLine =3D AllocatePool (CommandLineSize); + ASSERT (CommandLine !=3D NULL); + + QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData); + QemuFwCfgReadBytes (CommandLineSize, CommandLine); + + // + // Verify NUL-termination of the command line. + // + if (CommandLine[CommandLineSize - 1] !=3D '\0') { + DEBUG ((DEBUG_ERROR, "%a: kernel command line is not NUL-terminated\= n", + __FUNCTION__)); + Status =3D EFI_PROTOCOL_ERROR; + goto FreeCommandLine; + } + + // + // Drop the terminating NUL, convert to UTF-16. + // + KernelLoadedImage->LoadOptionsSize =3D (CommandLineSize - 1) * 2; + } + + QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize); + InitrdSize =3D (UINTN) QemuFwCfgRead32 (); + + if (InitrdSize > 0) { + // + // Append ' initrd=3Dinitrd' in UTF-16. + // + KernelLoadedImage->LoadOptionsSize +=3D sizeof (L" initrd=3Dinitrd") -= 2; + } + + if (KernelLoadedImage->LoadOptionsSize =3D=3D 0) { + KernelLoadedImage->LoadOptions =3D NULL; + } else { + // + // NUL-terminate in UTF-16. + // + KernelLoadedImage->LoadOptionsSize +=3D 2; + + KernelLoadedImage->LoadOptions =3D AllocatePool ( + KernelLoadedImage->LoadOptionsSize); + if (KernelLoadedImage->LoadOptions =3D=3D NULL) { + KernelLoadedImage->LoadOptionsSize =3D 0; + Status =3D EFI_OUT_OF_RESOURCES; + goto FreeCommandLine; + } + + UnicodeSPrintAsciiFormat ( + KernelLoadedImage->LoadOptions, + KernelLoadedImage->LoadOptionsSize, + "%a%a", + (CommandLineSize =3D=3D 0) ? "" : CommandLine, + (InitrdSize =3D=3D 0) ? "" : " initrd=3Dinitrd" + ); + DEBUG ((DEBUG_INFO, "%a: command line: \"%s\"\n", __FUNCTION__, + (CHAR16 *)KernelLoadedImage->LoadOptions)); + } + + *ImageHandle =3D KernelImageHandle; + return EFI_SUCCESS; + +FreeCommandLine: + FreePool (CommandLine); + gBS->UnloadImage (KernelImageHandle); + + return Status; +} + +/** + Transfer control to a kernel image loaded with QemuLoadKernelImage () + + @param[in,out] ImageHandle Handle of image to be started. May assum= e a + different value on return if the image w= as + reloaded. + + @retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image h= andle + or the image has already been initialize= d with + StartImage + @retval EFI_SECURITY_VIOLATION The current platform policy specifies th= at the + image should not be started. + + @return Error codes returned by the started image +**/ +EFI_STATUS +EFIAPI +QemuStartKernelImage ( + IN OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + QEMU_LEGACY_LOADED_IMAGE *LoadedImage; + EFI_HANDLE KernelImageHandle; + + Status =3D gBS->OpenProtocol (*ImageHandle, + &gX86QemuKernelLoadedImageGuid, + (VOID **)&LoadedImage, + gImageHandle, // AgentHandle + NULL, // ControllerHandle + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return QemuStartLegacyImage (*ImageHandle); + } + + Status =3D gBS->StartImage ( + *ImageHandle, + NULL, // ExitDataSize + NULL // ExitData + ); +#ifdef MDE_CPU_IA32 + if (Status =3D=3D EFI_UNSUPPORTED) { + // + // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64= while + // we are expecting a IA32 one, and the StartImage () boot service is = unable + // to handle it, either because the image does not have the special .c= ompat + // PE/COFF section that Linux specifies for mixed mode capable images,= or + // because we are running without the support code for that. So unload= the + // image, and reload and start it using the legacy loader. + // + QemuUnloadKernelImage (*ImageHandle); + + Status =3D QemuLoadLegacyImage (&KernelImageHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + *ImageHandle =3D KernelImageHandle; + return QemuStartLegacyImage (KernelImageHandle); + } +#endif + return Status; +} + +/** + Unloads an image loaded with QemuLoadKernelImage (). + + @param ImageHandle Handle that identifies the image to be + unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_UNSUPPORTED The image has been started, and does not + support unload. + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + + @return Exit code from the image=E2=80=99s unloa= d function. +**/ +EFI_STATUS +EFIAPI +QemuUnloadKernelImage ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage; + EFI_STATUS Status; + + Status =3D gBS->OpenProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&KernelLoadedImage, + gImageHandle, // AgentHandle + NULL, // ControllerHandle + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (Status =3D=3D EFI_UNSUPPORTED) { + // + // The handle exists but does not have an instance of the standard loa= ded + // image protocol installed on it. Attempt to unload it as a legacy im= age + // instead. + // + return QemuUnloadLegacyImage (ImageHandle); + } + + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // We are unloading an normal, non-legacy loaded image, either on behalf= of + // an external caller, or called from QemuStartKernelImage() on IA32, wh= ile + // switching from the normal to the legacy method to load and start a X64 + // image. + // + if (KernelLoadedImage->LoadOptions !=3D NULL) { + FreePool (KernelLoadedImage->LoadOptions); + KernelLoadedImage->LoadOptions =3D NULL; + } + KernelLoadedImage->LoadOptionsSize =3D 0; + + return gBS->UnloadImage (ImageHandle); +} diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf b/= OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf new file mode 100644 index 000000000000..1568a02bbd4f --- /dev/null +++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf @@ -0,0 +1,42 @@ +## @file +# X86 specific implementation of QemuLoadImageLib library class interface +# with support for loading mixed mode images and non-EFI stub images +# +# Copyright (c) 2020, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 1.27 + BASE_NAME =3D X86QemuLoadImageLib + FILE_GUID =3D 2304df80-e21d-4170-9c3c-113c878f7ac0 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D QemuLoadImageLib|DXE_DRIVER + +[Sources] + X86QemuLoadImageLib.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + DebugLib + MemoryAllocationLib + LoadLinuxLib + PrintLib + QemuFwCfgLib + ReportStatusCodeLib + UefiBootServicesTableLib + +[Protocols] + gEfiDevicePathProtocolGuid + gEfiLoadedImageProtocolGuid + gX86QemuKernelLoadedImageGuid + +[Guids] + gQemuKernelLoaderFsMediaGuid --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#55391): https://edk2.groups.io/g/devel/message/55391 Mute This Topic: https://groups.io/mt/71722804/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-