mirror of https://github.com/acidanthera/audk.git
OvmfPkg: provide a generic implementation of QemuLoadImageLib
Implement QemuLoadImageLib, and make it load the image provided by the QEMU_EFI_LOADER_FS_MEDIA_GUID/kernel device path that we implemented in a preceding patch in a separate DXE driver, using only the standard LoadImage and StartImage boot services. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
parent
28de1a5550
commit
ddd2be6b00
|
@ -0,0 +1,276 @@
|
|||
/** @file
|
||||
Generic implementation of QemuLoadImageLib library class interface.
|
||||
|
||||
Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <Base.h>
|
||||
#include <Guid/QemuKernelLoaderFsMedia.h>
|
||||
#include <Library/DebugLib.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>
|
||||
|
||||
#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) }
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
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.
|
||||
@retval EFI_ACCESS_DENIED The underlying LoadImage boot service call
|
||||
returned EFI_SECURITY_VIOLATION, and the image
|
||||
was unloaded again.
|
||||
|
||||
@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_SECURITY_VIOLATION:
|
||||
//
|
||||
// In this case, the image was loaded but failed to authenticate.
|
||||
//
|
||||
Status = EFI_ACCESS_DENIED;
|
||||
goto UnloadImage;
|
||||
|
||||
default:
|
||||
DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, 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",
|
||||
__FUNCTION__));
|
||||
Status = EFI_PROTOCOL_ERROR;
|
||||
goto FreeCommandLine;
|
||||
}
|
||||
|
||||
//
|
||||
// Drop the terminating NUL, convert to UTF-16.
|
||||
//
|
||||
KernelLoadedImage->LoadOptionsSize = (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", __FUNCTION__,
|
||||
(CHAR16 *)KernelLoadedImage->LoadOptions));
|
||||
}
|
||||
|
||||
*ImageHandle = KernelImageHandle;
|
||||
return EFI_SUCCESS;
|
||||
|
||||
FreeCommandLine:
|
||||
if (CommandLineSize > 0) {
|
||||
FreePool (CommandLine);
|
||||
}
|
||||
UnloadImage:
|
||||
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
|
||||
)
|
||||
{
|
||||
return gBS->StartImage (
|
||||
*ImageHandle,
|
||||
NULL, // ExitDataSize
|
||||
NULL // ExitData
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
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 (EFI_ERROR (Status)) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (KernelLoadedImage->LoadOptions != NULL) {
|
||||
FreePool (KernelLoadedImage->LoadOptions);
|
||||
KernelLoadedImage->LoadOptions = NULL;
|
||||
}
|
||||
KernelLoadedImage->LoadOptionsSize = 0;
|
||||
|
||||
return gBS->UnloadImage (ImageHandle);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
## @file
|
||||
# Generic implementation of QemuLoadImageLib library class interface.
|
||||
#
|
||||
# Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 1.27
|
||||
BASE_NAME = GenericQemuLoadImageLib
|
||||
FILE_GUID = 9e3e28da-c7b5-4f85-841a-84e6a9a1f1a0
|
||||
MODULE_TYPE = BASE
|
||||
VERSION_STRING = 1.0
|
||||
LIBRARY_CLASS = QemuLoadImageLib|DXE_DRIVER
|
||||
|
||||
[Sources]
|
||||
GenericQemuLoadImageLib.c
|
||||
|
||||
[Packages]
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
MdePkg/MdePkg.dec
|
||||
OvmfPkg/OvmfPkg.dec
|
||||
|
||||
[LibraryClasses]
|
||||
DebugLib
|
||||
MemoryAllocationLib
|
||||
PrintLib
|
||||
QemuFwCfgLib
|
||||
UefiBootServicesTableLib
|
||||
|
||||
[Protocols]
|
||||
gEfiDevicePathProtocolGuid
|
||||
gEfiLoadedImageProtocolGuid
|
||||
|
||||
[Guids]
|
||||
gQemuKernelLoaderFsMediaGuid
|
Loading…
Reference in New Issue