[PATCH v3 4/5] OvmfPkg/GenericQemuLoadImageLib: Read cmdline from QemuKernelLoaderFs


Dov Murik
 

Remove the QemuFwCfgLib interface used to read the QEMU cmdline
(-append argument) and the initrd size. Instead, use the synthetic
filesystem QemuKernelLoaderFs which has three files: "kernel", "initrd",
and "cmdline".

Cc: Laszlo Ersek <lersek@...>
Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: James Bottomley <jejb@...>
Cc: Tobin Feldman-Fitzthum <tobin@...>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3457
Signed-off-by: Dov Murik <dovmurik@...>
---
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf | 3 =
+-
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c | 151 =
++++++++++++++++++--
2 files changed, 139 insertions(+), 15 deletions(-)

diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLi=
b.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
index b262cb926a4d..9c9e35b1c5b9 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
@@ -25,14 +25,15 @@ [Packages]
=0D
[LibraryClasses]=0D
DebugLib=0D
+ FileHandleLib=0D
MemoryAllocationLib=0D
PrintLib=0D
- QemuFwCfgLib=0D
UefiBootServicesTableLib=0D
=0D
[Protocols]=0D
gEfiDevicePathProtocolGuid=0D
gEfiLoadedImageProtocolGuid=0D
+ gEfiSimpleFileSystemProtocolGuid=0D
=0D
[Guids]=0D
gQemuKernelLoaderFsMediaGuid=0D
diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLi=
b.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
index 8a29976ae172..66e029397bd6 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -11,13 +11,14 @@
#include <Base.h>=0D
#include <Guid/QemuKernelLoaderFsMedia.h>=0D
#include <Library/DebugLib.h>=0D
+#include <Library/FileHandleLib.h>=0D
#include <Library/MemoryAllocationLib.h>=0D
#include <Library/PrintLib.h>=0D
-#include <Library/QemuFwCfgLib.h>=0D
#include <Library/QemuLoadImageLib.h>=0D
#include <Library/UefiBootServicesTableLib.h>=0D
#include <Protocol/DevicePath.h>=0D
#include <Protocol/LoadedImage.h>=0D
+#include <Protocol/SimpleFileSystem.h>=0D
=0D
#pragma pack (1)=0D
typedef struct {=0D
@@ -30,6 +31,11 @@ typedef struct {
KERNEL_FILE_DEVPATH FileNode;=0D
EFI_DEVICE_PATH_PROTOCOL EndNode;=0D
} KERNEL_VENMEDIA_FILE_DEVPATH;=0D
+=0D
+typedef struct {=0D
+ VENDOR_DEVICE_PATH VenMediaNode;=0D
+ EFI_DEVICE_PATH_PROTOCOL EndNode;=0D
+} SINGLE_VENMEDIA_NODE_DEVPATH;=0D
#pragma pack ()=0D
=0D
STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath =3D {=0D
@@ -51,6 +57,82 @@ STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDeviceP=
ath =3D {
}=0D
};=0D
=0D
+STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mQemuKernelLoaderFsDevicePath =
=3D {=0D
+ {=0D
+ {=0D
+ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,=0D
+ { sizeof (VENDOR_DEVICE_PATH) }=0D
+ },=0D
+ QEMU_KERNEL_LOADER_FS_MEDIA_GUID=0D
+ }, {=0D
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL) }=0D
+ }=0D
+};=0D
+=0D
+STATIC=0D
+EFI_STATUS=0D
+GetQemuKernelLoaderBlobSize (=0D
+ IN EFI_FILE_HANDLE Root,=0D
+ IN CHAR16 *FileName,=0D
+ OUT UINTN *Size=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_FILE_HANDLE FileHandle;=0D
+ UINT64 FileSize;=0D
+=0D
+ Status =3D Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, =
0);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+ Status =3D FileHandleGetSize (FileHandle, &FileSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto CloseFile;=0D
+ }=0D
+ if (FileSize > MAX_UINTN) {=0D
+ Status =3D EFI_UNSUPPORTED;=0D
+ goto CloseFile;=0D
+ }=0D
+ *Size =3D (UINTN)FileSize;=0D
+ Status =3D EFI_SUCCESS;=0D
+CloseFile:=0D
+ FileHandle->Close (FileHandle);=0D
+ return Status;=0D
+}=0D
+=0D
+STATIC=0D
+EFI_STATUS=0D
+ReadWholeQemuKernelLoaderBlob (=0D
+ IN EFI_FILE_HANDLE Root,=0D
+ IN CHAR16 *FileName,=0D
+ IN UINTN Size,=0D
+ OUT VOID *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_FILE_HANDLE FileHandle;=0D
+ UINTN ReadSize;=0D
+=0D
+ Status =3D Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, =
0);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+ ReadSize =3D Size;=0D
+ Status =3D FileHandle->Read (FileHandle, &ReadSize, Buffer);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto CloseFile;=0D
+ }=0D
+ if (ReadSize !=3D Size) {=0D
+ Status =3D EFI_PROTOCOL_ERROR;=0D
+ goto CloseFile;=0D
+ }=0D
+ Status =3D EFI_SUCCESS;=0D
+CloseFile:=0D
+ FileHandle->Close (FileHandle);=0D
+ return Status;=0D
+}=0D
+=0D
/**=0D
Download the kernel, the initial ramdisk, and the kernel command line fr=
om=0D
QEMU's fw_cfg. The kernel will be instructed via its command line to loa=
d=0D
@@ -76,12 +158,16 @@ QemuLoadKernelImage (
OUT EFI_HANDLE *ImageHandle=0D
)=0D
{=0D
- EFI_STATUS Status;=0D
- EFI_HANDLE KernelImageHandle;=0D
- EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;=0D
- UINTN CommandLineSize;=0D
- CHAR8 *CommandLine;=0D
- UINTN InitrdSize;=0D
+ EFI_STATUS Status;=0D
+ EFI_HANDLE KernelImageHandle;=0D
+ EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;=0D
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;=0D
+ EFI_HANDLE FsVolumeHandle;=0D
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;=0D
+ EFI_FILE_HANDLE Root;=0D
+ UINTN CommandLineSize;=0D
+ CHAR8 *CommandLine;=0D
+ UINTN InitrdSize;=0D
=0D
//=0D
// Load the image. This should call back into the QEMU EFI loader file s=
ystem.=0D
@@ -124,8 +210,38 @@ QemuLoadKernelImage (
);=0D
ASSERT_EFI_ERROR (Status);=0D
=0D
- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);=0D
- CommandLineSize =3D (UINTN)QemuFwCfgRead32 ();=0D
+ //=0D
+ // Open the Qemu Kernel Loader abstract filesystem (volume) which will b=
e=0D
+ // used to query the "initrd" and to read the "cmdline" synthetic files.=
=0D
+ //=0D
+ DevicePathNode =3D (EFI_DEVICE_PATH_PROTOCOL *)&mQemuKernelLoaderFsDevic=
ePath;=0D
+ Status =3D gBS->LocateDevicePath (=0D
+ &gEfiSimpleFileSystemProtocolGuid,=0D
+ &DevicePathNode,=0D
+ &FsVolumeHandle=0D
+ );=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto UnloadImage;=0D
+ }=0D
+=0D
+ Status =3D gBS->HandleProtocol (=0D
+ FsVolumeHandle,=0D
+ &gEfiSimpleFileSystemProtocolGuid,=0D
+ (VOID **)&FsProtocol=0D
+ );=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto UnloadImage;=0D
+ }=0D
+=0D
+ Status =3D FsProtocol->OpenVolume (FsVolumeHandle, &Root);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto UnloadImage;=0D
+ }=0D
+=0D
+ Status =3D GetQemuKernelLoaderBlobSize (Root, L"cmdline", &CommandLineSi=
ze);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto CloseRoot;=0D
+ }=0D
=0D
if (CommandLineSize =3D=3D 0) {=0D
KernelLoadedImage->LoadOptionsSize =3D 0;=0D
@@ -133,11 +249,14 @@ QemuLoadKernelImage (
CommandLine =3D AllocatePool (CommandLineSize);=0D
if (CommandLine =3D=3D NULL) {=0D
Status =3D EFI_OUT_OF_RESOURCES;=0D
- goto UnloadImage;=0D
+ goto CloseRoot;=0D
}=0D
=0D
- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);=0D
- QemuFwCfgReadBytes (CommandLineSize, CommandLine);=0D
+ Status =3D ReadWholeQemuKernelLoaderBlob (Root, L"cmdline", CommandLin=
eSize,=0D
+ CommandLine);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto FreeCommandLine;=0D
+ }=0D
=0D
//=0D
// Verify NUL-termination of the command line.=0D
@@ -155,8 +274,10 @@ QemuLoadKernelImage (
KernelLoadedImage->LoadOptionsSize =3D (UINT32)((CommandLineSize - 1) =
* 2);=0D
}=0D
=0D
- QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);=0D
- InitrdSize =3D (UINTN)QemuFwCfgRead32 ();=0D
+ Status =3D GetQemuKernelLoaderBlobSize (Root, L"initrd", &InitrdSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto FreeCommandLine;=0D
+ }=0D
=0D
if (InitrdSize > 0) {=0D
//=0D
@@ -199,6 +320,8 @@ FreeCommandLine:
if (CommandLineSize > 0) {=0D
FreePool (CommandLine);=0D
}=0D
+CloseRoot:=0D
+ Root->Close (Root);=0D
UnloadImage:=0D
if (EFI_ERROR (Status)) {=0D
gBS->UnloadImage (KernelImageHandle);=0D
--=20
2.25.1


Laszlo Ersek
 

On 06/28/21 12:51, Dov Murik wrote:
Remove the QemuFwCfgLib interface used to read the QEMU cmdline
(-append argument) and the initrd size. Instead, use the synthetic
filesystem QemuKernelLoaderFs which has three files: "kernel", "initrd",
and "cmdline".

Cc: Laszlo Ersek <lersek@...>
Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: James Bottomley <jejb@...>
Cc: Tobin Feldman-Fitzthum <tobin@...>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3457
Signed-off-by: Dov Murik <dovmurik@...>
---
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf | 3 +-
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c | 151 ++++++++++++++++++--
2 files changed, 139 insertions(+), 15 deletions(-)

diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
index b262cb926a4d..9c9e35b1c5b9 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
@@ -25,14 +25,15 @@ [Packages]

[LibraryClasses]
DebugLib
+ FileHandleLib
MemoryAllocationLib
PrintLib
- QemuFwCfgLib
UefiBootServicesTableLib

[Protocols]
gEfiDevicePathProtocolGuid
gEfiLoadedImageProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid

[Guids]
gQemuKernelLoaderFsMediaGuid
diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
index 8a29976ae172..66e029397bd6 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -11,13 +11,14 @@
#include <Base.h>
#include <Guid/QemuKernelLoaderFsMedia.h>
#include <Library/DebugLib.h>
+#include <Library/FileHandleLib.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/SimpleFileSystem.h>

#pragma pack (1)
typedef struct {
@@ -30,6 +31,11 @@ typedef struct {
KERNEL_FILE_DEVPATH FileNode;
EFI_DEVICE_PATH_PROTOCOL EndNode;
} KERNEL_VENMEDIA_FILE_DEVPATH;
+
+typedef struct {
+ VENDOR_DEVICE_PATH VenMediaNode;
+ EFI_DEVICE_PATH_PROTOCOL EndNode;
+} SINGLE_VENMEDIA_NODE_DEVPATH;
#pragma pack ()

STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
@@ -51,6 +57,82 @@ STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
}
};

+STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mQemuKernelLoaderFsDevicePath = {
+ {
+ {
+ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+ { sizeof (VENDOR_DEVICE_PATH) }
+ },
+ QEMU_KERNEL_LOADER_FS_MEDIA_GUID
+ }, {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
+ }
+};
+
+STATIC
+EFI_STATUS
+GetQemuKernelLoaderBlobSize (
+ IN EFI_FILE_HANDLE Root,
+ IN CHAR16 *FileName,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE FileHandle;
+ UINT64 FileSize;
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = FileHandleGetSize (FileHandle, &FileSize);
+ if (EFI_ERROR (Status)) {
+ goto CloseFile;
+ }
+ if (FileSize > MAX_UINTN) {
+ Status = EFI_UNSUPPORTED;
+ goto CloseFile;
+ }
+ *Size = (UINTN)FileSize;
+ Status = EFI_SUCCESS;
+CloseFile:
+ FileHandle->Close (FileHandle);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+ReadWholeQemuKernelLoaderBlob (
+ IN EFI_FILE_HANDLE Root,
+ IN CHAR16 *FileName,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE FileHandle;
+ UINTN ReadSize;
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReadSize = Size;
+ Status = FileHandle->Read (FileHandle, &ReadSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ goto CloseFile;
+ }
+ if (ReadSize != Size) {
+ Status = EFI_PROTOCOL_ERROR;
+ goto CloseFile;
+ }
+ Status = EFI_SUCCESS;
+CloseFile:
+ FileHandle->Close (FileHandle);
+ return Status;
+}
+
/**
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
@@ -76,12 +158,16 @@ QemuLoadKernelImage (
OUT EFI_HANDLE *ImageHandle
)
{
- EFI_STATUS Status;
- EFI_HANDLE KernelImageHandle;
- EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
- UINTN CommandLineSize;
- CHAR8 *CommandLine;
- UINTN InitrdSize;
+ EFI_STATUS Status;
+ EFI_HANDLE KernelImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_HANDLE FsVolumeHandle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
+ EFI_FILE_HANDLE Root;
+ UINTN CommandLineSize;
+ CHAR8 *CommandLine;
+ UINTN InitrdSize;

//
// Load the image. This should call back into the QEMU EFI loader file system.
@@ -124,8 +210,38 @@ QemuLoadKernelImage (
);
ASSERT_EFI_ERROR (Status);

- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
- CommandLineSize = (UINTN)QemuFwCfgRead32 ();
+ //
+ // Open the Qemu Kernel Loader abstract filesystem (volume) which will be
+ // used to query the "initrd" and to read the "cmdline" synthetic files.
+ //
+ DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *)&mQemuKernelLoaderFsDevicePath;
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &DevicePathNode,
+ &FsVolumeHandle
+ );
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = gBS->HandleProtocol (
+ FsVolumeHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **)&FsProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = FsProtocol->OpenVolume (FsVolumeHandle, &Root);
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = GetQemuKernelLoaderBlobSize (Root, L"cmdline", &CommandLineSize);
+ if (EFI_ERROR (Status)) {
+ goto CloseRoot;
+ }

if (CommandLineSize == 0) {
KernelLoadedImage->LoadOptionsSize = 0;
@@ -133,11 +249,14 @@ QemuLoadKernelImage (
CommandLine = AllocatePool (CommandLineSize);
if (CommandLine == NULL) {
Status = EFI_OUT_OF_RESOURCES;
- goto UnloadImage;
+ goto CloseRoot;
}

- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
- QemuFwCfgReadBytes (CommandLineSize, CommandLine);
+ Status = ReadWholeQemuKernelLoaderBlob (Root, L"cmdline", CommandLineSize,
+ CommandLine);
+ if (EFI_ERROR (Status)) {
+ goto FreeCommandLine;
+ }

//
// Verify NUL-termination of the command line.
@@ -155,8 +274,10 @@ QemuLoadKernelImage (
KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);
}

- QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
- InitrdSize = (UINTN)QemuFwCfgRead32 ();
+ Status = GetQemuKernelLoaderBlobSize (Root, L"initrd", &InitrdSize);
+ if (EFI_ERROR (Status)) {
+ goto FreeCommandLine;
+ }

if (InitrdSize > 0) {
//
@@ -199,6 +320,8 @@ FreeCommandLine:
if (CommandLineSize > 0) {
FreePool (CommandLine);
}
+CloseRoot:
+ Root->Close (Root);
UnloadImage:
if (EFI_ERROR (Status)) {
gBS->UnloadImage (KernelImageHandle);
Reviewed-by: Laszlo Ersek <lersek@...>


Laszlo Ersek
 

On 06/28/21 12:51, Dov Murik wrote:
Remove the QemuFwCfgLib interface used to read the QEMU cmdline
(-append argument) and the initrd size. Instead, use the synthetic
filesystem QemuKernelLoaderFs which has three files: "kernel", "initrd",
and "cmdline".

Cc: Laszlo Ersek <lersek@...>
Cc: Ard Biesheuvel <ardb+tianocore@...>
Cc: Jordan Justen <jordan.l.justen@...>
Cc: James Bottomley <jejb@...>
Cc: Tobin Feldman-Fitzthum <tobin@...>
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=3457
Signed-off-by: Dov Murik <dovmurik@...>
---
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf | 3 +-
OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c | 151 ++++++++++++++++++--
2 files changed, 139 insertions(+), 15 deletions(-)

diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
index b262cb926a4d..9c9e35b1c5b9 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
@@ -25,14 +25,15 @@ [Packages]

[LibraryClasses]
DebugLib
+ FileHandleLib
MemoryAllocationLib
PrintLib
- QemuFwCfgLib
UefiBootServicesTableLib

[Protocols]
gEfiDevicePathProtocolGuid
gEfiLoadedImageProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid

[Guids]
gQemuKernelLoaderFsMediaGuid
diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
index 8a29976ae172..66e029397bd6 100644
--- a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -11,13 +11,14 @@
#include <Base.h>
#include <Guid/QemuKernelLoaderFsMedia.h>
#include <Library/DebugLib.h>
+#include <Library/FileHandleLib.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/SimpleFileSystem.h>

#pragma pack (1)
typedef struct {
@@ -30,6 +31,11 @@ typedef struct {
KERNEL_FILE_DEVPATH FileNode;
EFI_DEVICE_PATH_PROTOCOL EndNode;
} KERNEL_VENMEDIA_FILE_DEVPATH;
+
+typedef struct {
+ VENDOR_DEVICE_PATH VenMediaNode;
+ EFI_DEVICE_PATH_PROTOCOL EndNode;
+} SINGLE_VENMEDIA_NODE_DEVPATH;
#pragma pack ()

STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
@@ -51,6 +57,82 @@ STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
}
};

+STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mQemuKernelLoaderFsDevicePath = {
+ {
+ {
+ MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+ { sizeof (VENDOR_DEVICE_PATH) }
+ },
+ QEMU_KERNEL_LOADER_FS_MEDIA_GUID
+ }, {
+ END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
+ }
+};
+
+STATIC
+EFI_STATUS
+GetQemuKernelLoaderBlobSize (
+ IN EFI_FILE_HANDLE Root,
+ IN CHAR16 *FileName,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE FileHandle;
+ UINT64 FileSize;
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = FileHandleGetSize (FileHandle, &FileSize);
+ if (EFI_ERROR (Status)) {
+ goto CloseFile;
+ }
+ if (FileSize > MAX_UINTN) {
+ Status = EFI_UNSUPPORTED;
+ goto CloseFile;
+ }
+ *Size = (UINTN)FileSize;
+ Status = EFI_SUCCESS;
+CloseFile:
+ FileHandle->Close (FileHandle);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+ReadWholeQemuKernelLoaderBlob (
+ IN EFI_FILE_HANDLE Root,
+ IN CHAR16 *FileName,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE FileHandle;
+ UINTN ReadSize;
+
+ Status = Root->Open (Root, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReadSize = Size;
+ Status = FileHandle->Read (FileHandle, &ReadSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ goto CloseFile;
+ }
+ if (ReadSize != Size) {
+ Status = EFI_PROTOCOL_ERROR;
+ goto CloseFile;
+ }
+ Status = EFI_SUCCESS;
+CloseFile:
+ FileHandle->Close (FileHandle);
+ return Status;
+}
+
/**
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
@@ -76,12 +158,16 @@ QemuLoadKernelImage (
OUT EFI_HANDLE *ImageHandle
)
{
- EFI_STATUS Status;
- EFI_HANDLE KernelImageHandle;
- EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
- UINTN CommandLineSize;
- CHAR8 *CommandLine;
- UINTN InitrdSize;
+ EFI_STATUS Status;
+ EFI_HANDLE KernelImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_HANDLE FsVolumeHandle;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol;
+ EFI_FILE_HANDLE Root;
+ UINTN CommandLineSize;
+ CHAR8 *CommandLine;
+ UINTN InitrdSize;

//
// Load the image. This should call back into the QEMU EFI loader file system.
@@ -124,8 +210,38 @@ QemuLoadKernelImage (
);
ASSERT_EFI_ERROR (Status);

- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
- CommandLineSize = (UINTN)QemuFwCfgRead32 ();
+ //
+ // Open the Qemu Kernel Loader abstract filesystem (volume) which will be
+ // used to query the "initrd" and to read the "cmdline" synthetic files.
+ //
+ DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *)&mQemuKernelLoaderFsDevicePath;
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &DevicePathNode,
+ &FsVolumeHandle
+ );
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = gBS->HandleProtocol (
+ FsVolumeHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **)&FsProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = FsProtocol->OpenVolume (FsVolumeHandle, &Root);
+ if (EFI_ERROR (Status)) {
+ goto UnloadImage;
+ }
+
+ Status = GetQemuKernelLoaderBlobSize (Root, L"cmdline", &CommandLineSize);
+ if (EFI_ERROR (Status)) {
+ goto CloseRoot;
+ }

if (CommandLineSize == 0) {
KernelLoadedImage->LoadOptionsSize = 0;
@@ -133,11 +249,14 @@ QemuLoadKernelImage (
CommandLine = AllocatePool (CommandLineSize);
if (CommandLine == NULL) {
Status = EFI_OUT_OF_RESOURCES;
- goto UnloadImage;
+ goto CloseRoot;
}

- QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
- QemuFwCfgReadBytes (CommandLineSize, CommandLine);
+ Status = ReadWholeQemuKernelLoaderBlob (Root, L"cmdline", CommandLineSize,
+ CommandLine);
+ if (EFI_ERROR (Status)) {
+ goto FreeCommandLine;
+ }

//
// Verify NUL-termination of the command line.
@@ -155,8 +274,10 @@ QemuLoadKernelImage (
KernelLoadedImage->LoadOptionsSize = (UINT32)((CommandLineSize - 1) * 2);
}

- QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
- InitrdSize = (UINTN)QemuFwCfgRead32 ();
+ Status = GetQemuKernelLoaderBlobSize (Root, L"initrd", &InitrdSize);
+ if (EFI_ERROR (Status)) {
+ goto FreeCommandLine;
+ }

if (InitrdSize > 0) {
//
@@ -199,6 +320,8 @@ FreeCommandLine:
if (CommandLineSize > 0) {
FreePool (CommandLine);
}
+CloseRoot:
+ Root->Close (Root);
UnloadImage:
if (EFI_ERROR (Status)) {
gBS->UnloadImage (KernelImageHandle);
using an aarch64 guest,

Tested-by: Laszlo Ersek <lersek@...>