mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-01 12:53:27 +01:00
643 lines
20 KiB
C
643 lines
20 KiB
C
/** @file
|
|
X86 specific implementation of QemuLoadImageLib library class interface
|
|
with support for loading mixed mode images and non-EFI stub images
|
|
|
|
Note that this implementation reads the cmdline (and possibly kernel, setup
|
|
data, and initrd in the legacy boot mode) from fw_cfg directly.
|
|
|
|
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
|
|
Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Uefi.h>
|
|
|
|
#include <Guid/QemuKernelLoaderFsMedia.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/LoadLinuxLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/QemuFwCfgLib.h>
|
|
#include <Library/QemuLoadImageLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Protocol/DevicePath.h>
|
|
#include <Protocol/LoadedImage.h>
|
|
#include <Protocol/OvmfLoadedX86LinuxKernel.h>
|
|
|
|
#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 = {
|
|
{
|
|
{
|
|
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) }
|
|
}
|
|
};
|
|
|
|
STATIC
|
|
VOID
|
|
FreeLegacyImage (
|
|
IN OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage
|
|
)
|
|
{
|
|
if (LoadedImage->SetupBuf != NULL) {
|
|
FreePages (
|
|
LoadedImage->SetupBuf,
|
|
EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)
|
|
);
|
|
}
|
|
|
|
if (LoadedImage->KernelBuf != NULL) {
|
|
FreePages (
|
|
LoadedImage->KernelBuf,
|
|
EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
|
|
);
|
|
}
|
|
|
|
if (LoadedImage->CommandLine != NULL) {
|
|
FreePages (
|
|
LoadedImage->CommandLine,
|
|
EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize)
|
|
);
|
|
}
|
|
|
|
if (LoadedImage->InitrdData != 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;
|
|
OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
|
|
KernelSize = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
|
|
SetupSize = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
if ((KernelSize == 0) || (SetupSize == 0)) {
|
|
DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));
|
|
if (LoadedImage == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
LoadedImage->SetupSize = SetupSize;
|
|
LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (
|
|
EFI_SIZE_TO_PAGES (LoadedImage->SetupSize)
|
|
);
|
|
if (LoadedImage->SetupBuf == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));
|
|
Status = 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 = LoadLinuxCheckKernelSetup (
|
|
LoadedImage->SetupBuf,
|
|
LoadedImage->SetupSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeImage;
|
|
}
|
|
|
|
Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeImage;
|
|
}
|
|
|
|
LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (
|
|
LoadedImage->SetupBuf,
|
|
KernelSize
|
|
);
|
|
if (LoadedImage->KernelInitialSize == 0) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto FreeImage;
|
|
}
|
|
|
|
LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (
|
|
LoadedImage->SetupBuf,
|
|
EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
|
|
);
|
|
if (LoadedImage->KernelBuf == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));
|
|
Status = 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 = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
if (LoadedImage->CommandLineSize > 0) {
|
|
LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (
|
|
EFI_SIZE_TO_PAGES (
|
|
LoadedImage->CommandLineSize
|
|
)
|
|
);
|
|
if (LoadedImage->CommandLine == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel command line!\n"));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto FreeImage;
|
|
}
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
|
|
QemuFwCfgReadBytes (LoadedImage->CommandLineSize, LoadedImage->CommandLine);
|
|
}
|
|
|
|
Status = LoadLinuxSetCommandLine (
|
|
LoadedImage->SetupBuf,
|
|
LoadedImage->CommandLine
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeImage;
|
|
}
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
|
|
LoadedImage->InitrdSize = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
if (LoadedImage->InitrdSize > 0) {
|
|
LoadedImage->InitrdData = LoadLinuxAllocateInitrdPages (
|
|
LoadedImage->SetupBuf,
|
|
EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize)
|
|
);
|
|
if (LoadedImage->InitrdData == NULL) {
|
|
DEBUG ((DEBUG_ERROR, "Unable to allocate memory for initrd!\n"));
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto FreeImage;
|
|
}
|
|
|
|
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 = LoadLinuxSetInitrd (
|
|
LoadedImage->SetupBuf,
|
|
LoadedImage->InitrdData,
|
|
LoadedImage->InitrdSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto FreeImage;
|
|
}
|
|
|
|
*ImageHandle = NULL;
|
|
Status = gBS->InstallProtocolInterface (
|
|
ImageHandle,
|
|
&gOvmfLoadedX86LinuxKernelProtocolGuid,
|
|
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;
|
|
OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ImageHandle,
|
|
&gOvmfLoadedX86LinuxKernelProtocolGuid,
|
|
(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;
|
|
OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ImageHandle,
|
|
&gOvmfLoadedX86LinuxKernelProtocolGuid,
|
|
(VOID **)&LoadedImage,
|
|
gImageHandle, // AgentHandle
|
|
NULL, // ControllerHandle
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = gBS->UninstallProtocolInterface (
|
|
ImageHandle,
|
|
&gOvmfLoadedX86LinuxKernelProtocolGuid,
|
|
LoadedImage
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
FreeLegacyImage (LoadedImage);
|
|
FreePool (LoadedImage);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Download the kernel, the initial ramdisk, and the kernel command line from
|
|
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 from.
|
|
|
|
@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 system.
|
|
//
|
|
Status = gBS->LoadImage (
|
|
FALSE, // BootPolicy: exact match required
|
|
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:
|
|
//
|
|
// Since the image has been loaded, we need to unload it before proceeding
|
|
// to the EFI_ACCESS_DENIED case below.
|
|
//
|
|
gBS->UnloadImage (KernelImageHandle);
|
|
//
|
|
// Fall through
|
|
//
|
|
case EFI_ACCESS_DENIED:
|
|
//
|
|
// 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.
|
|
//
|
|
// 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 directly.
|
|
//
|
|
Status = QemuLoadLegacyImage (&KernelImageHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: QemuLoadLegacyImage(): %r\n",
|
|
__func__,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
|
|
*ImageHandle = KernelImageHandle;
|
|
return EFI_SUCCESS;
|
|
|
|
default:
|
|
DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __func__, Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Construct the kernel command line.
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
KernelImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **)&KernelLoadedImage,
|
|
gImageHandle, // AgentHandle
|
|
NULL, // ControllerHandle
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
|
|
CommandLineSize = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
if (CommandLineSize == 0) {
|
|
KernelLoadedImage->LoadOptionsSize = 0;
|
|
} else {
|
|
CommandLine = AllocatePool (CommandLineSize);
|
|
if (CommandLine == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto UnloadImage;
|
|
}
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
|
|
QemuFwCfgReadBytes (CommandLineSize, CommandLine);
|
|
|
|
//
|
|
// Verify NUL-termination of the command line.
|
|
//
|
|
if (CommandLine[CommandLineSize - 1] != '\0') {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: kernel command line is not NUL-terminated\n",
|
|
__func__
|
|
));
|
|
Status = EFI_PROTOCOL_ERROR;
|
|
goto FreeCommandLine;
|
|
}
|
|
|
|
//
|
|
// Drop the terminating NUL, convert to UTF-16.
|
|
//
|
|
KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);
|
|
}
|
|
|
|
QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
|
|
InitrdSize = (UINTN)QemuFwCfgRead32 ();
|
|
|
|
if (InitrdSize > 0) {
|
|
//
|
|
// Append ' initrd=initrd' in UTF-16.
|
|
//
|
|
KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;
|
|
}
|
|
|
|
if (KernelLoadedImage->LoadOptionsSize == 0) {
|
|
KernelLoadedImage->LoadOptions = NULL;
|
|
} else {
|
|
//
|
|
// NUL-terminate in UTF-16.
|
|
//
|
|
KernelLoadedImage->LoadOptionsSize += 2;
|
|
|
|
KernelLoadedImage->LoadOptions = AllocatePool (
|
|
KernelLoadedImage->LoadOptionsSize
|
|
);
|
|
if (KernelLoadedImage->LoadOptions == NULL) {
|
|
KernelLoadedImage->LoadOptionsSize = 0;
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto FreeCommandLine;
|
|
}
|
|
|
|
UnicodeSPrintAsciiFormat (
|
|
KernelLoadedImage->LoadOptions,
|
|
KernelLoadedImage->LoadOptionsSize,
|
|
"%a%a",
|
|
(CommandLineSize == 0) ? "" : CommandLine,
|
|
(InitrdSize == 0) ? "" : " initrd=initrd"
|
|
);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: command line: \"%s\"\n",
|
|
__func__,
|
|
(CHAR16 *)KernelLoadedImage->LoadOptions
|
|
));
|
|
}
|
|
|
|
*ImageHandle = KernelImageHandle;
|
|
Status = EFI_SUCCESS;
|
|
|
|
FreeCommandLine:
|
|
if (CommandLineSize > 0) {
|
|
FreePool (CommandLine);
|
|
}
|
|
|
|
UnloadImage:
|
|
if (EFI_ERROR (Status)) {
|
|
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 assume a
|
|
different value on return if the image was
|
|
reloaded.
|
|
|
|
@retval EFI_INVALID_PARAMETER ImageHandle is either an invalid image handle
|
|
or the image has already been initialized with
|
|
StartImage
|
|
@retval EFI_SECURITY_VIOLATION The current platform policy specifies that 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;
|
|
OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
*ImageHandle,
|
|
&gOvmfLoadedX86LinuxKernelProtocolGuid,
|
|
(VOID **)&LoadedImage,
|
|
gImageHandle, // AgentHandle
|
|
NULL, // ControllerHandle
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
return QemuStartLegacyImage (*ImageHandle);
|
|
}
|
|
|
|
Status = gBS->StartImage (
|
|
*ImageHandle,
|
|
NULL, // ExitDataSize
|
|
NULL // ExitData
|
|
);
|
|
#ifdef MDE_CPU_IA32
|
|
if (Status == EFI_UNSUPPORTED) {
|
|
EFI_HANDLE KernelImageHandle;
|
|
|
|
//
|
|
// 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 .compat
|
|
// PE/COFF section that Linux specifies for mixed mode capable images, or
|
|
// because we are running without the support code for that. So load the
|
|
// image again, using the legacy loader, and unload the normally loaded
|
|
// image before starting the legacy one.
|
|
//
|
|
Status = QemuLoadLegacyImage (&KernelImageHandle);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Note: no change to (*ImageHandle), the caller will release it.
|
|
//
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Swap in the legacy-loaded image.
|
|
//
|
|
QemuUnloadKernelImage (*ImageHandle);
|
|
*ImageHandle = 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's unload function.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
QemuUnloadKernelImage (
|
|
IN EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
|
|
EFI_STATUS Status;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
ImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID **)&KernelLoadedImage,
|
|
gImageHandle, // AgentHandle
|
|
NULL, // ControllerHandle
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (Status == EFI_UNSUPPORTED) {
|
|
//
|
|
// The handle exists but does not have an instance of the standard loaded
|
|
// image protocol installed on it. Attempt to unload it as a legacy image
|
|
// instead.
|
|
//
|
|
return QemuUnloadLegacyImage (ImageHandle);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// We are unloading a normal, non-legacy loaded image, either on behalf of
|
|
// an external caller, or called from QemuStartKernelImage() on IA32, while
|
|
// switching from the normal to the legacy method to load and start a X64
|
|
// image.
|
|
//
|
|
if (KernelLoadedImage->LoadOptions != NULL) {
|
|
FreePool (KernelLoadedImage->LoadOptions);
|
|
KernelLoadedImage->LoadOptions = NULL;
|
|
}
|
|
|
|
KernelLoadedImage->LoadOptionsSize = 0;
|
|
|
|
return gBS->UnloadImage (ImageHandle);
|
|
}
|