public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images
@ 2020-03-04  9:52 Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
                   ` (13 more replies)
  0 siblings, 14 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

On ArmVirtQemu, we require the kernel passed via the QEMU -kernel option
to have a PE/COFF header and an EFI stub, so that it can be loaded and
started using the LoadImage and StartImage boot services, respectively.
This means that, on builds that enable secure boot or measured boot, the
kernel image gets authenticated and/or measured as well.

On X86, for historical reasons, we never use LoadImage or StartImage, which
means that:
- kernel images are never authenticated or measured,
- calling Exit() from within the boot stub will attempt tp terminate the
  calling image, which is likely to end badly.

So instead, split and generalize the code that exists today for ArmVirtQemu,
and wire it up for x86 so that LoadImage and StartImage are used unless
there is a true need for the special Linux boot protocol.

The first 6 patches are only intended to be a refactoring of the existing
code, and should not result in any functional changes for either ArmVirtQemu
or OVMF.

Patch #12 adds the new Linux specific initrd loadfile2 protocol that aims
to simplify initrd loading from Linux when booting via the PE stub.

Patch #13 is optional, and disables the Linux loader fallback on builds that
have secure boot enabled.

Changes since [v1]:
- handle EFI_SECURITY_VIOLATION return codes from gBS->LoadImage inside the
  QemuLoadImageLib implementation consistently, instead of propagating it
- change the prototype of QemuStartKernelImage () to take the handle by
  reference, allowing the fallback x86 code to reload the image onto a
  fresh handle if needed
- add new patch to declare gX86QemuKernelLoadedImageGuid, and make it a
  true protocol instead of just a GUID
- drop unnecessary 'wrapper' struct around QEMU_LEGACY_LOADED_IMAGE (#10)
- switch to QemuFwCfgRead32() consistently
- fix numerous other minor style and logic issues pointed out by Laszlo
- add Laszlo's ack to #1, #2, #3, #5, #7, #11 and #14

Code can be found here:
https://github.com/ardbiesheuvel/edk2/tree/ovmf-loadimage-startimage-v1
https://github.com/ardbiesheuvel/edk2/tree/ovmf-loadimage-startimage-v2

[v1] http://mid.mail-archive.com/20200302072936.29221-1-ard.biesheuvel@linaro.org

Ard Biesheuvel (14):
  OvmfPkg: add GUID for the QEMU kernel loader fs media device path
  OvmfPkg: export abstract QEMU blob filesystem in standalone driver
  OvmfPkg: introduce QemuLoadImageLib library class
  OvmfPkg: provide a generic implementation of QemuLoadImageLib
  ArmVirtPkg: incorporate the new QEMU kernel loader driver and library
  ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader
  OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line
  OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block
  OvmfPkg: create protocol and GUID header for legacy loaded images
  OvmfPkg: implement QEMU loader library for X86 with legacy fallback
  OvmfPkg: add new QEMU kernel image loader components
  OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device
    path
  OvmfPkg: use generic QEMU image loader for secure boot enabled builds

 ArmVirtPkg/ArmVirtQemu.dsc                    |    2 +
 ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc          |    1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc              |    2 +
 .../PlatformBootManagerLib.inf                |    9 +-
 .../PlatformBootManagerLib/QemuKernel.c       | 1061 +----------------
 .../Include/Guid/QemuKernelLoaderFsMedia.h    |   18 +
 OvmfPkg/Include/Library/QemuLoadImageLib.h    |   84 ++
 .../Protocol/X86QemuKernelLoadedImage.h       |   19 +
 .../GenericQemuLoadImageLib.c                 |  278 +++++
 .../GenericQemuLoadImageLib.inf               |   38 +
 .../PlatformBootManagerLib.inf                |    2 +-
 .../PlatformBootManagerLib/QemuKernel.c       |  144 +--
 .../X86QemuLoadImageLib/X86QemuLoadImageLib.c |  564 +++++++++
 .../X86QemuLoadImageLib.inf                   |   42 +
 OvmfPkg/OvmfPkg.dec                           |    7 +
 OvmfPkg/OvmfPkgIa32.dsc                       |    6 +
 OvmfPkg/OvmfPkgIa32.fdf                       |    1 +
 OvmfPkg/OvmfPkgIa32X64.dsc                    |    6 +
 OvmfPkg/OvmfPkgIa32X64.fdf                    |    1 +
 OvmfPkg/OvmfPkgX64.dsc                        |    6 +
 OvmfPkg/OvmfPkgX64.fdf                        |    1 +
 .../QemuKernelLoaderFsDxe.c                   |  367 +++---
 .../QemuKernelLoaderFsDxe.inf                 |   50 +
 23 files changed, 1315 insertions(+), 1394 deletions(-)
 create mode 100644 OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h
 create mode 100644 OvmfPkg/Include/Library/QemuLoadImageLib.h
 create mode 100644 OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
 create mode 100644 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
 create mode 100644 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
 create mode 100644 OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
 create mode 100644 OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
 copy ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c => OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c (77%)
 create mode 100644 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf

-- 
2.17.1


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v2 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver Ard Biesheuvel
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

In an upcoming patch, we will introduce a separate DXE driver that
exposes the virtual SimpleFileSystem implementation that carries the
kernel and initrd passed via the QEMU command line, and a separate
library that consumes it, to be incorporated into the boot manager.

Since the GUID used for the SimpleFileSystem implementation's device
path will no longer be for internal use only, create a well defined
GUID to identify the media device path.

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>
---
 OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h | 18 ++++++++++++++++++
 OvmfPkg/OvmfPkg.dec                            |  1 +
 2 files changed, 19 insertions(+)

diff --git a/OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h b/OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h
new file mode 100644
index 000000000000..225c3c494613
--- /dev/null
+++ b/OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h
@@ -0,0 +1,18 @@
+/** @file
+  GUID definition for the QEMU LoaderFs media device path, containing the
+  kernel, initrd and command line as file objects
+
+  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef QEMU_KERNEL_LOADER_FS_MEDIA_GUID_H__
+#define QEMU_KERNEL_LOADER_FS_MEDIA_GUID_H__
+
+#define QEMU_KERNEL_LOADER_FS_MEDIA_GUID \
+  {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
+
+extern EFI_GUID gQemuKernelLoaderFsMediaGuid;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 43d16372a270..a21b279d140a 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -87,6 +87,7 @@ [Guids]
   gEfiLegacyBiosGuid                  = {0x2E3044AC, 0x879F, 0x490F, {0x97, 0x60, 0xBB, 0xDF, 0xAF, 0x69, 0x5F, 0x50}}
   gEfiLegacyDevOrderVariableGuid      = {0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52}}
   gLinuxEfiInitrdMediaGuid            = {0x5568e427, 0x68fc, 0x4f3d, {0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68}}
+  gQemuKernelLoaderFsMediaGuid        = {0x1428f772, 0xb64a, 0x441e, {0xb8, 0xc3, 0x9e, 0xbd, 0xd7, 0xf8, 0x93, 0xc7}}
 
 [Ppis]
   # PPI whose presence in the PPI database signals that the TPM base address
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Expose the existing implementation of an abstract filesystem exposing
the blobs passed to QEMU via the command line via a standalone DXE
driver.

Notable difference with the original code is the switch to a new vendor
GUIDed media device path, as opposed to a vendor GUID hardware device
path, which is not entirely appropriate for pure software constructs.

Since we are using the GetTime() runtime service in a DXE_DRIVER type
module, we need to DEPEX explicitly on gEfiRealTimeClockArchProtocolGuid.

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>
---
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c   | 979 ++++++++++++++++++++
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf |  48 +
 2 files changed, 1027 insertions(+)

diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
new file mode 100644
index 000000000000..e4539ec2fbe5
--- /dev/null
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
@@ -0,0 +1,979 @@
+/** @file
+  DXE driver to expose the 'kernel', 'initrd' and 'cmdline' blobs
+  provided by QEMU as files in an abstract file system
+
+  Copyright (C) 2014-2016, Red Hat, Inc.
+  Copyright (C) 2020, Arm, Limited.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/QemuKernelLoaderFsMedia.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleFileSystem.h>
+
+//
+// Static data that hosts the fw_cfg blobs and serves file requests.
+//
+typedef enum {
+  KernelBlobTypeKernel,
+  KernelBlobTypeInitrd,
+  KernelBlobTypeCommandLine,
+  KernelBlobTypeMax
+} KERNEL_BLOB_TYPE;
+
+typedef struct {
+  FIRMWARE_CONFIG_ITEM CONST SizeKey;
+  FIRMWARE_CONFIG_ITEM CONST DataKey;
+  CONST CHAR16 *       CONST Name;
+  UINT32                     Size;
+  UINT8                      *Data;
+} KERNEL_BLOB;
+
+STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
+  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
+  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
+  { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, L"cmdline" }
+};
+
+STATIC UINT64 mTotalBlobBytes;
+
+//
+// Device path for the handle that incorporates our "EFI stub filesystem".
+//
+#pragma pack (1)
+typedef struct {
+  VENDOR_DEVICE_PATH       VenMediaNode;
+  EFI_DEVICE_PATH_PROTOCOL EndNode;
+} SINGLE_VENMEDIA_NODE_DEVPATH;
+#pragma pack ()
+
+STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath = {
+  {
+    {
+      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) }
+  }
+};
+
+//
+// The "file in the EFI stub filesystem" abstraction.
+//
+STATIC EFI_TIME mInitTime;
+
+#define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
+
+typedef struct {
+  UINT64            Signature; // Carries STUB_FILE_SIG.
+
+  KERNEL_BLOB_TYPE  BlobType;  // Index into mKernelBlob. KernelBlobTypeMax
+                               // denotes the root directory of the filesystem.
+
+  UINT64            Position;  // Byte position for regular files;
+                               // next directory entry to return for the root
+                               // directory.
+
+  EFI_FILE_PROTOCOL File;      // Standard protocol interface.
+} STUB_FILE;
+
+#define STUB_FILE_FROM_FILE(FilePointer) \
+        CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
+
+//
+// Tentative definition of the file protocol template. The initializer
+// (external definition) will be provided later.
+//
+STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate;
+
+
+//
+// Protocol member functions for File.
+//
+
+/**
+  Opens a new file relative to the source file's location.
+
+  @param[in]  This        A pointer to the EFI_FILE_PROTOCOL instance that is
+                          the file handle to the source location. This would
+                          typically be an open handle to a directory.
+
+  @param[out] NewHandle   A pointer to the location to return the opened handle
+                          for the new file.
+
+  @param[in]  FileName    The Null-terminated string of the name of the file to
+                          be opened. The file name may contain the following
+                          path modifiers: "\", ".", and "..".
+
+  @param[in]  OpenMode    The mode to open the file. The only valid
+                          combinations that the file may be opened with are:
+                          Read, Read/Write, or Create/Read/Write.
+
+  @param[in]  Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case
+                          these are the attribute bits for the newly created
+                          file.
+
+  @retval EFI_SUCCESS           The file was opened.
+  @retval EFI_NOT_FOUND         The specified file could not be found on the
+                                device.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
+                                medium is no longer supported.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a
+                                file for write when the media is
+                                write-protected.
+  @retval EFI_ACCESS_DENIED     The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
+                                file.
+  @retval EFI_VOLUME_FULL       The volume is full.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileOpen (
+  IN EFI_FILE_PROTOCOL  *This,
+  OUT EFI_FILE_PROTOCOL **NewHandle,
+  IN CHAR16             *FileName,
+  IN UINT64             OpenMode,
+  IN UINT64             Attributes
+  )
+{
+  CONST STUB_FILE *StubFile;
+  UINTN           BlobType;
+  STUB_FILE       *NewStubFile;
+
+  //
+  // We're read-only.
+  //
+  switch (OpenMode) {
+    case EFI_FILE_MODE_READ:
+      break;
+
+    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
+    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
+      return EFI_WRITE_PROTECTED;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Only the root directory supports opening files in it.
+  //
+  StubFile = STUB_FILE_FROM_FILE (This);
+  if (StubFile->BlobType != KernelBlobTypeMax) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Locate the file.
+  //
+  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
+    if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
+      break;
+    }
+  }
+  if (BlobType == KernelBlobTypeMax) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Found it.
+  //
+  NewStubFile = AllocatePool (sizeof *NewStubFile);
+  if (NewStubFile == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  NewStubFile->Signature = STUB_FILE_SIG;
+  NewStubFile->BlobType  = (KERNEL_BLOB_TYPE)BlobType;
+  NewStubFile->Position  = 0;
+  CopyMem (&NewStubFile->File, &mEfiFileProtocolTemplate,
+    sizeof mEfiFileProtocolTemplate);
+  *NewHandle = &NewStubFile->File;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Closes a specified file handle.
+
+  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
+                   handle to close.
+
+  @retval EFI_SUCCESS  The file was closed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileClose (
+  IN EFI_FILE_PROTOCOL *This
+  )
+{
+  FreePool (STUB_FILE_FROM_FILE (This));
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Close and delete the file handle.
+
+  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
+                   handle to the file to delete.
+
+  @retval EFI_SUCCESS              The file was closed and deleted, and the
+                                   handle was closed.
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not
+                                   deleted.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileDelete (
+  IN EFI_FILE_PROTOCOL *This
+  )
+{
+  FreePool (STUB_FILE_FROM_FILE (This));
+  return EFI_WARN_DELETE_FAILURE;
+}
+
+
+/**
+  Helper function that formats an EFI_FILE_INFO structure into the
+  user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
+  KernelBlobTypeMax, which stands for the root directory).
+
+  The interface follows the EFI_FILE_GET_INFO -- and for directories, the
+  EFI_FILE_READ -- interfaces.
+
+  @param[in]     BlobType     The KERNEL_BLOB_TYPE value identifying the fw_cfg
+                              blob backing the STUB_FILE that information is
+                              being requested about. If BlobType equals
+                              KernelBlobTypeMax, then information will be
+                              provided about the root directory of the
+                              filesystem.
+
+  @param[in,out] BufferSize  On input, the size of Buffer. On output, the
+                             amount of data returned in Buffer. In both cases,
+                             the size is measured in bytes.
+
+  @param[out]    Buffer      A pointer to the data buffer to return. The
+                             buffer's type is EFI_FILE_INFO.
+
+  @retval EFI_SUCCESS           The information was returned.
+  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small to store the
+                                EFI_FILE_INFO structure. BufferSize has been
+                                updated with the size needed to complete the
+                                request.
+**/
+STATIC
+EFI_STATUS
+ConvertKernelBlobTypeToFileInfo (
+  IN KERNEL_BLOB_TYPE BlobType,
+  IN OUT UINTN        *BufferSize,
+  OUT VOID            *Buffer
+  )
+{
+  CONST CHAR16  *Name;
+  UINT64        FileSize;
+  UINT64        Attribute;
+
+  UINTN         NameSize;
+  UINTN         FileInfoSize;
+  EFI_FILE_INFO *FileInfo;
+  UINTN         OriginalBufferSize;
+
+  if (BlobType == KernelBlobTypeMax) {
+    //
+    // getting file info about the root directory
+    //
+    Name      = L"\\";
+    FileSize  = KernelBlobTypeMax;
+    Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
+  } else {
+    CONST KERNEL_BLOB *Blob;
+
+    Blob      = &mKernelBlob[BlobType];
+    Name      = Blob->Name;
+    FileSize  = Blob->Size;
+    Attribute = EFI_FILE_READ_ONLY;
+  }
+
+  NameSize     = (StrLen(Name) + 1) * 2;
+  FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;
+  ASSERT (FileInfoSize >= sizeof *FileInfo);
+
+  OriginalBufferSize = *BufferSize;
+  *BufferSize        = FileInfoSize;
+  if (OriginalBufferSize < *BufferSize) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  FileInfo               = (EFI_FILE_INFO *)Buffer;
+  FileInfo->Size         = FileInfoSize;
+  FileInfo->FileSize     = FileSize;
+  FileInfo->PhysicalSize = FileSize;
+  FileInfo->Attribute    = Attribute;
+
+  CopyMem (&FileInfo->CreateTime,       &mInitTime, sizeof mInitTime);
+  CopyMem (&FileInfo->LastAccessTime,   &mInitTime, sizeof mInitTime);
+  CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);
+  CopyMem (FileInfo->FileName,          Name,       NameSize);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Reads data from a file, or continues scanning a directory.
+
+  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
+                             is the file handle to read data from.
+
+  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
+                             amount of data returned in Buffer. In both cases,
+                             the size is measured in bytes. If the read goes
+                             beyond the end of the file, the read length is
+                             truncated to the end of the file.
+
+                             If This is a directory, the function reads the
+                             directory entry at the current position and
+                             returns the entry (as EFI_FILE_INFO) in Buffer. If
+                             there are no more directory entries, the
+                             BufferSize is set to zero on output.
+
+  @param[out]    Buffer      The buffer into which the data is read.
+
+  @retval EFI_SUCCESS           Data was read.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted
+                                file.
+  @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond
+                                the end of the file.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
+                                current directory entry as a EFI_FILE_INFO
+                                structure. BufferSize has been updated with the
+                                size needed to complete the request, and the
+                                directory position has not been advanced.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileRead (
+  IN EFI_FILE_PROTOCOL *This,
+  IN OUT UINTN         *BufferSize,
+  OUT VOID             *Buffer
+  )
+{
+  STUB_FILE         *StubFile;
+  CONST KERNEL_BLOB *Blob;
+  UINT64            Left;
+
+  StubFile = STUB_FILE_FROM_FILE (This);
+
+  //
+  // Scanning the root directory?
+  //
+  if (StubFile->BlobType == KernelBlobTypeMax) {
+    EFI_STATUS Status;
+
+    if (StubFile->Position == KernelBlobTypeMax) {
+      //
+      // Scanning complete.
+      //
+      *BufferSize = 0;
+      return EFI_SUCCESS;
+    }
+
+    Status = ConvertKernelBlobTypeToFileInfo (
+               (KERNEL_BLOB_TYPE)StubFile->Position,
+               BufferSize,
+               Buffer);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    ++StubFile->Position;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Reading a file.
+  //
+  Blob = &mKernelBlob[StubFile->BlobType];
+  if (StubFile->Position > Blob->Size) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  Left = Blob->Size - StubFile->Position;
+  if (*BufferSize > Left) {
+    *BufferSize = (UINTN)Left;
+  }
+  if (Blob->Data != NULL) {
+    CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
+  }
+  StubFile->Position += *BufferSize;
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Writes data to a file.
+
+  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
+                             is the file handle to write data to.
+
+  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
+                             amount of data actually written. In both cases,
+                             the size is measured in bytes.
+
+  @param[in]     Buffer      The buffer of data to write.
+
+  @retval EFI_SUCCESS           Data was written.
+  @retval EFI_UNSUPPORTED       Writes to open directory files are not
+                                supported.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_DEVICE_ERROR      An attempt was made to write to a deleted file.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
+  @retval EFI_ACCESS_DENIED     The file was opened read only.
+  @retval EFI_VOLUME_FULL       The volume is full.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileWrite (
+  IN EFI_FILE_PROTOCOL *This,
+  IN OUT UINTN         *BufferSize,
+  IN VOID              *Buffer
+  )
+{
+  STUB_FILE *StubFile;
+
+  StubFile = STUB_FILE_FROM_FILE (This);
+  return (StubFile->BlobType == KernelBlobTypeMax) ?
+         EFI_UNSUPPORTED :
+         EFI_WRITE_PROTECTED;
+}
+
+
+/**
+  Returns a file's current position.
+
+  @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is the
+                        file handle to get the current position on.
+
+  @param[out] Position  The address to return the file's current position
+                        value.
+
+  @retval EFI_SUCCESS      The position was returned.
+  @retval EFI_UNSUPPORTED  The request is not valid on open directories.
+  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
+                           deleted file.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileGetPosition (
+  IN EFI_FILE_PROTOCOL *This,
+  OUT UINT64           *Position
+  )
+{
+  STUB_FILE *StubFile;
+
+  StubFile = STUB_FILE_FROM_FILE (This);
+  if (StubFile->BlobType == KernelBlobTypeMax) {
+    return EFI_UNSUPPORTED;
+  }
+
+  *Position = StubFile->Position;
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Sets a file's current position.
+
+  @param[in] This      A pointer to the EFI_FILE_PROTOCOL instance that is the
+                       file handle to set the requested position on.
+
+  @param[in] Position  The byte position from the start of the file to set. For
+                       regular files, MAX_UINT64 means "seek to end". For
+                       directories, zero means "rewind directory scan".
+
+  @retval EFI_SUCCESS       The position was set.
+  @retval EFI_UNSUPPORTED   The seek request for nonzero is not valid on open
+                            directories.
+  @retval EFI_DEVICE_ERROR  An attempt was made to set the position of a
+                            deleted file.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileSetPosition (
+  IN EFI_FILE_PROTOCOL *This,
+  IN UINT64            Position
+  )
+{
+  STUB_FILE   *StubFile;
+  KERNEL_BLOB *Blob;
+
+  StubFile = STUB_FILE_FROM_FILE (This);
+
+  if (StubFile->BlobType == KernelBlobTypeMax) {
+    if (Position == 0) {
+      //
+      // rewinding a directory scan is allowed
+      //
+      StubFile->Position = 0;
+      return EFI_SUCCESS;
+    }
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // regular file seek
+  //
+  Blob = &mKernelBlob[StubFile->BlobType];
+  if (Position == MAX_UINT64) {
+    //
+    // seek to end
+    //
+    StubFile->Position = Blob->Size;
+  } else {
+    //
+    // absolute seek from beginning -- seeking past the end is allowed
+    //
+    StubFile->Position = Position;
+  }
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Returns information about a file.
+
+  @param[in]     This             A pointer to the EFI_FILE_PROTOCOL instance
+                                  that is the file handle the requested
+                                  information is for.
+
+  @param[in]     InformationType  The type identifier GUID for the information
+                                  being requested. The following information
+                                  types are supported, storing the
+                                  corresponding structures in Buffer:
+
+                                  - gEfiFileInfoGuid: EFI_FILE_INFO
+
+                                  - gEfiFileSystemInfoGuid:
+                                    EFI_FILE_SYSTEM_INFO
+
+                                  - gEfiFileSystemVolumeLabelInfoIdGuid:
+                                    EFI_FILE_SYSTEM_VOLUME_LABEL
+
+  @param[in,out] BufferSize       On input, the size of Buffer. On output, the
+                                  amount of data returned in Buffer. In both
+                                  cases, the size is measured in bytes.
+
+  @param[out]    Buffer           A pointer to the data buffer to return. The
+                                  buffer's type is indicated by
+                                  InformationType.
+
+  @retval EFI_SUCCESS           The information was returned.
+  @retval EFI_UNSUPPORTED       The InformationType is not known.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
+                                information structure requested by
+                                InformationType. BufferSize has been updated
+                                with the size needed to complete the request.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileGetInfo (
+  IN EFI_FILE_PROTOCOL *This,
+  IN EFI_GUID          *InformationType,
+  IN OUT UINTN         *BufferSize,
+  OUT VOID             *Buffer
+  )
+{
+  CONST STUB_FILE *StubFile;
+  UINTN           OriginalBufferSize;
+
+  StubFile = STUB_FILE_FROM_FILE (This);
+
+  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+    return ConvertKernelBlobTypeToFileInfo (StubFile->BlobType, BufferSize,
+             Buffer);
+  }
+
+  OriginalBufferSize = *BufferSize;
+
+  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+    EFI_FILE_SYSTEM_INFO *FileSystemInfo;
+
+    *BufferSize = sizeof *FileSystemInfo;
+    if (OriginalBufferSize < *BufferSize) {
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    FileSystemInfo                 = (EFI_FILE_SYSTEM_INFO *)Buffer;
+    FileSystemInfo->Size           = sizeof *FileSystemInfo;
+    FileSystemInfo->ReadOnly       = TRUE;
+    FileSystemInfo->VolumeSize     = mTotalBlobBytes;
+    FileSystemInfo->FreeSpace      = 0;
+    FileSystemInfo->BlockSize      = 1;
+    FileSystemInfo->VolumeLabel[0] = L'\0';
+
+    return EFI_SUCCESS;
+  }
+
+  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+    EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
+
+    *BufferSize = sizeof *FileSystemVolumeLabel;
+    if (OriginalBufferSize < *BufferSize) {
+      return EFI_BUFFER_TOO_SMALL;
+    }
+
+    FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
+    FileSystemVolumeLabel->VolumeLabel[0] = L'\0';
+
+    return EFI_SUCCESS;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  Sets information about a file.
+
+  @param[in] File             A pointer to the EFI_FILE_PROTOCOL instance that
+                              is the file handle the information is for.
+
+  @param[in] InformationType  The type identifier for the information being
+                              set.
+
+  @param[in] BufferSize       The size, in bytes, of Buffer.
+
+  @param[in] Buffer           A pointer to the data buffer to write. The
+                              buffer's type is indicated by InformationType.
+
+  @retval EFI_SUCCESS           The information was set.
+  @retval EFI_UNSUPPORTED       The InformationType is not known.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED   InformationType is EFI_FILE_INFO_ID and the
+                                media is read-only.
+  @retval EFI_WRITE_PROTECTED   InformationType is
+                                EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
+                                is read only.
+  @retval EFI_WRITE_PROTECTED   InformationType is
+                                EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
+                                is read-only.
+  @retval EFI_ACCESS_DENIED     An attempt is made to change the name of a file
+                                to a file that is already present.
+  @retval EFI_ACCESS_DENIED     An attempt is being made to change the
+                                EFI_FILE_DIRECTORY Attribute.
+  @retval EFI_ACCESS_DENIED     An attempt is being made to change the size of
+                                a directory.
+  @retval EFI_ACCESS_DENIED     InformationType is EFI_FILE_INFO_ID and the
+                                file was opened read-only and an attempt is
+                                being made to modify a field other than
+                                Attribute.
+  @retval EFI_VOLUME_FULL       The volume is full.
+  @retval EFI_BAD_BUFFER_SIZE   BufferSize is smaller than the size of the type
+                                indicated by InformationType.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileSetInfo (
+  IN EFI_FILE_PROTOCOL *This,
+  IN EFI_GUID          *InformationType,
+  IN UINTN             BufferSize,
+  IN VOID              *Buffer
+  )
+{
+  return EFI_WRITE_PROTECTED;
+}
+
+
+/**
+  Flushes all modified data associated with a file to a device.
+
+  @param [in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
+                    file handle to flush.
+
+  @retval EFI_SUCCESS           The data was flushed.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
+  @retval EFI_ACCESS_DENIED     The file was opened read-only.
+  @retval EFI_VOLUME_FULL       The volume is full.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileFlush (
+  IN EFI_FILE_PROTOCOL *This
+  )
+{
+  return EFI_WRITE_PROTECTED;
+}
+
+//
+// External definition of the file protocol template.
+//
+STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
+  EFI_FILE_PROTOCOL_REVISION, // revision 1
+  StubFileOpen,
+  StubFileClose,
+  StubFileDelete,
+  StubFileRead,
+  StubFileWrite,
+  StubFileGetPosition,
+  StubFileSetPosition,
+  StubFileGetInfo,
+  StubFileSetInfo,
+  StubFileFlush,
+  NULL,                       // OpenEx, revision 2
+  NULL,                       // ReadEx, revision 2
+  NULL,                       // WriteEx, revision 2
+  NULL                        // FlushEx, revision 2
+};
+
+
+//
+// Protocol member functions for SimpleFileSystem.
+//
+
+/**
+  Open the root directory on a volume.
+
+  @param[in]  This  A pointer to the volume to open the root directory on.
+
+  @param[out] Root  A pointer to the location to return the opened file handle
+                    for the root directory in.
+
+  @retval EFI_SUCCESS           The device was opened.
+  @retval EFI_UNSUPPORTED       This volume does not support the requested file
+                                system type.
+  @retval EFI_NO_MEDIA          The device has no medium.
+  @retval EFI_DEVICE_ERROR      The device reported an error.
+  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
+  @retval EFI_ACCESS_DENIED     The service denied access to the file.
+  @retval EFI_OUT_OF_RESOURCES  The volume was not opened due to lack of
+                                resources.
+  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
+                                medium is no longer supported. Any existing
+                                file handles for this volume are no longer
+                                valid. To access the files on the new medium,
+                                the volume must be reopened with OpenVolume().
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StubFileSystemOpenVolume (
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+  OUT EFI_FILE_PROTOCOL              **Root
+  )
+{
+  STUB_FILE *StubFile;
+
+  StubFile = AllocatePool (sizeof *StubFile);
+  if (StubFile == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  StubFile->Signature = STUB_FILE_SIG;
+  StubFile->BlobType  = KernelBlobTypeMax;
+  StubFile->Position  = 0;
+  CopyMem (&StubFile->File, &mEfiFileProtocolTemplate,
+    sizeof mEfiFileProtocolTemplate);
+  *Root = &StubFile->File;
+
+  return EFI_SUCCESS;
+}
+
+STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
+  StubFileSystemOpenVolume
+};
+
+
+//
+// Utility functions.
+//
+
+/**
+  Populate a blob in mKernelBlob.
+
+  param[in,out] Blob  Pointer to the KERNEL_BLOB element in mKernelBlob that is
+                      to be filled from fw_cfg.
+
+  @retval EFI_SUCCESS           Blob has been populated. If fw_cfg reported a
+                                size of zero for the blob, then Blob->Data has
+                                been left unchanged.
+
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Blob->Data.
+**/
+STATIC
+EFI_STATUS
+FetchBlob (
+  IN OUT KERNEL_BLOB *Blob
+  )
+{
+  UINT32 Left;
+
+  //
+  // Read blob size.
+  //
+  QemuFwCfgSelectItem (Blob->SizeKey);
+  Blob->Size = QemuFwCfgRead32 ();
+  if (Blob->Size == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Read blob.
+  //
+  Blob->Data = AllocatePool (Blob->Size);
+  if (Blob->Data == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: failed to allocate %Ld bytes for \"%s\"\n",
+      __FUNCTION__, (INT64)Blob->Size, Blob->Name));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,
+    (INT64)Blob->Size, Blob->Name));
+  QemuFwCfgSelectItem (Blob->DataKey);
+
+  Left = Blob->Size;
+  do {
+    UINT32 Chunk;
+
+    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
+    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));
+    Left -= Chunk;
+    DEBUG ((DEBUG_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",
+      __FUNCTION__, (INT64)Left, Blob->Name));
+  } while (Left > 0);
+  return EFI_SUCCESS;
+}
+
+
+//
+// The entry point of the feature.
+//
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. Construct a minimal SimpleFileSystem that contains the two
+  image files.
+
+  @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. On success, the function doesn't
+                                return.
+**/
+EFI_STATUS
+EFIAPI
+QemuKernelLoaderFsDxeEntrypoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  UINTN                     BlobType;
+  KERNEL_BLOB               *CurrentBlob;
+  KERNEL_BLOB               *KernelBlob;
+  EFI_STATUS                Status;
+  EFI_HANDLE                FileSystemHandle;
+
+  if (!QemuFwCfgIsAvailable ()) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: GetTime(): %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  //
+  // Fetch all blobs.
+  //
+  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
+    CurrentBlob = &mKernelBlob[BlobType];
+    Status = FetchBlob (CurrentBlob);
+    if (EFI_ERROR (Status)) {
+      goto FreeBlobs;
+    }
+    mTotalBlobBytes += CurrentBlob->Size;
+  }
+  KernelBlob      = &mKernelBlob[KernelBlobTypeKernel];
+
+  if (KernelBlob->Data == NULL) {
+    Status = EFI_NOT_FOUND;
+    goto FreeBlobs;
+  }
+
+  //
+  // Create a new handle with a single VenMedia() node device path protocol on
+  // it, plus a custom SimpleFileSystem protocol on it.
+  //
+  FileSystemHandle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (&FileSystemHandle,
+                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
+                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
+                  NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
+      __FUNCTION__, Status));
+    goto FreeBlobs;
+  }
+
+  return EFI_SUCCESS;
+
+FreeBlobs:
+  while (BlobType > 0) {
+    CurrentBlob = &mKernelBlob[--BlobType];
+    if (CurrentBlob->Data != NULL) {
+      FreePool (CurrentBlob->Data);
+      CurrentBlob->Size = 0;
+      CurrentBlob->Data = NULL;
+    }
+  }
+
+  return Status;
+}
diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
new file mode 100644
index 000000000000..5ba88063def0
--- /dev/null
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
@@ -0,0 +1,48 @@
+##  @file
+#  DXE driver to expose the 'kernel', 'initrd' and 'cmdline' blobs
+#  provided by QEMU as files in an abstract file system
+#
+#  Copyright (C) 2014-2016, Red Hat, Inc.
+#  Copyright (C) 2020, Arm, Limited.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 1.27
+  BASE_NAME                      = QemuKernelLoaderFsDxe
+  FILE_GUID                      = 806040ca-dad9-4978-a3b4-2d2ab0c8a48f
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = QemuKernelLoaderFsDxeEntrypoint
+
+[Sources]
+  QemuKernelLoaderFsDxe.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  QemuFwCfgLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiFileSystemInfoGuid
+  gEfiFileSystemVolumeLabelInfoIdGuid
+  gQemuKernelLoaderFsMediaGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid                ## PRODUCES
+  gEfiSimpleFileSystemProtocolGuid          ## PRODUCES
+
+[Depex]
+  gEfiRealTimeClockArchProtocolGuid
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05  9:37   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Introduce the QemuLoadImageLib library class that we will instantiate
to load the kernel image passed via the QEMU command line using the
standard LoadImage boot service.

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>
---
 OvmfPkg/Include/Library/QemuLoadImageLib.h | 84 ++++++++++++++++++++
 OvmfPkg/OvmfPkg.dec                        |  5 ++
 2 files changed, 89 insertions(+)

diff --git a/OvmfPkg/Include/Library/QemuLoadImageLib.h b/OvmfPkg/Include/Library/QemuLoadImageLib.h
new file mode 100644
index 000000000000..694905a6421b
--- /dev/null
+++ b/OvmfPkg/Include/Library/QemuLoadImageLib.h
@@ -0,0 +1,84 @@
+/** @file
+  Load a kernel image and command line passed to QEMU via
+  the command line
+
+  Copyright (C) 2020, Arm, Limited.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef QEMU_LOAD_IMAGE_LIB_H__
+#define QEMU_LOAD_IMAGE_LIB_H__
+
+#include <Uefi/UefiBaseType.h>
+#include <Base.h>
+
+#include <Protocol/LoadedImage.h>
+
+/**
+  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
+  );
+
+/**
+  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.
+                                  On success, the function doesn't return.
+**/
+EFI_STATUS
+EFIAPI
+QemuStartKernelImage (
+  IN  OUT EFI_HANDLE          *ImageHandle
+  );
+
+/**
+  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
+  );
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index a21b279d140a..055caaa43041 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -58,6 +58,11 @@ [LibraryClasses]
   #
   QemuBootOrderLib|Include/Library/QemuBootOrderLib.h
 
+  ##  @libraryclass  Load a kernel image and command line passed to QEMU via
+  #                  the command line
+  #
+  QemuLoadImageLib|Include/Library/QemuLoadImageLib.h
+
   ##  @libraryclass  Serialize (and deserialize) variables
   #
   SerializeVariablesLib|Include/Library/SerializeVariablesLib.h
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05  9:51   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library Ard Biesheuvel
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

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>
---
 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c   | 278 ++++++++++++++++++++
 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf |  38 +++
 2 files changed, 316 insertions(+)

diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
new file mode 100644
index 000000000000..f5edb43cc0b9
--- /dev/null
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -0,0 +1,278 @@
+/**  @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
+  @param[out] LoadedImage       The loaded image protocol that was installed
+                                on ImageHandle by the LoadImage boot service.
+
+  @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);
+}
diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
new file mode 100644
index 000000000000..b262cb926a4d
--- /dev/null
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
@@ -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
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Add the QEMU loader DXE driver and client library to the build for
our QEMU targeted implementations in ArmVirtPkg.

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>
---
 ArmVirtPkg/ArmVirtQemu.dsc           | 2 ++
 ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc     | 2 ++
 3 files changed, 5 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 5e5f71e7fe8a..8c77fc46427b 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -58,6 +58,7 @@ [LibraryClasses.common]
   VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
   QemuFwCfgLib|ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/BaseQemuFwCfgS3LibNull.inf
+  QemuLoadImageLib|OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
 
   ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf
 
@@ -427,6 +428,7 @@ [Components.common]
       NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
       NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
   }
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 
   #
   # Networking stack
diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
index 2a17583593ef..aaba0b1c8840 100644
--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
+++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc
@@ -114,6 +114,7 @@ [FV.FvMain]
   INF MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
   INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
   INF MdeModulePkg/Application/UiApp/UiApp.inf
+  INF OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 
   #
   # Networking stack
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index 37e19dfbd0db..4d82a77213ec 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -56,6 +56,7 @@ [LibraryClasses.common]
   VirtioMmioDeviceLib|OvmfPkg/Library/VirtioMmioDeviceLib/VirtioMmioDeviceLib.inf
   QemuFwCfgLib|ArmVirtPkg/Library/QemuFwCfgLib/QemuFwCfgLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/BaseQemuFwCfgS3LibNull.inf
+  QemuLoadImageLib|OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
 
   ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf
 
@@ -362,6 +363,7 @@ [Components.common]
       NULL|MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf
       NULL|MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
   }
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 
   #
   # Networking stack
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 10:01   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line Ard Biesheuvel
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Drop the QEMU loader file system implementation inside this library,
and switch to the separate QemuLoadImageLib library and the associated
driver to expose the kernel and initrd passed via the QEMU command line.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |    9 +-
 ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c               | 1061 +-------------------
 2 files changed, 7 insertions(+), 1063 deletions(-)

diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
index a9d4888d4377..a010564527b6 100644
--- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -44,9 +44,8 @@ [LibraryClasses]
   MemoryAllocationLib
   PcdLib
   PlatformBmPrintScLib
-  PrintLib
   QemuBootOrderLib
-  QemuFwCfgLib
+  QemuLoadImageLib
   ReportStatusCodeLib
   UefiBootManagerLib
   UefiBootServicesTableLib
@@ -64,18 +63,12 @@ [Pcd]
   gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
 
 [Guids]
-  gEfiFileInfoGuid
-  gEfiFileSystemInfoGuid
-  gEfiFileSystemVolumeLabelInfoIdGuid
   gEfiEndOfDxeEventGroupGuid
   gRootBridgesConnectedEventGroupGuid
   gUefiShellFileGuid
 
 [Protocols]
-  gEfiDevicePathProtocolGuid
   gEfiFirmwareVolume2ProtocolGuid
   gEfiGraphicsOutputProtocolGuid
-  gEfiLoadedImageProtocolGuid
   gEfiPciRootBridgeIoProtocolGuid
-  gEfiSimpleFileSystemProtocolGuid
   gVirtioDeviceProtocolGuid
diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c b/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
index d3851fd75fa5..e9c110a0ed75 100644
--- a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
+++ b/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
@@ -9,887 +9,11 @@
   SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
-#include <Guid/FileInfo.h>
-#include <Guid/FileSystemInfo.h>
-#include <Guid/FileSystemVolumeLabelInfo.h>
-#include <Library/PrintLib.h>
-#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuLoadImageLib.h>
 #include <Library/ReportStatusCodeLib.h>
-#include <Protocol/DevicePath.h>
-#include <Protocol/LoadedImage.h>
-#include <Protocol/SimpleFileSystem.h>
 
 #include "PlatformBm.h"
 
-//
-// Static data that hosts the fw_cfg blobs and serves file requests.
-//
-typedef enum {
-  KernelBlobTypeKernel,
-  KernelBlobTypeInitrd,
-  KernelBlobTypeCommandLine,
-  KernelBlobTypeMax
-} KERNEL_BLOB_TYPE;
-
-typedef struct {
-  FIRMWARE_CONFIG_ITEM CONST SizeKey;
-  FIRMWARE_CONFIG_ITEM CONST DataKey;
-  CONST CHAR16 *       CONST Name;
-  UINT32                     Size;
-  UINT8                      *Data;
-} KERNEL_BLOB;
-
-STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
-  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
-  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
-  { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, L"cmdline" }
-};
-
-STATIC UINT64 mTotalBlobBytes;
-
-//
-// Device path for the handle that incorporates our "EFI stub filesystem". The
-// GUID is arbitrary and need not be standardized or advertized.
-//
-#pragma pack(1)
-typedef struct {
-  VENDOR_DEVICE_PATH       VenHwNode;
-  EFI_DEVICE_PATH_PROTOCOL EndNode;
-} SINGLE_VENHW_NODE_DEVPATH;
-#pragma pack()
-
-STATIC CONST SINGLE_VENHW_NODE_DEVPATH mFileSystemDevicePath = {
-  {
-    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) } },
-    {
-      0xb0fae7e7, 0x6b07, 0x49d0,
-      { 0x9e, 0x5b, 0x3b, 0xde, 0xc8, 0x3b, 0x03, 0x9d }
-    }
-  },
-
-  {
-    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
-    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
-  }
-};
-
-//
-// The "file in the EFI stub filesystem" abstraction.
-//
-STATIC EFI_TIME mInitTime;
-
-#define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
-
-typedef struct {
-  UINT64            Signature; // Carries STUB_FILE_SIG.
-
-  KERNEL_BLOB_TYPE  BlobType;  // Index into mKernelBlob. KernelBlobTypeMax
-                               // denotes the root directory of the filesystem.
-
-  UINT64            Position;  // Byte position for regular files;
-                               // next directory entry to return for the root
-                               // directory.
-
-  EFI_FILE_PROTOCOL File;      // Standard protocol interface.
-} STUB_FILE;
-
-#define STUB_FILE_FROM_FILE(FilePointer) \
-        CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
-
-//
-// Tentative definition of the file protocol template. The initializer
-// (external definition) will be provided later.
-//
-STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate;
-
-
-//
-// Protocol member functions for File.
-//
-
-/**
-  Opens a new file relative to the source file's location.
-
-  @param[in]  This        A pointer to the EFI_FILE_PROTOCOL instance that is
-                          the file handle to the source location. This would
-                          typically be an open handle to a directory.
-
-  @param[out] NewHandle   A pointer to the location to return the opened handle
-                          for the new file.
-
-  @param[in]  FileName    The Null-terminated string of the name of the file to
-                          be opened. The file name may contain the following
-                          path modifiers: "\", ".", and "..".
-
-  @param[in]  OpenMode    The mode to open the file. The only valid
-                          combinations that the file may be opened with are:
-                          Read, Read/Write, or Create/Read/Write.
-
-  @param[in]  Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case
-                          these are the attribute bits for the newly created
-                          file.
-
-  @retval EFI_SUCCESS           The file was opened.
-  @retval EFI_NOT_FOUND         The specified file could not be found on the
-                                device.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
-                                medium is no longer supported.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a
-                                file for write when the media is
-                                write-protected.
-  @retval EFI_ACCESS_DENIED     The service denied access to the file.
-  @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
-                                file.
-  @retval EFI_VOLUME_FULL       The volume is full.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileOpen (
-  IN EFI_FILE_PROTOCOL  *This,
-  OUT EFI_FILE_PROTOCOL **NewHandle,
-  IN CHAR16             *FileName,
-  IN UINT64             OpenMode,
-  IN UINT64             Attributes
-  )
-{
-  CONST STUB_FILE *StubFile;
-  UINTN           BlobType;
-  STUB_FILE       *NewStubFile;
-
-  //
-  // We're read-only.
-  //
-  switch (OpenMode) {
-    case EFI_FILE_MODE_READ:
-      break;
-
-    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
-    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
-      return EFI_WRITE_PROTECTED;
-
-    default:
-      return EFI_INVALID_PARAMETER;
-  }
-
-  //
-  // Only the root directory supports opening files in it.
-  //
-  StubFile = STUB_FILE_FROM_FILE (This);
-  if (StubFile->BlobType != KernelBlobTypeMax) {
-    return EFI_UNSUPPORTED;
-  }
-
-  //
-  // Locate the file.
-  //
-  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
-    if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
-      break;
-    }
-  }
-  if (BlobType == KernelBlobTypeMax) {
-    return EFI_NOT_FOUND;
-  }
-
-  //
-  // Found it.
-  //
-  NewStubFile = AllocatePool (sizeof *NewStubFile);
-  if (NewStubFile == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  NewStubFile->Signature = STUB_FILE_SIG;
-  NewStubFile->BlobType  = (KERNEL_BLOB_TYPE)BlobType;
-  NewStubFile->Position  = 0;
-  CopyMem (&NewStubFile->File, &mEfiFileProtocolTemplate,
-    sizeof mEfiFileProtocolTemplate);
-  *NewHandle = &NewStubFile->File;
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Closes a specified file handle.
-
-  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
-                   handle to close.
-
-  @retval EFI_SUCCESS  The file was closed.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileClose (
-  IN EFI_FILE_PROTOCOL *This
-  )
-{
-  FreePool (STUB_FILE_FROM_FILE (This));
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Close and delete the file handle.
-
-  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
-                   handle to the file to delete.
-
-  @retval EFI_SUCCESS              The file was closed and deleted, and the
-                                   handle was closed.
-  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not
-                                   deleted.
-
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileDelete (
-  IN EFI_FILE_PROTOCOL *This
-  )
-{
-  FreePool (STUB_FILE_FROM_FILE (This));
-  return EFI_WARN_DELETE_FAILURE;
-}
-
-
-/**
-  Helper function that formats an EFI_FILE_INFO structure into the
-  user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
-  KernelBlobTypeMax, which stands for the root directory).
-
-  The interface follows the EFI_FILE_GET_INFO -- and for directories, the
-  EFI_FILE_READ -- interfaces.
-
-  @param[in]     BlobType     The KERNEL_BLOB_TYPE value identifying the fw_cfg
-                              blob backing the STUB_FILE that information is
-                              being requested about. If BlobType equals
-                              KernelBlobTypeMax, then information will be
-                              provided about the root directory of the
-                              filesystem.
-
-  @param[in,out] BufferSize  On input, the size of Buffer. On output, the
-                             amount of data returned in Buffer. In both cases,
-                             the size is measured in bytes.
-
-  @param[out]    Buffer      A pointer to the data buffer to return. The
-                             buffer's type is EFI_FILE_INFO.
-
-  @retval EFI_SUCCESS           The information was returned.
-  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small to store the
-                                EFI_FILE_INFO structure. BufferSize has been
-                                updated with the size needed to complete the
-                                request.
-**/
-STATIC
-EFI_STATUS
-ConvertKernelBlobTypeToFileInfo (
-  IN KERNEL_BLOB_TYPE BlobType,
-  IN OUT UINTN        *BufferSize,
-  OUT VOID            *Buffer
-  )
-{
-  CONST CHAR16  *Name;
-  UINT64        FileSize;
-  UINT64        Attribute;
-
-  UINTN         NameSize;
-  UINTN         FileInfoSize;
-  EFI_FILE_INFO *FileInfo;
-  UINTN         OriginalBufferSize;
-
-  if (BlobType == KernelBlobTypeMax) {
-    //
-    // getting file info about the root directory
-    //
-    Name      = L"\\";
-    FileSize  = KernelBlobTypeMax;
-    Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
-  } else {
-    CONST KERNEL_BLOB *Blob;
-
-    Blob      = &mKernelBlob[BlobType];
-    Name      = Blob->Name;
-    FileSize  = Blob->Size;
-    Attribute = EFI_FILE_READ_ONLY;
-  }
-
-  NameSize     = (StrLen(Name) + 1) * 2;
-  FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;
-  ASSERT (FileInfoSize >= sizeof *FileInfo);
-
-  OriginalBufferSize = *BufferSize;
-  *BufferSize        = FileInfoSize;
-  if (OriginalBufferSize < *BufferSize) {
-    return EFI_BUFFER_TOO_SMALL;
-  }
-
-  FileInfo               = (EFI_FILE_INFO *)Buffer;
-  FileInfo->Size         = FileInfoSize;
-  FileInfo->FileSize     = FileSize;
-  FileInfo->PhysicalSize = FileSize;
-  FileInfo->Attribute    = Attribute;
-
-  CopyMem (&FileInfo->CreateTime,       &mInitTime, sizeof mInitTime);
-  CopyMem (&FileInfo->LastAccessTime,   &mInitTime, sizeof mInitTime);
-  CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);
-  CopyMem (FileInfo->FileName,          Name,       NameSize);
-
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Reads data from a file, or continues scanning a directory.
-
-  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
-                             is the file handle to read data from.
-
-  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
-                             amount of data returned in Buffer. In both cases,
-                             the size is measured in bytes. If the read goes
-                             beyond the end of the file, the read length is
-                             truncated to the end of the file.
-
-                             If This is a directory, the function reads the
-                             directory entry at the current position and
-                             returns the entry (as EFI_FILE_INFO) in Buffer. If
-                             there are no more directory entries, the
-                             BufferSize is set to zero on output.
-
-  @param[out]    Buffer      The buffer into which the data is read.
-
-  @retval EFI_SUCCESS           Data was read.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted
-                                file.
-  @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond
-                                the end of the file.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
-                                current directory entry as a EFI_FILE_INFO
-                                structure. BufferSize has been updated with the
-                                size needed to complete the request, and the
-                                directory position has not been advanced.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileRead (
-  IN EFI_FILE_PROTOCOL *This,
-  IN OUT UINTN         *BufferSize,
-  OUT VOID             *Buffer
-  )
-{
-  STUB_FILE         *StubFile;
-  CONST KERNEL_BLOB *Blob;
-  UINT64            Left;
-
-  StubFile = STUB_FILE_FROM_FILE (This);
-
-  //
-  // Scanning the root directory?
-  //
-  if (StubFile->BlobType == KernelBlobTypeMax) {
-    EFI_STATUS Status;
-
-    if (StubFile->Position == KernelBlobTypeMax) {
-      //
-      // Scanning complete.
-      //
-      *BufferSize = 0;
-      return EFI_SUCCESS;
-    }
-
-    Status = ConvertKernelBlobTypeToFileInfo (
-               (KERNEL_BLOB_TYPE)StubFile->Position,
-               BufferSize,
-               Buffer);
-    if (EFI_ERROR (Status)) {
-      return Status;
-    }
-
-    ++StubFile->Position;
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Reading a file.
-  //
-  Blob = &mKernelBlob[StubFile->BlobType];
-  if (StubFile->Position > Blob->Size) {
-    return EFI_DEVICE_ERROR;
-  }
-
-  Left = Blob->Size - StubFile->Position;
-  if (*BufferSize > Left) {
-    *BufferSize = (UINTN)Left;
-  }
-  if (Blob->Data != NULL) {
-    CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
-  }
-  StubFile->Position += *BufferSize;
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Writes data to a file.
-
-  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
-                             is the file handle to write data to.
-
-  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
-                             amount of data actually written. In both cases,
-                             the size is measured in bytes.
-
-  @param[in]     Buffer      The buffer of data to write.
-
-  @retval EFI_SUCCESS           Data was written.
-  @retval EFI_UNSUPPORTED       Writes to open directory files are not
-                                supported.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_DEVICE_ERROR      An attempt was made to write to a deleted file.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
-  @retval EFI_ACCESS_DENIED     The file was opened read only.
-  @retval EFI_VOLUME_FULL       The volume is full.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileWrite (
-  IN EFI_FILE_PROTOCOL *This,
-  IN OUT UINTN         *BufferSize,
-  IN VOID              *Buffer
-  )
-{
-  STUB_FILE *StubFile;
-
-  StubFile = STUB_FILE_FROM_FILE (This);
-  return (StubFile->BlobType == KernelBlobTypeMax) ?
-         EFI_UNSUPPORTED :
-         EFI_WRITE_PROTECTED;
-}
-
-
-/**
-  Returns a file's current position.
-
-  @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is the
-                        file handle to get the current position on.
-
-  @param[out] Position  The address to return the file's current position
-                        value.
-
-  @retval EFI_SUCCESS      The position was returned.
-  @retval EFI_UNSUPPORTED  The request is not valid on open directories.
-  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
-                           deleted file.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileGetPosition (
-  IN EFI_FILE_PROTOCOL *This,
-  OUT UINT64           *Position
-  )
-{
-  STUB_FILE *StubFile;
-
-  StubFile = STUB_FILE_FROM_FILE (This);
-  if (StubFile->BlobType == KernelBlobTypeMax) {
-    return EFI_UNSUPPORTED;
-  }
-
-  *Position = StubFile->Position;
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Sets a file's current position.
-
-  @param[in] This      A pointer to the EFI_FILE_PROTOCOL instance that is the
-                       file handle to set the requested position on.
-
-  @param[in] Position  The byte position from the start of the file to set. For
-                       regular files, MAX_UINT64 means "seek to end". For
-                       directories, zero means "rewind directory scan".
-
-  @retval EFI_SUCCESS       The position was set.
-  @retval EFI_UNSUPPORTED   The seek request for nonzero is not valid on open
-                            directories.
-  @retval EFI_DEVICE_ERROR  An attempt was made to set the position of a
-                            deleted file.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileSetPosition (
-  IN EFI_FILE_PROTOCOL *This,
-  IN UINT64            Position
-  )
-{
-  STUB_FILE   *StubFile;
-  KERNEL_BLOB *Blob;
-
-  StubFile = STUB_FILE_FROM_FILE (This);
-
-  if (StubFile->BlobType == KernelBlobTypeMax) {
-    if (Position == 0) {
-      //
-      // rewinding a directory scan is allowed
-      //
-      StubFile->Position = 0;
-      return EFI_SUCCESS;
-    }
-    return EFI_UNSUPPORTED;
-  }
-
-  //
-  // regular file seek
-  //
-  Blob = &mKernelBlob[StubFile->BlobType];
-  if (Position == MAX_UINT64) {
-    //
-    // seek to end
-    //
-    StubFile->Position = Blob->Size;
-  } else {
-    //
-    // absolute seek from beginning -- seeking past the end is allowed
-    //
-    StubFile->Position = Position;
-  }
-  return EFI_SUCCESS;
-}
-
-
-/**
-  Returns information about a file.
-
-  @param[in]     This             A pointer to the EFI_FILE_PROTOCOL instance
-                                  that is the file handle the requested
-                                  information is for.
-
-  @param[in]     InformationType  The type identifier GUID for the information
-                                  being requested. The following information
-                                  types are supported, storing the
-                                  corresponding structures in Buffer:
-
-                                  - gEfiFileInfoGuid: EFI_FILE_INFO
-
-                                  - gEfiFileSystemInfoGuid:
-                                    EFI_FILE_SYSTEM_INFO
-
-                                  - gEfiFileSystemVolumeLabelInfoIdGuid:
-                                    EFI_FILE_SYSTEM_VOLUME_LABEL
-
-  @param[in,out] BufferSize       On input, the size of Buffer. On output, the
-                                  amount of data returned in Buffer. In both
-                                  cases, the size is measured in bytes.
-
-  @param[out]    Buffer           A pointer to the data buffer to return. The
-                                  buffer's type is indicated by
-                                  InformationType.
-
-  @retval EFI_SUCCESS           The information was returned.
-  @retval EFI_UNSUPPORTED       The InformationType is not known.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
-                                information structure requested by
-                                InformationType. BufferSize has been updated
-                                with the size needed to complete the request.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileGetInfo (
-  IN EFI_FILE_PROTOCOL *This,
-  IN EFI_GUID          *InformationType,
-  IN OUT UINTN         *BufferSize,
-  OUT VOID             *Buffer
-  )
-{
-  CONST STUB_FILE *StubFile;
-  UINTN           OriginalBufferSize;
-
-  StubFile = STUB_FILE_FROM_FILE (This);
-
-  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
-    return ConvertKernelBlobTypeToFileInfo (StubFile->BlobType, BufferSize,
-             Buffer);
-  }
-
-  OriginalBufferSize = *BufferSize;
-
-  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
-    EFI_FILE_SYSTEM_INFO *FileSystemInfo;
-
-    *BufferSize = sizeof *FileSystemInfo;
-    if (OriginalBufferSize < *BufferSize) {
-      return EFI_BUFFER_TOO_SMALL;
-    }
-
-    FileSystemInfo                 = (EFI_FILE_SYSTEM_INFO *)Buffer;
-    FileSystemInfo->Size           = sizeof *FileSystemInfo;
-    FileSystemInfo->ReadOnly       = TRUE;
-    FileSystemInfo->VolumeSize     = mTotalBlobBytes;
-    FileSystemInfo->FreeSpace      = 0;
-    FileSystemInfo->BlockSize      = 1;
-    FileSystemInfo->VolumeLabel[0] = L'\0';
-
-    return EFI_SUCCESS;
-  }
-
-  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
-    EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
-
-    *BufferSize = sizeof *FileSystemVolumeLabel;
-    if (OriginalBufferSize < *BufferSize) {
-      return EFI_BUFFER_TOO_SMALL;
-    }
-
-    FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
-    FileSystemVolumeLabel->VolumeLabel[0] = L'\0';
-
-    return EFI_SUCCESS;
-  }
-
-  return EFI_UNSUPPORTED;
-}
-
-
-/**
-  Sets information about a file.
-
-  @param[in] File             A pointer to the EFI_FILE_PROTOCOL instance that
-                              is the file handle the information is for.
-
-  @param[in] InformationType  The type identifier for the information being
-                              set.
-
-  @param[in] BufferSize       The size, in bytes, of Buffer.
-
-  @param[in] Buffer           A pointer to the data buffer to write. The
-                              buffer's type is indicated by InformationType.
-
-  @retval EFI_SUCCESS           The information was set.
-  @retval EFI_UNSUPPORTED       The InformationType is not known.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_WRITE_PROTECTED   InformationType is EFI_FILE_INFO_ID and the
-                                media is read-only.
-  @retval EFI_WRITE_PROTECTED   InformationType is
-                                EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
-                                is read only.
-  @retval EFI_WRITE_PROTECTED   InformationType is
-                                EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
-                                is read-only.
-  @retval EFI_ACCESS_DENIED     An attempt is made to change the name of a file
-                                to a file that is already present.
-  @retval EFI_ACCESS_DENIED     An attempt is being made to change the
-                                EFI_FILE_DIRECTORY Attribute.
-  @retval EFI_ACCESS_DENIED     An attempt is being made to change the size of
-                                a directory.
-  @retval EFI_ACCESS_DENIED     InformationType is EFI_FILE_INFO_ID and the
-                                file was opened read-only and an attempt is
-                                being made to modify a field other than
-                                Attribute.
-  @retval EFI_VOLUME_FULL       The volume is full.
-  @retval EFI_BAD_BUFFER_SIZE   BufferSize is smaller than the size of the type
-                                indicated by InformationType.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileSetInfo (
-  IN EFI_FILE_PROTOCOL *This,
-  IN EFI_GUID          *InformationType,
-  IN UINTN             BufferSize,
-  IN VOID              *Buffer
-  )
-{
-  return EFI_WRITE_PROTECTED;
-}
-
-
-/**
-  Flushes all modified data associated with a file to a device.
-
-  @param [in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
-                    file handle to flush.
-
-  @retval EFI_SUCCESS           The data was flushed.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
-  @retval EFI_ACCESS_DENIED     The file was opened read-only.
-  @retval EFI_VOLUME_FULL       The volume is full.
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileFlush (
-  IN EFI_FILE_PROTOCOL *This
-  )
-{
-  return EFI_WRITE_PROTECTED;
-}
-
-//
-// External definition of the file protocol template.
-//
-STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
-  EFI_FILE_PROTOCOL_REVISION, // revision 1
-  StubFileOpen,
-  StubFileClose,
-  StubFileDelete,
-  StubFileRead,
-  StubFileWrite,
-  StubFileGetPosition,
-  StubFileSetPosition,
-  StubFileGetInfo,
-  StubFileSetInfo,
-  StubFileFlush,
-  NULL,                       // OpenEx, revision 2
-  NULL,                       // ReadEx, revision 2
-  NULL,                       // WriteEx, revision 2
-  NULL                        // FlushEx, revision 2
-};
-
-
-//
-// Protocol member functions for SimpleFileSystem.
-//
-
-/**
-  Open the root directory on a volume.
-
-  @param[in]  This  A pointer to the volume to open the root directory on.
-
-  @param[out] Root  A pointer to the location to return the opened file handle
-                    for the root directory in.
-
-  @retval EFI_SUCCESS           The device was opened.
-  @retval EFI_UNSUPPORTED       This volume does not support the requested file
-                                system type.
-  @retval EFI_NO_MEDIA          The device has no medium.
-  @retval EFI_DEVICE_ERROR      The device reported an error.
-  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
-  @retval EFI_ACCESS_DENIED     The service denied access to the file.
-  @retval EFI_OUT_OF_RESOURCES  The volume was not opened due to lack of
-                                resources.
-  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
-                                medium is no longer supported. Any existing
-                                file handles for this volume are no longer
-                                valid. To access the files on the new medium,
-                                the volume must be reopened with OpenVolume().
-**/
-STATIC
-EFI_STATUS
-EFIAPI
-StubFileSystemOpenVolume (
-  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
-  OUT EFI_FILE_PROTOCOL              **Root
-  )
-{
-  STUB_FILE *StubFile;
-
-  StubFile = AllocatePool (sizeof *StubFile);
-  if (StubFile == NULL) {
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  StubFile->Signature = STUB_FILE_SIG;
-  StubFile->BlobType  = KernelBlobTypeMax;
-  StubFile->Position  = 0;
-  CopyMem (&StubFile->File, &mEfiFileProtocolTemplate,
-    sizeof mEfiFileProtocolTemplate);
-  *Root = &StubFile->File;
-
-  return EFI_SUCCESS;
-}
-
-STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
-  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
-  StubFileSystemOpenVolume
-};
-
-
-//
-// Utility functions.
-//
-
-/**
-  Populate a blob in mKernelBlob.
-
-  param[in,out] Blob  Pointer to the KERNEL_BLOB element in mKernelBlob that is
-                      to be filled from fw_cfg.
-
-  @retval EFI_SUCCESS           Blob has been populated. If fw_cfg reported a
-                                size of zero for the blob, then Blob->Data has
-                                been left unchanged.
-
-  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Blob->Data.
-**/
-STATIC
-EFI_STATUS
-FetchBlob (
-  IN OUT KERNEL_BLOB *Blob
-  )
-{
-  UINT32 Left;
-
-  //
-  // Read blob size.
-  //
-  QemuFwCfgSelectItem (Blob->SizeKey);
-  Blob->Size = QemuFwCfgRead32 ();
-  if (Blob->Size == 0) {
-    return EFI_SUCCESS;
-  }
-
-  //
-  // Read blob.
-  //
-  Blob->Data = AllocatePool (Blob->Size);
-  if (Blob->Data == NULL) {
-    DEBUG ((EFI_D_ERROR, "%a: failed to allocate %Ld bytes for \"%s\"\n",
-      __FUNCTION__, (INT64)Blob->Size, Blob->Name));
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  DEBUG ((EFI_D_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,
-    (INT64)Blob->Size, Blob->Name));
-  QemuFwCfgSelectItem (Blob->DataKey);
-
-  Left = Blob->Size;
-  do {
-    UINT32 Chunk;
-
-    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
-    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));
-    Left -= Chunk;
-    DEBUG ((EFI_D_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",
-      __FUNCTION__, (INT64)Left, Blob->Name));
-  } while (Left > 0);
-  return EFI_SUCCESS;
-}
-
-
 //
 // The entry point of the feature.
 //
@@ -916,159 +40,14 @@ TryRunningQemuKernel (
   VOID
   )
 {
-  UINTN                     BlobType;
-  KERNEL_BLOB               *CurrentBlob;
-  KERNEL_BLOB               *KernelBlob, *InitrdBlob, *CommandLineBlob;
   EFI_STATUS                Status;
-  EFI_HANDLE                FileSystemHandle;
-  EFI_DEVICE_PATH_PROTOCOL  *KernelDevicePath;
   EFI_HANDLE                KernelImageHandle;
-  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
 
-  Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);
+  Status = QemuLoadKernelImage (&KernelImageHandle);
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "%a: GetTime(): %r\n", __FUNCTION__, Status));
     return Status;
   }
 
-  //
-  // Fetch all blobs.
-  //
-  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
-    CurrentBlob = &mKernelBlob[BlobType];
-    Status = FetchBlob (CurrentBlob);
-    if (EFI_ERROR (Status)) {
-      goto FreeBlobs;
-    }
-    mTotalBlobBytes += CurrentBlob->Size;
-  }
-  KernelBlob      = &mKernelBlob[KernelBlobTypeKernel];
-  InitrdBlob      = &mKernelBlob[KernelBlobTypeInitrd];
-  CommandLineBlob = &mKernelBlob[KernelBlobTypeCommandLine];
-
-  if (KernelBlob->Data == NULL) {
-    Status = EFI_NOT_FOUND;
-    goto FreeBlobs;
-  }
-
-  //
-  // Create a new handle with a single VenHw() node device path protocol on it,
-  // plus a custom SimpleFileSystem protocol on it.
-  //
-  FileSystemHandle = NULL;
-  Status = gBS->InstallMultipleProtocolInterfaces (&FileSystemHandle,
-                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
-                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
-                  NULL);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
-      __FUNCTION__, Status));
-    goto FreeBlobs;
-  }
-
-  //
-  // Create a device path for the kernel image to be loaded from that will call
-  // back into our file system.
-  //
-  KernelDevicePath = FileDevicePath (FileSystemHandle, KernelBlob->Name);
-  if (KernelDevicePath == NULL) {
-    DEBUG ((EFI_D_ERROR, "%a: failed to allocate kernel device path\n",
-      __FUNCTION__));
-    Status = EFI_OUT_OF_RESOURCES;
-    goto UninstallProtocols;
-  }
-
-  //
-  // Load the image. This should call back into our file system.
-  //
-  Status = gBS->LoadImage (
-                  FALSE,             // BootPolicy: exact match required
-                  gImageHandle,      // ParentImageHandle
-                  KernelDevicePath,
-                  NULL,              // SourceBuffer
-                  0,                 // SourceSize
-                  &KernelImageHandle
-                  );
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));
-    if (Status != EFI_SECURITY_VIOLATION) {
-      goto FreeKernelDevicePath;
-    }
-    //
-    // From the resource allocation perspective, EFI_SECURITY_VIOLATION means
-    // "success", so we must roll back the image loading.
-    //
-    goto UnloadKernelImage;
-  }
-
-  //
-  // 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);
-
-  if (CommandLineBlob->Data == NULL) {
-    KernelLoadedImage->LoadOptionsSize = 0;
-  } else {
-    //
-    // Verify NUL-termination of the command line.
-    //
-    if (CommandLineBlob->Data[CommandLineBlob->Size - 1] != '\0') {
-      DEBUG ((EFI_D_ERROR, "%a: kernel command line is not NUL-terminated\n",
-        __FUNCTION__));
-      Status = EFI_PROTOCOL_ERROR;
-      goto UnloadKernelImage;
-    }
-
-    //
-    // Drop the terminating NUL, convert to UTF-16.
-    //
-    KernelLoadedImage->LoadOptionsSize = (CommandLineBlob->Size - 1) * 2;
-  }
-
-  if (InitrdBlob->Data != NULL) {
-    //
-    // Append ' initrd=<name>' in UTF-16.
-    //
-    KernelLoadedImage->LoadOptionsSize +=
-                                        (8 + StrLen(InitrdBlob->Name)) * 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 UnloadKernelImage;
-    }
-
-    UnicodeSPrintAsciiFormat (
-      KernelLoadedImage->LoadOptions,
-      KernelLoadedImage->LoadOptionsSize,
-      "%a%a%s",
-      (CommandLineBlob->Data == NULL) ?  "" : (CHAR8 *)CommandLineBlob->Data,
-      (InitrdBlob->Data      == NULL) ?  "" : " initrd=",
-      (InitrdBlob->Data      == NULL) ? L"" : InitrdBlob->Name
-      );
-    DEBUG ((EFI_D_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,
-      (CHAR16 *)KernelLoadedImage->LoadOptions));
-  }
-
   //
   // Signal the EFI_EVENT_GROUP_READY_TO_BOOT event.
   //
@@ -1080,41 +59,13 @@ TryRunningQemuKernel (
   //
   // Start the image.
   //
-  Status = gBS->StartImage (
-                KernelImageHandle,
-                NULL,              // ExitDataSize
-                NULL               // ExitData
-                );
+  Status = QemuStartKernelImage (&KernelImageHandle);
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "%a: StartImage(): %r\n", __FUNCTION__, Status));
+    DEBUG ((DEBUG_ERROR, "%a: QemuStartKernelImage(): %r\n", __FUNCTION__,
+      Status));
   }
 
-  if (KernelLoadedImage->LoadOptions != NULL) {
-    FreePool (KernelLoadedImage->LoadOptions);
-  }
-  KernelLoadedImage->LoadOptionsSize = 0;
-
-UnloadKernelImage:
-  gBS->UnloadImage (KernelImageHandle);
-
-FreeKernelDevicePath:
-  FreePool (KernelDevicePath);
-
-UninstallProtocols:
-  gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,
-         &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
-         &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
-         NULL);
-
-FreeBlobs:
-  while (BlobType > 0) {
-    CurrentBlob = &mKernelBlob[--BlobType];
-    if (CurrentBlob->Data != NULL) {
-      FreePool (CurrentBlob->Data);
-      CurrentBlob->Size = 0;
-      CurrentBlob->Data = NULL;
-    }
-  }
+  QemuUnloadKernelImage (KernelImageHandle);
 
   return Status;
 }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (5 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

We have no need for exposing the kernel command line as a file,
so remove support for that. Since the remaining blobs (kernel
and initrd) are typically much larger than a page, switch to
the page based allocator for blobs at the same time.

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>
---
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
index e4539ec2fbe5..dc86a48af378 100644
--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
@@ -30,7 +30,6 @@
 typedef enum {
   KernelBlobTypeKernel,
   KernelBlobTypeInitrd,
-  KernelBlobTypeCommandLine,
   KernelBlobTypeMax
 } KERNEL_BLOB_TYPE;
 
@@ -45,7 +44,6 @@ typedef struct {
 STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
   { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
   { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
-  { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, L"cmdline" }
 };
 
 STATIC UINT64 mTotalBlobBytes;
@@ -865,7 +863,7 @@ FetchBlob (
   //
   // Read blob.
   //
-  Blob->Data = AllocatePool (Blob->Size);
+  Blob->Data = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)Blob->Size));
   if (Blob->Data == NULL) {
     DEBUG ((DEBUG_ERROR, "%a: failed to allocate %Ld bytes for \"%s\"\n",
       __FUNCTION__, (INT64)Blob->Size, Blob->Name));
@@ -969,7 +967,8 @@ QemuKernelLoaderFsDxeEntrypoint (
   while (BlobType > 0) {
     CurrentBlob = &mKernelBlob[--BlobType];
     if (CurrentBlob->Data != NULL) {
-      FreePool (CurrentBlob->Data);
+      FreePages (CurrentBlob->Data,
+        EFI_SIZE_TO_PAGES ((UINTN)CurrentBlob->Size));
       CurrentBlob->Size = 0;
       CurrentBlob->Data = NULL;
     }
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (6 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 10:12   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images Ard Biesheuvel
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

On x86, the kernel image consists of a setup block and the actual kernel,
and QEMU presents these as separate blobs, whereas on disk (and in terms
of PE/COFF image signing), they consist of a single image.

So add support to our FS loader driver to expose files via the abstract
file system that consist of up to two concatenated blobs, and redefine
the kernel file so it consists of the setup and kernel blobs, on every
architecture (on non-x86, the setup block is simply 0 bytes and is
therefore ignored implicitly)

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 74 ++++++++++++++------
 1 file changed, 53 insertions(+), 21 deletions(-)

diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
index dc86a48af378..8ccb1983170c 100644
--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
@@ -34,16 +34,29 @@ typedef enum {
 } KERNEL_BLOB_TYPE;
 
 typedef struct {
-  FIRMWARE_CONFIG_ITEM CONST SizeKey;
-  FIRMWARE_CONFIG_ITEM CONST DataKey;
-  CONST CHAR16 *       CONST Name;
-  UINT32                     Size;
-  UINT8                      *Data;
+  CONST CHAR16                  Name[8];
+  struct {
+    FIRMWARE_CONFIG_ITEM CONST  SizeKey;
+    FIRMWARE_CONFIG_ITEM CONST  DataKey;
+    UINT32                      Size;
+  }                             FwCfgItem[2];
+  UINT32                        Size;
+  UINT8                         *Data;
 } KERNEL_BLOB;
 
 STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
-  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
-  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
+  {
+    L"kernel",
+    {
+      { QemuFwCfgItemKernelSetupSize, QemuFwCfgItemKernelSetupData, },
+      { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      },
+    }
+  }, {
+    L"initrd",
+    {
+      { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      },
+    }
+  }
 };
 
 STATIC UINT64 mTotalBlobBytes;
@@ -850,12 +863,21 @@ FetchBlob (
   )
 {
   UINT32 Left;
+  UINTN  Idx;
+  UINT8  *ChunkData;
 
   //
   // Read blob size.
   //
-  QemuFwCfgSelectItem (Blob->SizeKey);
-  Blob->Size = QemuFwCfgRead32 ();
+  Blob->Size = 0;
+  for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
+    if (Blob->FwCfgItem[Idx].SizeKey == 0) {
+      break;
+    }
+    QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey);
+    Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
+    Blob->Size += Blob->FwCfgItem[Idx].Size;
+  }
   if (Blob->Size == 0) {
     return EFI_SUCCESS;
   }
@@ -872,18 +894,28 @@ FetchBlob (
 
   DEBUG ((DEBUG_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,
     (INT64)Blob->Size, Blob->Name));
-  QemuFwCfgSelectItem (Blob->DataKey);
-
-  Left = Blob->Size;
-  do {
-    UINT32 Chunk;
-
-    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
-    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));
-    Left -= Chunk;
-    DEBUG ((DEBUG_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",
-      __FUNCTION__, (INT64)Left, Blob->Name));
-  } while (Left > 0);
+
+  ChunkData = Blob->Data;
+  for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
+    if (Blob->FwCfgItem[Idx].DataKey == 0) {
+      break;
+    }
+    QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey);
+
+    Left = Blob->FwCfgItem[Idx].Size;
+    while (Left > 0) {
+      UINT32 Chunk;
+
+      Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
+      QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left);
+      Left -= Chunk;
+      DEBUG ((DEBUG_VERBOSE, "%a: %Ld bytes remaining for \"%s\" (%d)\n",
+        __FUNCTION__, (INT64)Left, Blob->Name, (INT32)Idx));
+    }
+
+    ChunkData += Blob->FwCfgItem[Idx].Size;
+  }
+
   return EFI_SUCCESS;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (7 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 10:31   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

In preparation of moving the legacy x86 loading to an implementation
of the QEMU load image library class, introduce a protocol header
and GUID that we will use to identify legacy loaded images in the
protocol database.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h | 19 +++++++++++++++++++
 OvmfPkg/OvmfPkg.dec                                 |  1 +
 2 files changed, 20 insertions(+)

diff --git a/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
new file mode 100644
index 000000000000..7e1bebaa6a07
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
@@ -0,0 +1,19 @@
+/** @file
+  Protocol/GUID definition to describe a kernel image loaded by the legacy X86
+  loader from the file specified on the QEMU command line via the -kernel
+  option.
+
+  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__
+#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__
+
+#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID \
+  {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
+
+extern EFI_GUID gX86QemuKernelLoadedImageGuid;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 055caaa43041..06ffd4198d44 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -112,6 +112,7 @@ [Protocols]
   gEfiLegacyBiosPlatformProtocolGuid  = {0x783658a3, 0x4172, 0x4421, {0xa2, 0x99, 0xe0, 0x09, 0x07, 0x9c, 0x0c, 0xb4}}
   gEfiLegacyInterruptProtocolGuid     = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
   gEfiVgaMiniPortProtocolGuid         = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
+  gX86QemuKernelLoadedImageGuid       = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
 
 [PcdsFixedAtBuild]
   gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (8 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 12:33   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 11/14] OvmfPkg: add new QEMU kernel image loader components Ard Biesheuvel
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

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=2566
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 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/OvmfPkg/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.<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/X86QemuKernelLoadedImage.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) }
+  }
+};
+
+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 != 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;
+  QEMU_LEGACY_LOADED_IMAGE        *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));
+    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));
+    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,
+                  &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 = 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 = gBS->OpenProtocol (ImageHandle,
+                  &gX86QemuKernelLoadedImageGuid,
+                  (VOID **)&LoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = 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 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:
+    //
+    // 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 unload
+    // 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 directly.
+    //
+    Status = QemuLoadLegacyImage (&KernelImageHandle);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: QemuLoadLegacyImage(): %r\n", __FUNCTION__,
+        Status));
+      return Status;
+    }
+    *ImageHandle = KernelImageHandle;
+    return EFI_SUCCESS;
+
+  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);
+    ASSERT (CommandLine != NULL);
+
+    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:
+  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 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;
+  QEMU_LEGACY_LOADED_IMAGE      *LoadedImage;
+  EFI_HANDLE                    KernelImageHandle;
+
+  Status = gBS->OpenProtocol (*ImageHandle,
+                  &gX86QemuKernelLoadedImageGuid,
+                  (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) {
+    //
+    // 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 unload the
+    // image, and reload and start it using the legacy loader.
+    //
+    QemuUnloadKernelImage (*ImageHandle);
+
+    Status = QemuLoadLegacyImage (&KernelImageHandle);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    *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 an 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);
+}
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.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.27
+  BASE_NAME                      = X86QemuLoadImageLib
+  FILE_GUID                      = 2304df80-e21d-4170-9c3c-113c878f7ac0
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = 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
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 11/14] OvmfPkg: add new QEMU kernel image loader components
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (9 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Add the components that expose the QEMU abstract loader file system so
that we can switch over our PlatformBmLib over to it in a subsequent
patch.

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>
---
 OvmfPkg/OvmfPkgIa32.dsc    | 2 ++
 OvmfPkg/OvmfPkgIa32.fdf    | 1 +
 OvmfPkg/OvmfPkgIa32X64.dsc | 2 ++
 OvmfPkg/OvmfPkgIa32X64.fdf | 1 +
 OvmfPkg/OvmfPkgX64.dsc     | 2 ++
 OvmfPkg/OvmfPkgX64.fdf     | 1 +
 6 files changed, 9 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 8d91903f8b4e..2cc924a6986a 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -361,6 +361,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
@@ -711,6 +712,7 @@ [Components]
       NULL|OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
 !endif
   }
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
   OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
   OvmfPkg/Virtio10Dxe/Virtio10.inf
   OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
diff --git a/OvmfPkg/OvmfPkgIa32.fdf b/OvmfPkg/OvmfPkgIa32.fdf
index f57de4a26f92..61287bd51f84 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.fdf
@@ -242,6 +242,7 @@ [FV.DXEFV]
 INF  MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
 INF  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
 INF  MdeModulePkg/Application/UiApp/UiApp.inf
+INF  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 842b4a028913..21d1f156973b 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -365,6 +365,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
@@ -723,6 +724,7 @@ [Components.X64]
       NULL|OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
 !endif
   }
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
   OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
   OvmfPkg/Virtio10Dxe/Virtio10.inf
   OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.fdf b/OvmfPkg/OvmfPkgIa32X64.fdf
index 69c133ec08d5..7b770f8fa424 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -243,6 +243,7 @@ [FV.DXEFV]
 INF  MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
 INF  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
 INF  MdeModulePkg/Application/UiApp/UiApp.inf
+INF  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 0b1e45d1f15a..f3d0f18db7e2 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -365,6 +365,7 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+  QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
@@ -721,6 +722,7 @@ [Components]
       NULL|OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
 !endif
   }
+  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
   OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf
   OvmfPkg/Virtio10Dxe/Virtio10.inf
   OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
index 69c133ec08d5..7b770f8fa424 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -243,6 +243,7 @@ [FV.DXEFV]
 INF  MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf
 INF  MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
 INF  MdeModulePkg/Application/UiApp/UiApp.inf
+INF  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
 INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
 INF  MdeModulePkg/Universal/PrintDxe/PrintDxe.inf
 INF  MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (10 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 11/14] OvmfPkg: add new QEMU kernel image loader components Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 12:57   ` [edk2-devel] " Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
  2020-03-04  9:52 ` [PATCH v2 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Replace the open coded sequence to load Linux on x86 with a short and
generic sequence invoking QemuLoadImageLib, which can be provided by
a generic version that only supports the LoadImage and StartImage boot
services, and one that incorporates the entire legacy loading sequence
as well.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |   2 +-
 OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c               | 144 ++------------------
 2 files changed, 14 insertions(+), 132 deletions(-)

diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
index f89cce187942..40ac5dd7f9d5 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -48,7 +48,7 @@ [LibraryClasses]
   NvVarsFileLib
   QemuFwCfgLib
   QemuFwCfgS3Lib
-  LoadLinuxLib
+  QemuLoadImageLib
   QemuBootOrderLib
   ReportStatusCodeLib
   UefiLib
diff --git a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
index ddfef925edd3..c6255921779e 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
+++ b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
@@ -9,11 +9,8 @@
 
 #include <Library/BaseLib.h>
 #include <Library/DebugLib.h>
-#include <Library/LoadLinuxLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuLoadImageLib.h>
 #include <Library/ReportStatusCodeLib.h>
-#include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 
 
@@ -23,120 +20,11 @@ TryRunningQemuKernel (
   )
 {
   EFI_STATUS                Status;
-  UINTN                     KernelSize;
-  UINTN                     KernelInitialSize;
-  VOID                      *KernelBuf;
-  UINTN                     SetupSize;
-  VOID                      *SetupBuf;
-  UINTN                     CommandLineSize;
-  CHAR8                     *CommandLine;
-  UINTN                     InitrdSize;
-  VOID*                     InitrdData;
+  EFI_HANDLE                KernelImageHandle;
 
-  SetupBuf = NULL;
-  SetupSize = 0;
-  KernelBuf = NULL;
-  KernelInitialSize = 0;
-  CommandLine = NULL;
-  CommandLineSize = 0;
-  InitrdData = NULL;
-  InitrdSize = 0;
-
-  if (!QemuFwCfgIsAvailable ()) {
-    return EFI_NOT_FOUND;
-  }
-
-  QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
-  KernelSize = (UINTN) QemuFwCfgRead64 ();
-
-  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
-  SetupSize = (UINTN) QemuFwCfgRead64 ();
-
-  if (KernelSize == 0 || SetupSize == 0) {
-    DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
-    return EFI_NOT_FOUND;
-  }
-
-  SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES (SetupSize));
-  if (SetupBuf == NULL) {
-    DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
-    return EFI_OUT_OF_RESOURCES;
-  }
-
-  DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
-  DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
-  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
-  QemuFwCfgReadBytes (SetupSize, SetupBuf);
-  DEBUG ((EFI_D_INFO, " [done]\n"));
-
-  Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize);
-  if (EFI_ERROR (Status)) {
-    goto FreeAndReturn;
-  }
-
-  Status = LoadLinuxInitializeKernelSetup (SetupBuf);
-  if (EFI_ERROR (Status)) {
-    goto FreeAndReturn;
-  }
-
-  KernelInitialSize = LoadLinuxGetKernelSize (SetupBuf, KernelSize);
-  if (KernelInitialSize == 0) {
-    Status = EFI_UNSUPPORTED;
-    goto FreeAndReturn;
-  }
-
-  KernelBuf = LoadLinuxAllocateKernelPages (
-                SetupBuf,
-                EFI_SIZE_TO_PAGES (KernelInitialSize));
-  if (KernelBuf == NULL) {
-    DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel!\n"));
-    Status = EFI_OUT_OF_RESOURCES;
-    goto FreeAndReturn;
-  }
-
-  DEBUG ((EFI_D_INFO, "Kernel size: 0x%x\n", (UINT32) KernelSize));
-  DEBUG ((EFI_D_INFO, "Reading kernel image ..."));
-  QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
-  QemuFwCfgReadBytes (KernelSize, KernelBuf);
-  DEBUG ((EFI_D_INFO, " [done]\n"));
-
-  QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
-  CommandLineSize = (UINTN) QemuFwCfgRead64 ();
-
-  if (CommandLineSize > 0) {
-    CommandLine = LoadLinuxAllocateCommandLinePages (
-                    EFI_SIZE_TO_PAGES (CommandLineSize));
-    QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
-    QemuFwCfgReadBytes (CommandLineSize, CommandLine);
-  } else {
-    CommandLine = NULL;
-  }
-
-  Status = LoadLinuxSetCommandLine (SetupBuf, CommandLine);
-  if (EFI_ERROR (Status)) {
-    goto FreeAndReturn;
-  }
-
-  QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
-  InitrdSize = (UINTN) QemuFwCfgRead64 ();
-
-  if (InitrdSize > 0) {
-    InitrdData = LoadLinuxAllocateInitrdPages (
-                   SetupBuf,
-                   EFI_SIZE_TO_PAGES (InitrdSize)
-                   );
-    DEBUG ((EFI_D_INFO, "Initrd size: 0x%x\n", (UINT32) InitrdSize));
-    DEBUG ((EFI_D_INFO, "Reading initrd image ..."));
-    QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);
-    QemuFwCfgReadBytes (InitrdSize, InitrdData);
-    DEBUG ((EFI_D_INFO, " [done]\n"));
-  } else {
-    InitrdData = NULL;
-  }
-
-  Status = LoadLinuxSetInitrd (SetupBuf, InitrdData, InitrdSize);
+  Status = QemuLoadKernelImage (&KernelImageHandle);
   if (EFI_ERROR (Status)) {
-    goto FreeAndReturn;
+    return Status;
   }
 
   //
@@ -147,22 +35,16 @@ TryRunningQemuKernel (
   REPORT_STATUS_CODE (EFI_PROGRESS_CODE,
     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
 
-  Status = LoadLinux (KernelBuf, SetupBuf);
+  //
+  // Start the image.
+  //
+  Status = QemuStartKernelImage (&KernelImageHandle);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: QemuStartKernelImage(): %r\n", __FUNCTION__,
+      Status));
+  }
 
-FreeAndReturn:
-  if (SetupBuf != NULL) {
-    FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
-  }
-  if (KernelBuf != NULL) {
-    FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize));
-  }
-  if (CommandLine != NULL) {
-    FreePages (CommandLine, EFI_SIZE_TO_PAGES (CommandLineSize));
-  }
-  if (InitrdData != NULL) {
-    FreePages (InitrdData, EFI_SIZE_TO_PAGES (InitrdSize));
-  }
+  QemuUnloadKernelImage (KernelImageHandle);
 
   return Status;
 }
-
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (11 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  2020-03-05 13:19   ` Laszlo Ersek
  2020-03-04  9:52 ` [PATCH v2 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel
  13 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

Linux v5.7 will introduce a new method to load the initial ramdisk
(initrd) from the loader, using the LoadFile2 protocol installed on a
special vendor GUIDed media device path.

Add support for this to our QEMU command line kernel/initrd loader.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c   | 79 ++++++++++++++++++++
 OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf |  2 +
 2 files changed, 81 insertions(+)

diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
index 8ccb1983170c..f43b4c0db0ec 100644
--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
@@ -13,15 +13,18 @@
 #include <Guid/FileInfo.h>
 #include <Guid/FileSystemInfo.h>
 #include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/LinuxEfiInitrdMedia.h>
 #include <Guid/QemuKernelLoaderFsMedia.h>
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/QemuFwCfgLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
 #include <Protocol/DevicePath.h>
+#include <Protocol/LoadFile2.h>
 #include <Protocol/SimpleFileSystem.h>
 
 //
@@ -84,6 +87,19 @@ STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath = {
   }
 };
 
+STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath = {
+  {
+    {
+      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+      { sizeof (VENDOR_DEVICE_PATH) }
+    },
+    LINUX_EFI_INITRD_MEDIA_GUID
+  }, {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
+  }
+};
+
 //
 // The "file in the EFI stub filesystem" abstraction.
 //
@@ -839,6 +855,48 @@ STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
   StubFileSystemOpenVolume
 };
 
+STATIC
+EFI_STATUS
+EFIAPI
+InitrdLoadFile2 (
+  IN EFI_LOAD_FILE2_PROTOCOL          *This,
+  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
+  IN BOOLEAN                          BootPolicy,
+  IN OUT UINTN                        *BufferSize,
+  IN VOID                             *Buffer OPTIONAL
+  )
+{
+  CONST KERNEL_BLOB   *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
+
+  ASSERT (InitrdBlob->Size > 0);
+
+  if (BootPolicy) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (BufferSize == NULL || !IsDevicePathValid (FilePath, 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (FilePath->Type != END_DEVICE_PATH_TYPE ||
+      FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (Buffer == NULL || *BufferSize < InitrdBlob->Size) {
+    *BufferSize = InitrdBlob->Size;
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  CopyMem (Buffer, InitrdBlob->Data, InitrdBlob->Size);
+
+  *BufferSize = InitrdBlob->Size;
+  return EFI_SUCCESS;
+}
+
+STATIC CONST EFI_LOAD_FILE2_PROTOCOL     mInitrdLoadFile2 = {
+  InitrdLoadFile2,
+};
 
 //
 // Utility functions.
@@ -949,6 +1007,7 @@ QemuKernelLoaderFsDxeEntrypoint (
   KERNEL_BLOB               *KernelBlob;
   EFI_STATUS                Status;
   EFI_HANDLE                FileSystemHandle;
+  EFI_HANDLE                InitrdLoadFile2Handle;
 
   if (!QemuFwCfgIsAvailable ()) {
     return EFI_NOT_FOUND;
@@ -993,8 +1052,28 @@ QemuKernelLoaderFsDxeEntrypoint (
     goto FreeBlobs;
   }
 
+  if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
+    InitrdLoadFile2Handle = NULL;
+    Status = gBS->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle,
+                    &gEfiDevicePathProtocolGuid,  &mInitrdDevicePath,
+                    &gEfiLoadFile2ProtocolGuid,   &mInitrdLoadFile2,
+                    NULL);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
+        __FUNCTION__, Status));
+      goto UninstallFileSystemHandle;
+    }
+  }
+
   return EFI_SUCCESS;
 
+UninstallFileSystemHandle:
+  Status = gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,
+                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
+                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
+                  NULL);
+  ASSERT_EFI_ERROR (Status);
+
 FreeBlobs:
   while (BlobType > 0) {
     CurrentBlob = &mKernelBlob[--BlobType];
diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
index 5ba88063def0..7b35adb8e034 100644
--- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
+++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
@@ -28,6 +28,7 @@ [LibraryClasses]
   BaseLib
   BaseMemoryLib
   DebugLib
+  DevicePathLib
   MemoryAllocationLib
   QemuFwCfgLib
   UefiBootServicesTableLib
@@ -42,6 +43,7 @@ [Guids]
 
 [Protocols]
   gEfiDevicePathProtocolGuid                ## PRODUCES
+  gEfiLoadFile2ProtocolGuid                 ## PRODUCES
   gEfiSimpleFileSystemProtocolGuid          ## PRODUCES
 
 [Depex]
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (12 preceding siblings ...)
  2020-03-04  9:52 ` [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
@ 2020-03-04  9:52 ` Ard Biesheuvel
  13 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-04  9:52 UTC (permalink / raw)
  To: devel; +Cc: lersek, Ard Biesheuvel

The QemuLoadImageLib implementation we currently use for all OVMF
builds copies the behavior of the QEMU loader code that precedes it,
which is to disregard UEFI secure boot policies entirely when it comes
to loading kernel images that have been specified on the QEMU command
line. This behavior deviates from ArmVirtQemu based builds, which do
take UEFI secure boot policies into account, and refuse to load images
from the command line that cannot be authenticated.

The disparity was originally due to the fact that the QEMU command line
kernel loader did not use LoadImage and StartImage at all, but this
changed recently, and now, there are only a couple of reasons left to
stick with the legacy loader:
- it permits loading images that lack a valid PE/COFF header,
- it permits loading X64 kernels on IA32 firmware running on a X64
  capable system.

Since every non-authentic PE/COFF image can trivially be converted into
an image that lacks a valid PE/COFF header, the former case can simply
not be supported in a UEFI secure boot context. The latter case is highly
theoretical, given that one could easily switch to native X64 firmware in
a VM scenario.

That leaves us with little justification to use the legacy loader at all
when UEFI secure boot policies are in effect, so let's switch to the
generic loader for UEFI secure boot enabled builds.

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>
---
 OvmfPkg/OvmfPkgIa32.dsc    | 4 ++++
 OvmfPkg/OvmfPkgIa32X64.dsc | 4 ++++
 OvmfPkg/OvmfPkgX64.dsc     | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 2cc924a6986a..eceddb71948f 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -361,7 +361,11 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+!if $(SECURE_BOOT_ENABLE) == TRUE
+  QemuLoadImageLib|OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+!else
   QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
+!endif
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 21d1f156973b..8bdf2e692b00 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -365,7 +365,11 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+!if $(SECURE_BOOT_ENABLE) == TRUE
+  QemuLoadImageLib|OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+!else
   QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
+!endif
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index f3d0f18db7e2..bc0a3e438d2a 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -365,7 +365,11 @@ [LibraryClasses.common.DXE_DRIVER]
   PciLib|OvmfPkg/Library/DxePciLibI440FxQ35/DxePciLibI440FxQ35.inf
   MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
   QemuFwCfgS3Lib|OvmfPkg/Library/QemuFwCfgS3Lib/DxeQemuFwCfgS3LibFwCfg.inf
+!if $(SECURE_BOOT_ENABLE) == TRUE
+  QemuLoadImageLib|OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
+!else
   QemuLoadImageLib|OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
+!endif
 !if $(TPM2_ENABLE) == TRUE
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
 !endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class
  2020-03-04  9:52 ` [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
@ 2020-03-05  9:37   ` Laszlo Ersek
  2020-03-05  9:39     ` Laszlo Ersek
  0 siblings, 1 reply; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05  9:37 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> Introduce the QemuLoadImageLib library class that we will instantiate
> to load the kernel image passed via the QEMU command line using the
> standard LoadImage boot service.
> 
> 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>
> ---
>  OvmfPkg/Include/Library/QemuLoadImageLib.h | 84 ++++++++++++++++++++
>  OvmfPkg/OvmfPkg.dec                        |  5 ++
>  2 files changed, 89 insertions(+)
> 
> diff --git a/OvmfPkg/Include/Library/QemuLoadImageLib.h b/OvmfPkg/Include/Library/QemuLoadImageLib.h
> new file mode 100644
> index 000000000000..694905a6421b
> --- /dev/null
> +++ b/OvmfPkg/Include/Library/QemuLoadImageLib.h
> @@ -0,0 +1,84 @@
> +/** @file
> +  Load a kernel image and command line passed to QEMU via
> +  the command line
> +
> +  Copyright (C) 2020, Arm, Limited.
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef QEMU_LOAD_IMAGE_LIB_H__
> +#define QEMU_LOAD_IMAGE_LIB_H__
> +
> +#include <Uefi/UefiBaseType.h>
> +#include <Base.h>
> +
> +#include <Protocol/LoadedImage.h>
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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.
> +                                  On success, the function doesn't return.
> +**/
> +EFI_STATUS
> +EFIAPI
> +QemuStartKernelImage (
> +  IN  OUT EFI_HANDLE          *ImageHandle
> +  );
> +
> +/**
> +  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.

(1) The above apostrophe (in the "image’s" expression) is U+2019 ("RIGHT
SINGLE QUOTATION MARK"). Please replace it with a normal ASCII 0x27
character (U+0027, "APOSTROPHE") when you push the series.

Thanks
Laszlo


> +**/
> +EFI_STATUS
> +EFIAPI
> +QemuUnloadKernelImage (
> +  IN  EFI_HANDLE          ImageHandle
> +  );
> +
> +#endif
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index a21b279d140a..055caaa43041 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -58,6 +58,11 @@ [LibraryClasses]
>    #
>    QemuBootOrderLib|Include/Library/QemuBootOrderLib.h
>  
> +  ##  @libraryclass  Load a kernel image and command line passed to QEMU via
> +  #                  the command line
> +  #
> +  QemuLoadImageLib|Include/Library/QemuLoadImageLib.h
> +
>    ##  @libraryclass  Serialize (and deserialize) variables
>    #
>    SerializeVariablesLib|Include/Library/SerializeVariablesLib.h
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class
  2020-03-05  9:37   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-05  9:39     ` Laszlo Ersek
  2020-03-05 10:22       ` Ard Biesheuvel
  0 siblings, 1 reply; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05  9:39 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/05/20 10:37, Laszlo Ersek wrote:
> On 03/04/20 10:52, Ard Biesheuvel wrote:
>> Introduce the QemuLoadImageLib library class that we will instantiate
>> to load the kernel image passed via the QEMU command line using the
>> standard LoadImage boot service.
>>
>> 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>
>> ---
>>  OvmfPkg/Include/Library/QemuLoadImageLib.h | 84 ++++++++++++++++++++
>>  OvmfPkg/OvmfPkg.dec                        |  5 ++
>>  2 files changed, 89 insertions(+)
>>
>> diff --git a/OvmfPkg/Include/Library/QemuLoadImageLib.h b/OvmfPkg/Include/Library/QemuLoadImageLib.h
>> new file mode 100644
>> index 000000000000..694905a6421b
>> --- /dev/null
>> +++ b/OvmfPkg/Include/Library/QemuLoadImageLib.h
>> @@ -0,0 +1,84 @@
>> +/** @file
>> +  Load a kernel image and command line passed to QEMU via
>> +  the command line
>> +
>> +  Copyright (C) 2020, Arm, Limited.
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +**/
>> +
>> +#ifndef QEMU_LOAD_IMAGE_LIB_H__
>> +#define QEMU_LOAD_IMAGE_LIB_H__
>> +
>> +#include <Uefi/UefiBaseType.h>
>> +#include <Base.h>
>> +
>> +#include <Protocol/LoadedImage.h>
>> +
>> +/**
>> +  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
>> +  );
>> +
>> +/**
>> +  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.
>> +                                  On success, the function doesn't return.
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +QemuStartKernelImage (
>> +  IN  OUT EFI_HANDLE          *ImageHandle
>> +  );
>> +
>> +/**
>> +  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.
> 
> (1) The above apostrophe (in the "image’s" expression) is U+2019 ("RIGHT
> SINGLE QUOTATION MARK"). Please replace it with a normal ASCII 0x27
> character (U+0027, "APOSTROPHE") when you push the series.

Please also sync the comment in the lib instances too.

Laszlo


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib
  2020-03-04  9:52 ` [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
@ 2020-03-05  9:51   ` Laszlo Ersek
  2020-03-05 11:29     ` Laszlo Ersek
  0 siblings, 1 reply; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05  9:51 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> 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>
> ---
>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c   | 278 ++++++++++++++++++++
>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf |  38 +++
>  2 files changed, 316 insertions(+)

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo

> diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
> new file mode 100644
> index 000000000000..f5edb43cc0b9
> --- /dev/null
> +++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
> @@ -0,0 +1,278 @@
> +/**  @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
> +  @param[out] LoadedImage       The loaded image protocol that was installed
> +                                on ImageHandle by the LoadImage boot service.
> +
> +  @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);
> +}
> diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
> new file mode 100644
> index 000000000000..b262cb926a4d
> --- /dev/null
> +++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
> @@ -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
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader
  2020-03-04  9:52 ` [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
@ 2020-03-05 10:01   ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 10:01 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> Drop the QEMU loader file system implementation inside this library,
> and switch to the separate QemuLoadImageLib library and the associated
> driver to expose the kernel and initrd passed via the QEMU command line.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |    9 +-
>  ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c               | 1061 +-------------------
>  2 files changed, 7 insertions(+), 1063 deletions(-)

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo

> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> index a9d4888d4377..a010564527b6 100644
> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -44,9 +44,8 @@ [LibraryClasses]
>    MemoryAllocationLib
>    PcdLib
>    PlatformBmPrintScLib
> -  PrintLib
>    QemuBootOrderLib
> -  QemuFwCfgLib
> +  QemuLoadImageLib
>    ReportStatusCodeLib
>    UefiBootManagerLib
>    UefiBootServicesTableLib
> @@ -64,18 +63,12 @@ [Pcd]
>    gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
>  
>  [Guids]
> -  gEfiFileInfoGuid
> -  gEfiFileSystemInfoGuid
> -  gEfiFileSystemVolumeLabelInfoIdGuid
>    gEfiEndOfDxeEventGroupGuid
>    gRootBridgesConnectedEventGroupGuid
>    gUefiShellFileGuid
>  
>  [Protocols]
> -  gEfiDevicePathProtocolGuid
>    gEfiFirmwareVolume2ProtocolGuid
>    gEfiGraphicsOutputProtocolGuid
> -  gEfiLoadedImageProtocolGuid
>    gEfiPciRootBridgeIoProtocolGuid
> -  gEfiSimpleFileSystemProtocolGuid
>    gVirtioDeviceProtocolGuid
> diff --git a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c b/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
> index d3851fd75fa5..e9c110a0ed75 100644
> --- a/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
> +++ b/ArmVirtPkg/Library/PlatformBootManagerLib/QemuKernel.c
> @@ -9,887 +9,11 @@
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>  **/
>  
> -#include <Guid/FileInfo.h>
> -#include <Guid/FileSystemInfo.h>
> -#include <Guid/FileSystemVolumeLabelInfo.h>
> -#include <Library/PrintLib.h>
> -#include <Library/QemuFwCfgLib.h>
> +#include <Library/QemuLoadImageLib.h>
>  #include <Library/ReportStatusCodeLib.h>
> -#include <Protocol/DevicePath.h>
> -#include <Protocol/LoadedImage.h>
> -#include <Protocol/SimpleFileSystem.h>
>  
>  #include "PlatformBm.h"
>  
> -//
> -// Static data that hosts the fw_cfg blobs and serves file requests.
> -//
> -typedef enum {
> -  KernelBlobTypeKernel,
> -  KernelBlobTypeInitrd,
> -  KernelBlobTypeCommandLine,
> -  KernelBlobTypeMax
> -} KERNEL_BLOB_TYPE;
> -
> -typedef struct {
> -  FIRMWARE_CONFIG_ITEM CONST SizeKey;
> -  FIRMWARE_CONFIG_ITEM CONST DataKey;
> -  CONST CHAR16 *       CONST Name;
> -  UINT32                     Size;
> -  UINT8                      *Data;
> -} KERNEL_BLOB;
> -
> -STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
> -  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
> -  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
> -  { QemuFwCfgItemCommandLineSize, QemuFwCfgItemCommandLineData, L"cmdline" }
> -};
> -
> -STATIC UINT64 mTotalBlobBytes;
> -
> -//
> -// Device path for the handle that incorporates our "EFI stub filesystem". The
> -// GUID is arbitrary and need not be standardized or advertized.
> -//
> -#pragma pack(1)
> -typedef struct {
> -  VENDOR_DEVICE_PATH       VenHwNode;
> -  EFI_DEVICE_PATH_PROTOCOL EndNode;
> -} SINGLE_VENHW_NODE_DEVPATH;
> -#pragma pack()
> -
> -STATIC CONST SINGLE_VENHW_NODE_DEVPATH mFileSystemDevicePath = {
> -  {
> -    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH) } },
> -    {
> -      0xb0fae7e7, 0x6b07, 0x49d0,
> -      { 0x9e, 0x5b, 0x3b, 0xde, 0xc8, 0x3b, 0x03, 0x9d }
> -    }
> -  },
> -
> -  {
> -    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> -    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
> -  }
> -};
> -
> -//
> -// The "file in the EFI stub filesystem" abstraction.
> -//
> -STATIC EFI_TIME mInitTime;
> -
> -#define STUB_FILE_SIG SIGNATURE_64 ('S', 'T', 'U', 'B', 'F', 'I', 'L', 'E')
> -
> -typedef struct {
> -  UINT64            Signature; // Carries STUB_FILE_SIG.
> -
> -  KERNEL_BLOB_TYPE  BlobType;  // Index into mKernelBlob. KernelBlobTypeMax
> -                               // denotes the root directory of the filesystem.
> -
> -  UINT64            Position;  // Byte position for regular files;
> -                               // next directory entry to return for the root
> -                               // directory.
> -
> -  EFI_FILE_PROTOCOL File;      // Standard protocol interface.
> -} STUB_FILE;
> -
> -#define STUB_FILE_FROM_FILE(FilePointer) \
> -        CR (FilePointer, STUB_FILE, File, STUB_FILE_SIG)
> -
> -//
> -// Tentative definition of the file protocol template. The initializer
> -// (external definition) will be provided later.
> -//
> -STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate;
> -
> -
> -//
> -// Protocol member functions for File.
> -//
> -
> -/**
> -  Opens a new file relative to the source file's location.
> -
> -  @param[in]  This        A pointer to the EFI_FILE_PROTOCOL instance that is
> -                          the file handle to the source location. This would
> -                          typically be an open handle to a directory.
> -
> -  @param[out] NewHandle   A pointer to the location to return the opened handle
> -                          for the new file.
> -
> -  @param[in]  FileName    The Null-terminated string of the name of the file to
> -                          be opened. The file name may contain the following
> -                          path modifiers: "\", ".", and "..".
> -
> -  @param[in]  OpenMode    The mode to open the file. The only valid
> -                          combinations that the file may be opened with are:
> -                          Read, Read/Write, or Create/Read/Write.
> -
> -  @param[in]  Attributes  Only valid for EFI_FILE_MODE_CREATE, in which case
> -                          these are the attribute bits for the newly created
> -                          file.
> -
> -  @retval EFI_SUCCESS           The file was opened.
> -  @retval EFI_NOT_FOUND         The specified file could not be found on the
> -                                device.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
> -                                medium is no longer supported.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_WRITE_PROTECTED   An attempt was made to create a file, or open a
> -                                file for write when the media is
> -                                write-protected.
> -  @retval EFI_ACCESS_DENIED     The service denied access to the file.
> -  @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
> -                                file.
> -  @retval EFI_VOLUME_FULL       The volume is full.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileOpen (
> -  IN EFI_FILE_PROTOCOL  *This,
> -  OUT EFI_FILE_PROTOCOL **NewHandle,
> -  IN CHAR16             *FileName,
> -  IN UINT64             OpenMode,
> -  IN UINT64             Attributes
> -  )
> -{
> -  CONST STUB_FILE *StubFile;
> -  UINTN           BlobType;
> -  STUB_FILE       *NewStubFile;
> -
> -  //
> -  // We're read-only.
> -  //
> -  switch (OpenMode) {
> -    case EFI_FILE_MODE_READ:
> -      break;
> -
> -    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
> -    case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
> -      return EFI_WRITE_PROTECTED;
> -
> -    default:
> -      return EFI_INVALID_PARAMETER;
> -  }
> -
> -  //
> -  // Only the root directory supports opening files in it.
> -  //
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -  if (StubFile->BlobType != KernelBlobTypeMax) {
> -    return EFI_UNSUPPORTED;
> -  }
> -
> -  //
> -  // Locate the file.
> -  //
> -  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
> -    if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
> -      break;
> -    }
> -  }
> -  if (BlobType == KernelBlobTypeMax) {
> -    return EFI_NOT_FOUND;
> -  }
> -
> -  //
> -  // Found it.
> -  //
> -  NewStubFile = AllocatePool (sizeof *NewStubFile);
> -  if (NewStubFile == NULL) {
> -    return EFI_OUT_OF_RESOURCES;
> -  }
> -
> -  NewStubFile->Signature = STUB_FILE_SIG;
> -  NewStubFile->BlobType  = (KERNEL_BLOB_TYPE)BlobType;
> -  NewStubFile->Position  = 0;
> -  CopyMem (&NewStubFile->File, &mEfiFileProtocolTemplate,
> -    sizeof mEfiFileProtocolTemplate);
> -  *NewHandle = &NewStubFile->File;
> -
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Closes a specified file handle.
> -
> -  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
> -                   handle to close.
> -
> -  @retval EFI_SUCCESS  The file was closed.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileClose (
> -  IN EFI_FILE_PROTOCOL *This
> -  )
> -{
> -  FreePool (STUB_FILE_FROM_FILE (This));
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Close and delete the file handle.
> -
> -  @param[in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
> -                   handle to the file to delete.
> -
> -  @retval EFI_SUCCESS              The file was closed and deleted, and the
> -                                   handle was closed.
> -  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not
> -                                   deleted.
> -
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileDelete (
> -  IN EFI_FILE_PROTOCOL *This
> -  )
> -{
> -  FreePool (STUB_FILE_FROM_FILE (This));
> -  return EFI_WARN_DELETE_FAILURE;
> -}
> -
> -
> -/**
> -  Helper function that formats an EFI_FILE_INFO structure into the
> -  user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
> -  KernelBlobTypeMax, which stands for the root directory).
> -
> -  The interface follows the EFI_FILE_GET_INFO -- and for directories, the
> -  EFI_FILE_READ -- interfaces.
> -
> -  @param[in]     BlobType     The KERNEL_BLOB_TYPE value identifying the fw_cfg
> -                              blob backing the STUB_FILE that information is
> -                              being requested about. If BlobType equals
> -                              KernelBlobTypeMax, then information will be
> -                              provided about the root directory of the
> -                              filesystem.
> -
> -  @param[in,out] BufferSize  On input, the size of Buffer. On output, the
> -                             amount of data returned in Buffer. In both cases,
> -                             the size is measured in bytes.
> -
> -  @param[out]    Buffer      A pointer to the data buffer to return. The
> -                             buffer's type is EFI_FILE_INFO.
> -
> -  @retval EFI_SUCCESS           The information was returned.
> -  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small to store the
> -                                EFI_FILE_INFO structure. BufferSize has been
> -                                updated with the size needed to complete the
> -                                request.
> -**/
> -STATIC
> -EFI_STATUS
> -ConvertKernelBlobTypeToFileInfo (
> -  IN KERNEL_BLOB_TYPE BlobType,
> -  IN OUT UINTN        *BufferSize,
> -  OUT VOID            *Buffer
> -  )
> -{
> -  CONST CHAR16  *Name;
> -  UINT64        FileSize;
> -  UINT64        Attribute;
> -
> -  UINTN         NameSize;
> -  UINTN         FileInfoSize;
> -  EFI_FILE_INFO *FileInfo;
> -  UINTN         OriginalBufferSize;
> -
> -  if (BlobType == KernelBlobTypeMax) {
> -    //
> -    // getting file info about the root directory
> -    //
> -    Name      = L"\\";
> -    FileSize  = KernelBlobTypeMax;
> -    Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
> -  } else {
> -    CONST KERNEL_BLOB *Blob;
> -
> -    Blob      = &mKernelBlob[BlobType];
> -    Name      = Blob->Name;
> -    FileSize  = Blob->Size;
> -    Attribute = EFI_FILE_READ_ONLY;
> -  }
> -
> -  NameSize     = (StrLen(Name) + 1) * 2;
> -  FileInfoSize = OFFSET_OF (EFI_FILE_INFO, FileName) + NameSize;
> -  ASSERT (FileInfoSize >= sizeof *FileInfo);
> -
> -  OriginalBufferSize = *BufferSize;
> -  *BufferSize        = FileInfoSize;
> -  if (OriginalBufferSize < *BufferSize) {
> -    return EFI_BUFFER_TOO_SMALL;
> -  }
> -
> -  FileInfo               = (EFI_FILE_INFO *)Buffer;
> -  FileInfo->Size         = FileInfoSize;
> -  FileInfo->FileSize     = FileSize;
> -  FileInfo->PhysicalSize = FileSize;
> -  FileInfo->Attribute    = Attribute;
> -
> -  CopyMem (&FileInfo->CreateTime,       &mInitTime, sizeof mInitTime);
> -  CopyMem (&FileInfo->LastAccessTime,   &mInitTime, sizeof mInitTime);
> -  CopyMem (&FileInfo->ModificationTime, &mInitTime, sizeof mInitTime);
> -  CopyMem (FileInfo->FileName,          Name,       NameSize);
> -
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Reads data from a file, or continues scanning a directory.
> -
> -  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
> -                             is the file handle to read data from.
> -
> -  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
> -                             amount of data returned in Buffer. In both cases,
> -                             the size is measured in bytes. If the read goes
> -                             beyond the end of the file, the read length is
> -                             truncated to the end of the file.
> -
> -                             If This is a directory, the function reads the
> -                             directory entry at the current position and
> -                             returns the entry (as EFI_FILE_INFO) in Buffer. If
> -                             there are no more directory entries, the
> -                             BufferSize is set to zero on output.
> -
> -  @param[out]    Buffer      The buffer into which the data is read.
> -
> -  @retval EFI_SUCCESS           Data was read.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted
> -                                file.
> -  @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond
> -                                the end of the file.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
> -                                current directory entry as a EFI_FILE_INFO
> -                                structure. BufferSize has been updated with the
> -                                size needed to complete the request, and the
> -                                directory position has not been advanced.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileRead (
> -  IN EFI_FILE_PROTOCOL *This,
> -  IN OUT UINTN         *BufferSize,
> -  OUT VOID             *Buffer
> -  )
> -{
> -  STUB_FILE         *StubFile;
> -  CONST KERNEL_BLOB *Blob;
> -  UINT64            Left;
> -
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -
> -  //
> -  // Scanning the root directory?
> -  //
> -  if (StubFile->BlobType == KernelBlobTypeMax) {
> -    EFI_STATUS Status;
> -
> -    if (StubFile->Position == KernelBlobTypeMax) {
> -      //
> -      // Scanning complete.
> -      //
> -      *BufferSize = 0;
> -      return EFI_SUCCESS;
> -    }
> -
> -    Status = ConvertKernelBlobTypeToFileInfo (
> -               (KERNEL_BLOB_TYPE)StubFile->Position,
> -               BufferSize,
> -               Buffer);
> -    if (EFI_ERROR (Status)) {
> -      return Status;
> -    }
> -
> -    ++StubFile->Position;
> -    return EFI_SUCCESS;
> -  }
> -
> -  //
> -  // Reading a file.
> -  //
> -  Blob = &mKernelBlob[StubFile->BlobType];
> -  if (StubFile->Position > Blob->Size) {
> -    return EFI_DEVICE_ERROR;
> -  }
> -
> -  Left = Blob->Size - StubFile->Position;
> -  if (*BufferSize > Left) {
> -    *BufferSize = (UINTN)Left;
> -  }
> -  if (Blob->Data != NULL) {
> -    CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
> -  }
> -  StubFile->Position += *BufferSize;
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Writes data to a file.
> -
> -  @param[in]     This        A pointer to the EFI_FILE_PROTOCOL instance that
> -                             is the file handle to write data to.
> -
> -  @param[in,out] BufferSize  On input, the size of the Buffer. On output, the
> -                             amount of data actually written. In both cases,
> -                             the size is measured in bytes.
> -
> -  @param[in]     Buffer      The buffer of data to write.
> -
> -  @retval EFI_SUCCESS           Data was written.
> -  @retval EFI_UNSUPPORTED       Writes to open directory files are not
> -                                supported.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_DEVICE_ERROR      An attempt was made to write to a deleted file.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
> -  @retval EFI_ACCESS_DENIED     The file was opened read only.
> -  @retval EFI_VOLUME_FULL       The volume is full.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileWrite (
> -  IN EFI_FILE_PROTOCOL *This,
> -  IN OUT UINTN         *BufferSize,
> -  IN VOID              *Buffer
> -  )
> -{
> -  STUB_FILE *StubFile;
> -
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -  return (StubFile->BlobType == KernelBlobTypeMax) ?
> -         EFI_UNSUPPORTED :
> -         EFI_WRITE_PROTECTED;
> -}
> -
> -
> -/**
> -  Returns a file's current position.
> -
> -  @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is the
> -                        file handle to get the current position on.
> -
> -  @param[out] Position  The address to return the file's current position
> -                        value.
> -
> -  @retval EFI_SUCCESS      The position was returned.
> -  @retval EFI_UNSUPPORTED  The request is not valid on open directories.
> -  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a
> -                           deleted file.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileGetPosition (
> -  IN EFI_FILE_PROTOCOL *This,
> -  OUT UINT64           *Position
> -  )
> -{
> -  STUB_FILE *StubFile;
> -
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -  if (StubFile->BlobType == KernelBlobTypeMax) {
> -    return EFI_UNSUPPORTED;
> -  }
> -
> -  *Position = StubFile->Position;
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Sets a file's current position.
> -
> -  @param[in] This      A pointer to the EFI_FILE_PROTOCOL instance that is the
> -                       file handle to set the requested position on.
> -
> -  @param[in] Position  The byte position from the start of the file to set. For
> -                       regular files, MAX_UINT64 means "seek to end". For
> -                       directories, zero means "rewind directory scan".
> -
> -  @retval EFI_SUCCESS       The position was set.
> -  @retval EFI_UNSUPPORTED   The seek request for nonzero is not valid on open
> -                            directories.
> -  @retval EFI_DEVICE_ERROR  An attempt was made to set the position of a
> -                            deleted file.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileSetPosition (
> -  IN EFI_FILE_PROTOCOL *This,
> -  IN UINT64            Position
> -  )
> -{
> -  STUB_FILE   *StubFile;
> -  KERNEL_BLOB *Blob;
> -
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -
> -  if (StubFile->BlobType == KernelBlobTypeMax) {
> -    if (Position == 0) {
> -      //
> -      // rewinding a directory scan is allowed
> -      //
> -      StubFile->Position = 0;
> -      return EFI_SUCCESS;
> -    }
> -    return EFI_UNSUPPORTED;
> -  }
> -
> -  //
> -  // regular file seek
> -  //
> -  Blob = &mKernelBlob[StubFile->BlobType];
> -  if (Position == MAX_UINT64) {
> -    //
> -    // seek to end
> -    //
> -    StubFile->Position = Blob->Size;
> -  } else {
> -    //
> -    // absolute seek from beginning -- seeking past the end is allowed
> -    //
> -    StubFile->Position = Position;
> -  }
> -  return EFI_SUCCESS;
> -}
> -
> -
> -/**
> -  Returns information about a file.
> -
> -  @param[in]     This             A pointer to the EFI_FILE_PROTOCOL instance
> -                                  that is the file handle the requested
> -                                  information is for.
> -
> -  @param[in]     InformationType  The type identifier GUID for the information
> -                                  being requested. The following information
> -                                  types are supported, storing the
> -                                  corresponding structures in Buffer:
> -
> -                                  - gEfiFileInfoGuid: EFI_FILE_INFO
> -
> -                                  - gEfiFileSystemInfoGuid:
> -                                    EFI_FILE_SYSTEM_INFO
> -
> -                                  - gEfiFileSystemVolumeLabelInfoIdGuid:
> -                                    EFI_FILE_SYSTEM_VOLUME_LABEL
> -
> -  @param[in,out] BufferSize       On input, the size of Buffer. On output, the
> -                                  amount of data returned in Buffer. In both
> -                                  cases, the size is measured in bytes.
> -
> -  @param[out]    Buffer           A pointer to the data buffer to return. The
> -                                  buffer's type is indicated by
> -                                  InformationType.
> -
> -  @retval EFI_SUCCESS           The information was returned.
> -  @retval EFI_UNSUPPORTED       The InformationType is not known.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to store the
> -                                information structure requested by
> -                                InformationType. BufferSize has been updated
> -                                with the size needed to complete the request.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileGetInfo (
> -  IN EFI_FILE_PROTOCOL *This,
> -  IN EFI_GUID          *InformationType,
> -  IN OUT UINTN         *BufferSize,
> -  OUT VOID             *Buffer
> -  )
> -{
> -  CONST STUB_FILE *StubFile;
> -  UINTN           OriginalBufferSize;
> -
> -  StubFile = STUB_FILE_FROM_FILE (This);
> -
> -  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
> -    return ConvertKernelBlobTypeToFileInfo (StubFile->BlobType, BufferSize,
> -             Buffer);
> -  }
> -
> -  OriginalBufferSize = *BufferSize;
> -
> -  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
> -    EFI_FILE_SYSTEM_INFO *FileSystemInfo;
> -
> -    *BufferSize = sizeof *FileSystemInfo;
> -    if (OriginalBufferSize < *BufferSize) {
> -      return EFI_BUFFER_TOO_SMALL;
> -    }
> -
> -    FileSystemInfo                 = (EFI_FILE_SYSTEM_INFO *)Buffer;
> -    FileSystemInfo->Size           = sizeof *FileSystemInfo;
> -    FileSystemInfo->ReadOnly       = TRUE;
> -    FileSystemInfo->VolumeSize     = mTotalBlobBytes;
> -    FileSystemInfo->FreeSpace      = 0;
> -    FileSystemInfo->BlockSize      = 1;
> -    FileSystemInfo->VolumeLabel[0] = L'\0';
> -
> -    return EFI_SUCCESS;
> -  }
> -
> -  if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
> -    EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
> -
> -    *BufferSize = sizeof *FileSystemVolumeLabel;
> -    if (OriginalBufferSize < *BufferSize) {
> -      return EFI_BUFFER_TOO_SMALL;
> -    }
> -
> -    FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
> -    FileSystemVolumeLabel->VolumeLabel[0] = L'\0';
> -
> -    return EFI_SUCCESS;
> -  }
> -
> -  return EFI_UNSUPPORTED;
> -}
> -
> -
> -/**
> -  Sets information about a file.
> -
> -  @param[in] File             A pointer to the EFI_FILE_PROTOCOL instance that
> -                              is the file handle the information is for.
> -
> -  @param[in] InformationType  The type identifier for the information being
> -                              set.
> -
> -  @param[in] BufferSize       The size, in bytes, of Buffer.
> -
> -  @param[in] Buffer           A pointer to the data buffer to write. The
> -                              buffer's type is indicated by InformationType.
> -
> -  @retval EFI_SUCCESS           The information was set.
> -  @retval EFI_UNSUPPORTED       The InformationType is not known.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_WRITE_PROTECTED   InformationType is EFI_FILE_INFO_ID and the
> -                                media is read-only.
> -  @retval EFI_WRITE_PROTECTED   InformationType is
> -                                EFI_FILE_PROTOCOL_SYSTEM_INFO_ID and the media
> -                                is read only.
> -  @retval EFI_WRITE_PROTECTED   InformationType is
> -                                EFI_FILE_SYSTEM_VOLUME_LABEL_ID and the media
> -                                is read-only.
> -  @retval EFI_ACCESS_DENIED     An attempt is made to change the name of a file
> -                                to a file that is already present.
> -  @retval EFI_ACCESS_DENIED     An attempt is being made to change the
> -                                EFI_FILE_DIRECTORY Attribute.
> -  @retval EFI_ACCESS_DENIED     An attempt is being made to change the size of
> -                                a directory.
> -  @retval EFI_ACCESS_DENIED     InformationType is EFI_FILE_INFO_ID and the
> -                                file was opened read-only and an attempt is
> -                                being made to modify a field other than
> -                                Attribute.
> -  @retval EFI_VOLUME_FULL       The volume is full.
> -  @retval EFI_BAD_BUFFER_SIZE   BufferSize is smaller than the size of the type
> -                                indicated by InformationType.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileSetInfo (
> -  IN EFI_FILE_PROTOCOL *This,
> -  IN EFI_GUID          *InformationType,
> -  IN UINTN             BufferSize,
> -  IN VOID              *Buffer
> -  )
> -{
> -  return EFI_WRITE_PROTECTED;
> -}
> -
> -
> -/**
> -  Flushes all modified data associated with a file to a device.
> -
> -  @param [in] This  A pointer to the EFI_FILE_PROTOCOL instance that is the
> -                    file handle to flush.
> -
> -  @retval EFI_SUCCESS           The data was flushed.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_WRITE_PROTECTED   The file or medium is write-protected.
> -  @retval EFI_ACCESS_DENIED     The file was opened read-only.
> -  @retval EFI_VOLUME_FULL       The volume is full.
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileFlush (
> -  IN EFI_FILE_PROTOCOL *This
> -  )
> -{
> -  return EFI_WRITE_PROTECTED;
> -}
> -
> -//
> -// External definition of the file protocol template.
> -//
> -STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
> -  EFI_FILE_PROTOCOL_REVISION, // revision 1
> -  StubFileOpen,
> -  StubFileClose,
> -  StubFileDelete,
> -  StubFileRead,
> -  StubFileWrite,
> -  StubFileGetPosition,
> -  StubFileSetPosition,
> -  StubFileGetInfo,
> -  StubFileSetInfo,
> -  StubFileFlush,
> -  NULL,                       // OpenEx, revision 2
> -  NULL,                       // ReadEx, revision 2
> -  NULL,                       // WriteEx, revision 2
> -  NULL                        // FlushEx, revision 2
> -};
> -
> -
> -//
> -// Protocol member functions for SimpleFileSystem.
> -//
> -
> -/**
> -  Open the root directory on a volume.
> -
> -  @param[in]  This  A pointer to the volume to open the root directory on.
> -
> -  @param[out] Root  A pointer to the location to return the opened file handle
> -                    for the root directory in.
> -
> -  @retval EFI_SUCCESS           The device was opened.
> -  @retval EFI_UNSUPPORTED       This volume does not support the requested file
> -                                system type.
> -  @retval EFI_NO_MEDIA          The device has no medium.
> -  @retval EFI_DEVICE_ERROR      The device reported an error.
> -  @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
> -  @retval EFI_ACCESS_DENIED     The service denied access to the file.
> -  @retval EFI_OUT_OF_RESOURCES  The volume was not opened due to lack of
> -                                resources.
> -  @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
> -                                medium is no longer supported. Any existing
> -                                file handles for this volume are no longer
> -                                valid. To access the files on the new medium,
> -                                the volume must be reopened with OpenVolume().
> -**/
> -STATIC
> -EFI_STATUS
> -EFIAPI
> -StubFileSystemOpenVolume (
> -  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
> -  OUT EFI_FILE_PROTOCOL              **Root
> -  )
> -{
> -  STUB_FILE *StubFile;
> -
> -  StubFile = AllocatePool (sizeof *StubFile);
> -  if (StubFile == NULL) {
> -    return EFI_OUT_OF_RESOURCES;
> -  }
> -
> -  StubFile->Signature = STUB_FILE_SIG;
> -  StubFile->BlobType  = KernelBlobTypeMax;
> -  StubFile->Position  = 0;
> -  CopyMem (&StubFile->File, &mEfiFileProtocolTemplate,
> -    sizeof mEfiFileProtocolTemplate);
> -  *Root = &StubFile->File;
> -
> -  return EFI_SUCCESS;
> -}
> -
> -STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
> -  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
> -  StubFileSystemOpenVolume
> -};
> -
> -
> -//
> -// Utility functions.
> -//
> -
> -/**
> -  Populate a blob in mKernelBlob.
> -
> -  param[in,out] Blob  Pointer to the KERNEL_BLOB element in mKernelBlob that is
> -                      to be filled from fw_cfg.
> -
> -  @retval EFI_SUCCESS           Blob has been populated. If fw_cfg reported a
> -                                size of zero for the blob, then Blob->Data has
> -                                been left unchanged.
> -
> -  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Blob->Data.
> -**/
> -STATIC
> -EFI_STATUS
> -FetchBlob (
> -  IN OUT KERNEL_BLOB *Blob
> -  )
> -{
> -  UINT32 Left;
> -
> -  //
> -  // Read blob size.
> -  //
> -  QemuFwCfgSelectItem (Blob->SizeKey);
> -  Blob->Size = QemuFwCfgRead32 ();
> -  if (Blob->Size == 0) {
> -    return EFI_SUCCESS;
> -  }
> -
> -  //
> -  // Read blob.
> -  //
> -  Blob->Data = AllocatePool (Blob->Size);
> -  if (Blob->Data == NULL) {
> -    DEBUG ((EFI_D_ERROR, "%a: failed to allocate %Ld bytes for \"%s\"\n",
> -      __FUNCTION__, (INT64)Blob->Size, Blob->Name));
> -    return EFI_OUT_OF_RESOURCES;
> -  }
> -
> -  DEBUG ((EFI_D_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,
> -    (INT64)Blob->Size, Blob->Name));
> -  QemuFwCfgSelectItem (Blob->DataKey);
> -
> -  Left = Blob->Size;
> -  do {
> -    UINT32 Chunk;
> -
> -    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
> -    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));
> -    Left -= Chunk;
> -    DEBUG ((EFI_D_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",
> -      __FUNCTION__, (INT64)Left, Blob->Name));
> -  } while (Left > 0);
> -  return EFI_SUCCESS;
> -}
> -
> -
>  //
>  // The entry point of the feature.
>  //
> @@ -916,159 +40,14 @@ TryRunningQemuKernel (
>    VOID
>    )
>  {
> -  UINTN                     BlobType;
> -  KERNEL_BLOB               *CurrentBlob;
> -  KERNEL_BLOB               *KernelBlob, *InitrdBlob, *CommandLineBlob;
>    EFI_STATUS                Status;
> -  EFI_HANDLE                FileSystemHandle;
> -  EFI_DEVICE_PATH_PROTOCOL  *KernelDevicePath;
>    EFI_HANDLE                KernelImageHandle;
> -  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
>  
> -  Status = gRT->GetTime (&mInitTime, NULL /* Capabilities */);
> +  Status = QemuLoadKernelImage (&KernelImageHandle);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((EFI_D_ERROR, "%a: GetTime(): %r\n", __FUNCTION__, Status));
>      return Status;
>    }
>  
> -  //
> -  // Fetch all blobs.
> -  //
> -  for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
> -    CurrentBlob = &mKernelBlob[BlobType];
> -    Status = FetchBlob (CurrentBlob);
> -    if (EFI_ERROR (Status)) {
> -      goto FreeBlobs;
> -    }
> -    mTotalBlobBytes += CurrentBlob->Size;
> -  }
> -  KernelBlob      = &mKernelBlob[KernelBlobTypeKernel];
> -  InitrdBlob      = &mKernelBlob[KernelBlobTypeInitrd];
> -  CommandLineBlob = &mKernelBlob[KernelBlobTypeCommandLine];
> -
> -  if (KernelBlob->Data == NULL) {
> -    Status = EFI_NOT_FOUND;
> -    goto FreeBlobs;
> -  }
> -
> -  //
> -  // Create a new handle with a single VenHw() node device path protocol on it,
> -  // plus a custom SimpleFileSystem protocol on it.
> -  //
> -  FileSystemHandle = NULL;
> -  Status = gBS->InstallMultipleProtocolInterfaces (&FileSystemHandle,
> -                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
> -                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
> -                  NULL);
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((EFI_D_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
> -      __FUNCTION__, Status));
> -    goto FreeBlobs;
> -  }
> -
> -  //
> -  // Create a device path for the kernel image to be loaded from that will call
> -  // back into our file system.
> -  //
> -  KernelDevicePath = FileDevicePath (FileSystemHandle, KernelBlob->Name);
> -  if (KernelDevicePath == NULL) {
> -    DEBUG ((EFI_D_ERROR, "%a: failed to allocate kernel device path\n",
> -      __FUNCTION__));
> -    Status = EFI_OUT_OF_RESOURCES;
> -    goto UninstallProtocols;
> -  }
> -
> -  //
> -  // Load the image. This should call back into our file system.
> -  //
> -  Status = gBS->LoadImage (
> -                  FALSE,             // BootPolicy: exact match required
> -                  gImageHandle,      // ParentImageHandle
> -                  KernelDevicePath,
> -                  NULL,              // SourceBuffer
> -                  0,                 // SourceSize
> -                  &KernelImageHandle
> -                  );
> -  if (EFI_ERROR (Status)) {
> -    DEBUG ((EFI_D_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));
> -    if (Status != EFI_SECURITY_VIOLATION) {
> -      goto FreeKernelDevicePath;
> -    }
> -    //
> -    // From the resource allocation perspective, EFI_SECURITY_VIOLATION means
> -    // "success", so we must roll back the image loading.
> -    //
> -    goto UnloadKernelImage;
> -  }
> -
> -  //
> -  // 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);
> -
> -  if (CommandLineBlob->Data == NULL) {
> -    KernelLoadedImage->LoadOptionsSize = 0;
> -  } else {
> -    //
> -    // Verify NUL-termination of the command line.
> -    //
> -    if (CommandLineBlob->Data[CommandLineBlob->Size - 1] != '\0') {
> -      DEBUG ((EFI_D_ERROR, "%a: kernel command line is not NUL-terminated\n",
> -        __FUNCTION__));
> -      Status = EFI_PROTOCOL_ERROR;
> -      goto UnloadKernelImage;
> -    }
> -
> -    //
> -    // Drop the terminating NUL, convert to UTF-16.
> -    //
> -    KernelLoadedImage->LoadOptionsSize = (CommandLineBlob->Size - 1) * 2;
> -  }
> -
> -  if (InitrdBlob->Data != NULL) {
> -    //
> -    // Append ' initrd=<name>' in UTF-16.
> -    //
> -    KernelLoadedImage->LoadOptionsSize +=
> -                                        (8 + StrLen(InitrdBlob->Name)) * 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 UnloadKernelImage;
> -    }
> -
> -    UnicodeSPrintAsciiFormat (
> -      KernelLoadedImage->LoadOptions,
> -      KernelLoadedImage->LoadOptionsSize,
> -      "%a%a%s",
> -      (CommandLineBlob->Data == NULL) ?  "" : (CHAR8 *)CommandLineBlob->Data,
> -      (InitrdBlob->Data      == NULL) ?  "" : " initrd=",
> -      (InitrdBlob->Data      == NULL) ? L"" : InitrdBlob->Name
> -      );
> -    DEBUG ((EFI_D_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,
> -      (CHAR16 *)KernelLoadedImage->LoadOptions));
> -  }
> -
>    //
>    // Signal the EFI_EVENT_GROUP_READY_TO_BOOT event.
>    //
> @@ -1080,41 +59,13 @@ TryRunningQemuKernel (
>    //
>    // Start the image.
>    //
> -  Status = gBS->StartImage (
> -                KernelImageHandle,
> -                NULL,              // ExitDataSize
> -                NULL               // ExitData
> -                );
> +  Status = QemuStartKernelImage (&KernelImageHandle);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((EFI_D_ERROR, "%a: StartImage(): %r\n", __FUNCTION__, Status));
> +    DEBUG ((DEBUG_ERROR, "%a: QemuStartKernelImage(): %r\n", __FUNCTION__,
> +      Status));
>    }
>  
> -  if (KernelLoadedImage->LoadOptions != NULL) {
> -    FreePool (KernelLoadedImage->LoadOptions);
> -  }
> -  KernelLoadedImage->LoadOptionsSize = 0;
> -
> -UnloadKernelImage:
> -  gBS->UnloadImage (KernelImageHandle);
> -
> -FreeKernelDevicePath:
> -  FreePool (KernelDevicePath);
> -
> -UninstallProtocols:
> -  gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,
> -         &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
> -         &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
> -         NULL);
> -
> -FreeBlobs:
> -  while (BlobType > 0) {
> -    CurrentBlob = &mKernelBlob[--BlobType];
> -    if (CurrentBlob->Data != NULL) {
> -      FreePool (CurrentBlob->Data);
> -      CurrentBlob->Size = 0;
> -      CurrentBlob->Data = NULL;
> -    }
> -  }
> +  QemuUnloadKernelImage (KernelImageHandle);
>  
>    return Status;
>  }
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block
  2020-03-04  9:52 ` [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
@ 2020-03-05 10:12   ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 10:12 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> On x86, the kernel image consists of a setup block and the actual kernel,
> and QEMU presents these as separate blobs, whereas on disk (and in terms
> of PE/COFF image signing), they consist of a single image.
> 
> So add support to our FS loader driver to expose files via the abstract
> file system that consist of up to two concatenated blobs, and redefine
> the kernel file so it consists of the setup and kernel blobs, on every
> architecture (on non-x86, the setup block is simply 0 bytes and is
> therefore ignored implicitly)
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c | 74 ++++++++++++++------
>  1 file changed, 53 insertions(+), 21 deletions(-)

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo

> diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> index dc86a48af378..8ccb1983170c 100644
> --- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> +++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> @@ -34,16 +34,29 @@ typedef enum {
>  } KERNEL_BLOB_TYPE;
>  
>  typedef struct {
> -  FIRMWARE_CONFIG_ITEM CONST SizeKey;
> -  FIRMWARE_CONFIG_ITEM CONST DataKey;
> -  CONST CHAR16 *       CONST Name;
> -  UINT32                     Size;
> -  UINT8                      *Data;
> +  CONST CHAR16                  Name[8];
> +  struct {
> +    FIRMWARE_CONFIG_ITEM CONST  SizeKey;
> +    FIRMWARE_CONFIG_ITEM CONST  DataKey;
> +    UINT32                      Size;
> +  }                             FwCfgItem[2];
> +  UINT32                        Size;
> +  UINT8                         *Data;
>  } KERNEL_BLOB;
>  
>  STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
> -  { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      L"kernel"  },
> -  { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      L"initrd"  },
> +  {
> +    L"kernel",
> +    {
> +      { QemuFwCfgItemKernelSetupSize, QemuFwCfgItemKernelSetupData, },
> +      { QemuFwCfgItemKernelSize,      QemuFwCfgItemKernelData,      },
> +    }
> +  }, {
> +    L"initrd",
> +    {
> +      { QemuFwCfgItemInitrdSize,      QemuFwCfgItemInitrdData,      },
> +    }
> +  }
>  };
>  
>  STATIC UINT64 mTotalBlobBytes;
> @@ -850,12 +863,21 @@ FetchBlob (
>    )
>  {
>    UINT32 Left;
> +  UINTN  Idx;
> +  UINT8  *ChunkData;
>  
>    //
>    // Read blob size.
>    //
> -  QemuFwCfgSelectItem (Blob->SizeKey);
> -  Blob->Size = QemuFwCfgRead32 ();
> +  Blob->Size = 0;
> +  for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
> +    if (Blob->FwCfgItem[Idx].SizeKey == 0) {
> +      break;
> +    }
> +    QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey);
> +    Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
> +    Blob->Size += Blob->FwCfgItem[Idx].Size;
> +  }
>    if (Blob->Size == 0) {
>      return EFI_SUCCESS;
>    }
> @@ -872,18 +894,28 @@ FetchBlob (
>  
>    DEBUG ((DEBUG_INFO, "%a: loading %Ld bytes for \"%s\"\n", __FUNCTION__,
>      (INT64)Blob->Size, Blob->Name));
> -  QemuFwCfgSelectItem (Blob->DataKey);
> -
> -  Left = Blob->Size;
> -  do {
> -    UINT32 Chunk;
> -
> -    Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
> -    QemuFwCfgReadBytes (Chunk, Blob->Data + (Blob->Size - Left));
> -    Left -= Chunk;
> -    DEBUG ((DEBUG_VERBOSE, "%a: %Ld bytes remaining for \"%s\"\n",
> -      __FUNCTION__, (INT64)Left, Blob->Name));
> -  } while (Left > 0);
> +
> +  ChunkData = Blob->Data;
> +  for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
> +    if (Blob->FwCfgItem[Idx].DataKey == 0) {
> +      break;
> +    }
> +    QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey);
> +
> +    Left = Blob->FwCfgItem[Idx].Size;
> +    while (Left > 0) {
> +      UINT32 Chunk;
> +
> +      Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
> +      QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left);
> +      Left -= Chunk;
> +      DEBUG ((DEBUG_VERBOSE, "%a: %Ld bytes remaining for \"%s\" (%d)\n",
> +        __FUNCTION__, (INT64)Left, Blob->Name, (INT32)Idx));
> +    }
> +
> +    ChunkData += Blob->FwCfgItem[Idx].Size;
> +  }
> +
>    return EFI_SUCCESS;
>  }
>  
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class
  2020-03-05  9:39     ` Laszlo Ersek
@ 2020-03-05 10:22       ` Ard Biesheuvel
  0 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 10:22 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel-groups-io

On Thu, 5 Mar 2020 at 10:39, Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 03/05/20 10:37, Laszlo Ersek wrote:
> > On 03/04/20 10:52, Ard Biesheuvel wrote:
> >> Introduce the QemuLoadImageLib library class that we will instantiate
> >> to load the kernel image passed via the QEMU command line using the
> >> standard LoadImage boot service.
> >>
> >> 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>
> >> ---
> >>  OvmfPkg/Include/Library/QemuLoadImageLib.h | 84 ++++++++++++++++++++
> >>  OvmfPkg/OvmfPkg.dec                        |  5 ++
> >>  2 files changed, 89 insertions(+)
> >>
> >> diff --git a/OvmfPkg/Include/Library/QemuLoadImageLib.h b/OvmfPkg/Include/Library/QemuLoadImageLib.h
> >> new file mode 100644
> >> index 000000000000..694905a6421b
> >> --- /dev/null
> >> +++ b/OvmfPkg/Include/Library/QemuLoadImageLib.h
> >> @@ -0,0 +1,84 @@
> >> +/** @file
> >> +  Load a kernel image and command line passed to QEMU via
> >> +  the command line
> >> +
> >> +  Copyright (C) 2020, Arm, Limited.
> >> +
> >> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> >> +**/
> >> +
> >> +#ifndef QEMU_LOAD_IMAGE_LIB_H__
> >> +#define QEMU_LOAD_IMAGE_LIB_H__
> >> +
> >> +#include <Uefi/UefiBaseType.h>
> >> +#include <Base.h>
> >> +
> >> +#include <Protocol/LoadedImage.h>
> >> +
> >> +/**
> >> +  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
> >> +  );
> >> +
> >> +/**
> >> +  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.
> >> +                                  On success, the function doesn't return.
> >> +**/
> >> +EFI_STATUS
> >> +EFIAPI
> >> +QemuStartKernelImage (
> >> +  IN  OUT EFI_HANDLE          *ImageHandle
> >> +  );
> >> +
> >> +/**
> >> +  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.
> >
> > (1) The above apostrophe (in the "image’s" expression) is U+2019 ("RIGHT
> > SINGLE QUOTATION MARK"). Please replace it with a normal ASCII 0x27
> > character (U+0027, "APOSTROPHE") when you push the series.
>
> Please also sync the comment in the lib instances too.
>

OK

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images
  2020-03-04  9:52 ` [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images Ard Biesheuvel
@ 2020-03-05 10:31   ` Laszlo Ersek
  2020-03-05 10:40     ` Ard Biesheuvel
  0 siblings, 1 reply; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 10:31 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> In preparation of moving the legacy x86 loading to an implementation
> of the QEMU load image library class, introduce a protocol header
> and GUID that we will use to identify legacy loaded images in the
> protocol database.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h | 19 +++++++++++++++++++
>  OvmfPkg/OvmfPkg.dec                                 |  1 +
>  2 files changed, 20 insertions(+)
> 
> diff --git a/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
> new file mode 100644
> index 000000000000..7e1bebaa6a07
> --- /dev/null
> +++ b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
> @@ -0,0 +1,19 @@
> +/** @file
> +  Protocol/GUID definition to describe a kernel image loaded by the legacy X86
> +  loader from the file specified on the QEMU command line via the -kernel
> +  option.

(1) Please add a comment that the interface structure associated with
this protocol GUID is subject to change, and should not be used outside
of the EDK II tree.

(I'm requesting this comment regardless of point (5) below.)

> +
> +  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__
> +#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__

(2) Please drop "_GUID" from the guard macro's name.

> +
> +#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID \
> +  {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}

(3) Please replace "_GUID" with "_PROTOCOL_GUID" in the initializer
macro's name.

> +
> +extern EFI_GUID gX86QemuKernelLoadedImageGuid;

(4) Please replace "Guid" with "ProtocolGuid" in the variable name.

> +
> +#endif

(5) Please consider moving the QEMU_LEGACY_LOADED_IMAGE typedef here,
from the next patch. It's not a technical necessity at all, but edk2
protocol headers always include the interface typedef too. And due to
(1) above, I think it's safe too.

If you don't like the idea, I won't insist. :)

> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 055caaa43041..06ffd4198d44 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -112,6 +112,7 @@ [Protocols]
>    gEfiLegacyBiosPlatformProtocolGuid  = {0x783658a3, 0x4172, 0x4421, {0xa2, 0x99, 0xe0, 0x09, 0x07, 0x9c, 0x0c, 0xb4}}
>    gEfiLegacyInterruptProtocolGuid     = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
>    gEfiVgaMiniPortProtocolGuid         = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
> +  gX86QemuKernelLoadedImageGuid       = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}

(6) Same as (4).

>  
>  [PcdsFixedAtBuild]
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
> 

With (1)-(4) and (6) fixed, and with (5) optionally implemented:

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images
  2020-03-05 10:31   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-05 10:40     ` Ard Biesheuvel
  2020-03-05 14:29       ` Laszlo Ersek
  0 siblings, 1 reply; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 10:40 UTC (permalink / raw)
  To: edk2-devel-groups-io, Laszlo Ersek

On Thu, 5 Mar 2020 at 11:31, Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 03/04/20 10:52, Ard Biesheuvel wrote:
> > In preparation of moving the legacy x86 loading to an implementation
> > of the QEMU load image library class, introduce a protocol header
> > and GUID that we will use to identify legacy loaded images in the
> > protocol database.
> >
> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> >  OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h | 19 +++++++++++++++++++
> >  OvmfPkg/OvmfPkg.dec                                 |  1 +
> >  2 files changed, 20 insertions(+)
> >
> > diff --git a/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
> > new file mode 100644
> > index 000000000000..7e1bebaa6a07
> > --- /dev/null
> > +++ b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
> > @@ -0,0 +1,19 @@
> > +/** @file
> > +  Protocol/GUID definition to describe a kernel image loaded by the legacy X86
> > +  loader from the file specified on the QEMU command line via the -kernel
> > +  option.
>
> (1) Please add a comment that the interface structure associated with
> this protocol GUID is subject to change, and should not be used outside
> of the EDK II tree.
>
> (I'm requesting this comment regardless of point (5) below.)
>

Now that we're bikeshedding: :-)

Given the internal nature of this protocol, perhaps the name should
reflect it? And if we're changing it, perhaps make it more precise?

It is internal to OVMF so

gOvmfLoadedX86LinuxKernelProtocolGuid

and for the type

OVMF_LOADED_X86_LINUX_KERNEL

(given that the only thing it can represent is a loaded x86 Linux
kernel, but that is not specific to QEMU in principle)

This ignores the initrd aspect as well as the command line, but EFI's
loaded image subsumes the command line as well, so I think that is
fine.




> > +
> > +  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
> > +
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +**/
> > +
> > +#ifndef X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__
> > +#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID_H__
>
> (2) Please drop "_GUID" from the guard macro's name.
>
> > +
> > +#define X86_QEMU_KERNEL_LOADED_IMAGE_GUID \
> > +  {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
>
> (3) Please replace "_GUID" with "_PROTOCOL_GUID" in the initializer
> macro's name.
>
> > +
> > +extern EFI_GUID gX86QemuKernelLoadedImageGuid;
>
> (4) Please replace "Guid" with "ProtocolGuid" in the variable name.
>
> > +
> > +#endif
>
> (5) Please consider moving the QEMU_LEGACY_LOADED_IMAGE typedef here,
> from the next patch. It's not a technical necessity at all, but edk2
> protocol headers always include the interface typedef too. And due to
> (1) above, I think it's safe too.
>
> If you don't like the idea, I won't insist. :)
>
> > diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> > index 055caaa43041..06ffd4198d44 100644
> > --- a/OvmfPkg/OvmfPkg.dec
> > +++ b/OvmfPkg/OvmfPkg.dec
> > @@ -112,6 +112,7 @@ [Protocols]
> >    gEfiLegacyBiosPlatformProtocolGuid  = {0x783658a3, 0x4172, 0x4421, {0xa2, 0x99, 0xe0, 0x09, 0x07, 0x9c, 0x0c, 0xb4}}
> >    gEfiLegacyInterruptProtocolGuid     = {0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe}}
> >    gEfiVgaMiniPortProtocolGuid         = {0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3}}
> > +  gX86QemuKernelLoadedImageGuid       = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
>
> (6) Same as (4).
>
> >
> >  [PcdsFixedAtBuild]
> >    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
> >
>
> With (1)-(4) and (6) fixed, and with (5) optionally implemented:
>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>
> Thanks!
> Laszlo
>
>
> 
>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib
  2020-03-05  9:51   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-05 11:29     ` Laszlo Ersek
  2020-03-05 11:37       ` Ard Biesheuvel
  0 siblings, 1 reply; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 11:29 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/05/20 10:51, Laszlo Ersek wrote:
> On 03/04/20 10:52, Ard Biesheuvel wrote:
>> 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>
>> ---
>>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c   | 278 ++++++++++++++++++++
>>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf |  38 +++
>>  2 files changed, 316 insertions(+)
> 
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>

One request though:

> 
>> diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
>> new file mode 100644
>> index 000000000000..f5edb43cc0b9
>> --- /dev/null
>> +++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
>> @@ -0,0 +1,278 @@
>> +/**  @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
>> +  @param[out] LoadedImage       The loaded image protocol that was installed
>> +                                on ImageHandle by the LoadImage boot service.

(1) Please remove this parameter. (I've noticed this now, after diffing
the two implementations of this function, including leading comments.)

The R-b stands.

Thanks!
Laszlo

>> +
>> +  @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);
>> +}
>> diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
>> new file mode 100644
>> index 000000000000..b262cb926a4d
>> --- /dev/null
>> +++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf
>> @@ -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
>>
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib
  2020-03-05 11:29     ` Laszlo Ersek
@ 2020-03-05 11:37       ` Ard Biesheuvel
  0 siblings, 0 replies; 29+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 11:37 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel-groups-io

On Thu, 5 Mar 2020 at 12:29, Laszlo Ersek <lersek@redhat.com> wrote:
>
> On 03/05/20 10:51, Laszlo Ersek wrote:
> > On 03/04/20 10:52, Ard Biesheuvel wrote:
> >> 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>
> >> ---
> >>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c   | 278 ++++++++++++++++++++
> >>  OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf |  38 +++
> >>  2 files changed, 316 insertions(+)
> >
> > Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>
> One request though:
>
> >
> >> diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
> >> new file mode 100644
> >> index 000000000000..f5edb43cc0b9
> >> --- /dev/null
> >> +++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
> >> @@ -0,0 +1,278 @@
> >> +/**  @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
> >> +  @param[out] LoadedImage       The loaded image protocol that was installed
> >> +                                on ImageHandle by the LoadImage boot service.
>
> (1) Please remove this parameter. (I've noticed this now, after diffing
> the two implementations of this function, including leading comments.)
>
> The R-b stands.
>

Ah yes - that param went out of date a while ago :-)

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback
  2020-03-04  9:52 ` [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
@ 2020-03-05 12:33   ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 12:33 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> 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.

(1) Please remove the last sentence; it no longer applies.

>
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  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/OvmfPkg/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.<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/X86QemuKernelLoadedImage.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) }
> +  }
> +};
> +
> +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 != 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;
> +  QEMU_LEGACY_LOADED_IMAGE        *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));
> +    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));
> +    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;

I agree, this belongs here.

> +  Status = 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 = 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 = gBS->OpenProtocol (ImageHandle,
> +                  &gX86QemuKernelLoadedImageGuid,
> +                  (VOID **)&LoadedImage,
> +                  gImageHandle,                  // AgentHandle
> +                  NULL,                          // ControllerHandle
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = gBS->UninstallProtocolInterface (ImageHandle,
> +                  &gX86QemuKernelLoadedImageGuid, ImageHandle);

(2) Typo: the last argument (for parameter "Interface") should be
LoadedImage, not ImageHandle.

> +  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:
> +    //
> +    // 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 unload
> +    // 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 directly.
> +    //
> +    Status = QemuLoadLegacyImage (&KernelImageHandle);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: QemuLoadLegacyImage(): %r\n", __FUNCTION__,
> +        Status));
> +      return Status;
> +    }
> +    *ImageHandle = KernelImageHandle;
> +    return EFI_SUCCESS;
> +
> +  default:
> +    DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));
> +    return Status;
> +  }

OK. So we reach this point only if the gBS->LoadImage() above succeeds.
Therefore the rest of the function below follows the generic method:

> +
> +  //
> +  // 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);
> +    ASSERT (CommandLine != NULL);
> +
> +    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:
> +  FreePool (CommandLine);
> +  gBS->UnloadImage (KernelImageHandle);
> +
> +  return Status;
> +}

(3) AFAICT you forgot to sync the "CommandLine" lifecycle fixes from the
generic instance to this instance. There's no UnloadImage label, and no
(CommandLineSize > 0) check before freeing "CommandLine".

Here's a diff (between both implementations of this API) that shows
what's needed here:

> @@ -99,7 +79,10 @@
>      KernelLoadedImage->LoadOptionsSize = 0;
>    } else {
>      CommandLine = AllocatePool (CommandLineSize);
> -    ASSERT (CommandLine != NULL);
> +    if (CommandLine == NULL) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      goto UnloadImage;
> +    }
>
>      QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
>      QemuFwCfgReadBytes (CommandLineSize, CommandLine);
> @@ -121,7 +104,7 @@
>    }
>
>    QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
> -  InitrdSize = (UINTN) QemuFwCfgRead32 ();
> +  InitrdSize = (UINTN)QemuFwCfgRead32 ();
>
>    if (InitrdSize > 0) {
>      //
> @@ -161,7 +144,10 @@
>    return EFI_SUCCESS;
>
>  FreeCommandLine:
> -  FreePool (CommandLine);
> +  if (CommandLineSize > 0) {
> +    FreePool (CommandLine);
> +  }
> +UnloadImage:
>    gBS->UnloadImage (KernelImageHandle);
>
>    return Status;

Back to this patch:

> +
> +/**
> +  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;
> +  QEMU_LEGACY_LOADED_IMAGE      *LoadedImage;
> +  EFI_HANDLE                    KernelImageHandle;
> +
> +  Status = gBS->OpenProtocol (*ImageHandle,

(4) Please break this argument to a separate line, too.

> +                  &gX86QemuKernelLoadedImageGuid,
> +                  (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) {
> +    //
> +    // 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 unload the
> +    // image, and reload and start it using the legacy loader.
> +    //
> +    QemuUnloadKernelImage (*ImageHandle);
> +
> +    Status = QemuLoadLegacyImage (&KernelImageHandle);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    *ImageHandle = KernelImageHandle;
> +    return QemuStartLegacyImage (KernelImageHandle);
> +  }
> +#endif
> +  return Status;
> +}

This function is now safe, with regard to the life cycle of handles
created with LoadImage().

However, there is a code path in the function that releases the former
image handle, and creates no new image handle. It happens when
QemuLoadLegacyImage() fails.

That will cause a problem for the caller. In both patch#6
("ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader")
and patch#12 ("OvmfPkg/PlatformBootManagerLib: switch to
QemuLoadImageLib"), QemuUnloadKernelImage() is called -- correctly! --
after QemuStartKernelImage() fails. That works fine if
QemuStartKernelImage() leaves the handle intact, or replaces it with a
new (but also valid) handle. It doesn't work if QemuStartKernelImage()
only invalidates the handle.

(5) Therefore I suggest calling QemuLoadLegacyImage() first, and
QemuUnloadKernelImage() second:

#ifdef MDE_CPU_IA32
  if (Status == EFI_UNSUPPORTED) {
    //
    // explain what's what
    //
    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

Considering the "handle count", this approach uses 1 -> 2 -> 1, rather
than 1 -> 0 -> 1. Holding two handles "in the middle" is safe, holding
zero is not.

Note: I realize that with this, we're returning to the original order of
operations, seen in the previous version. But now we're going to use
*different* handles!

This also means that only *two* use cases remain for
QemuUnloadKernelImage() -- at any point in time, either the custom
(legacy) protocol is installed on the handle, or the standard protocol.
They are mutually exclusive, at all times.


> +
> +/**
> +  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\x19s 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 an normal, non-legacy loaded image, either on behalf of

(6) s/an normal/a normal/

> +  // 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);
> +}

Perfect.

> 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.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 1.27
> +  BASE_NAME                      = X86QemuLoadImageLib
> +  FILE_GUID                      = 2304df80-e21d-4170-9c3c-113c878f7ac0
> +  MODULE_TYPE                    = BASE
> +  VERSION_STRING                 = 1.0
> +  LIBRARY_CLASS                  = 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
>

Looks good. Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-04  9:52 ` [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
@ 2020-03-05 12:57   ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 12:57 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> Replace the open coded sequence to load Linux on x86 with a short and
> generic sequence invoking QemuLoadImageLib, which can be provided by
> a generic version that only supports the LoadImage and StartImage boot
> services, and one that incorporates the entire legacy loading sequence
> as well.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf |   2 +-
>  OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c               | 144 ++------------------
>  2 files changed, 14 insertions(+), 132 deletions(-)

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks,
Laszlo

> 
> diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> index f89cce187942..40ac5dd7f9d5 100644
> --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -48,7 +48,7 @@ [LibraryClasses]
>    NvVarsFileLib
>    QemuFwCfgLib
>    QemuFwCfgS3Lib
> -  LoadLinuxLib
> +  QemuLoadImageLib
>    QemuBootOrderLib
>    ReportStatusCodeLib
>    UefiLib
> diff --git a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> index ddfef925edd3..c6255921779e 100644
> --- a/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> +++ b/OvmfPkg/Library/PlatformBootManagerLib/QemuKernel.c
> @@ -9,11 +9,8 @@
>  
>  #include <Library/BaseLib.h>
>  #include <Library/DebugLib.h>
> -#include <Library/LoadLinuxLib.h>
> -#include <Library/MemoryAllocationLib.h>
> -#include <Library/QemuFwCfgLib.h>
> +#include <Library/QemuLoadImageLib.h>
>  #include <Library/ReportStatusCodeLib.h>
> -#include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  
>  
> @@ -23,120 +20,11 @@ TryRunningQemuKernel (
>    )
>  {
>    EFI_STATUS                Status;
> -  UINTN                     KernelSize;
> -  UINTN                     KernelInitialSize;
> -  VOID                      *KernelBuf;
> -  UINTN                     SetupSize;
> -  VOID                      *SetupBuf;
> -  UINTN                     CommandLineSize;
> -  CHAR8                     *CommandLine;
> -  UINTN                     InitrdSize;
> -  VOID*                     InitrdData;
> +  EFI_HANDLE                KernelImageHandle;
>  
> -  SetupBuf = NULL;
> -  SetupSize = 0;
> -  KernelBuf = NULL;
> -  KernelInitialSize = 0;
> -  CommandLine = NULL;
> -  CommandLineSize = 0;
> -  InitrdData = NULL;
> -  InitrdSize = 0;
> -
> -  if (!QemuFwCfgIsAvailable ()) {
> -    return EFI_NOT_FOUND;
> -  }
> -
> -  QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
> -  KernelSize = (UINTN) QemuFwCfgRead64 ();
> -
> -  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
> -  SetupSize = (UINTN) QemuFwCfgRead64 ();
> -
> -  if (KernelSize == 0 || SetupSize == 0) {
> -    DEBUG ((EFI_D_INFO, "qemu -kernel was not used.\n"));
> -    return EFI_NOT_FOUND;
> -  }
> -
> -  SetupBuf = LoadLinuxAllocateKernelSetupPages (EFI_SIZE_TO_PAGES (SetupSize));
> -  if (SetupBuf == NULL) {
> -    DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel setup!\n"));
> -    return EFI_OUT_OF_RESOURCES;
> -  }
> -
> -  DEBUG ((EFI_D_INFO, "Setup size: 0x%x\n", (UINT32) SetupSize));
> -  DEBUG ((EFI_D_INFO, "Reading kernel setup image ..."));
> -  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
> -  QemuFwCfgReadBytes (SetupSize, SetupBuf);
> -  DEBUG ((EFI_D_INFO, " [done]\n"));
> -
> -  Status = LoadLinuxCheckKernelSetup (SetupBuf, SetupSize);
> -  if (EFI_ERROR (Status)) {
> -    goto FreeAndReturn;
> -  }
> -
> -  Status = LoadLinuxInitializeKernelSetup (SetupBuf);
> -  if (EFI_ERROR (Status)) {
> -    goto FreeAndReturn;
> -  }
> -
> -  KernelInitialSize = LoadLinuxGetKernelSize (SetupBuf, KernelSize);
> -  if (KernelInitialSize == 0) {
> -    Status = EFI_UNSUPPORTED;
> -    goto FreeAndReturn;
> -  }
> -
> -  KernelBuf = LoadLinuxAllocateKernelPages (
> -                SetupBuf,
> -                EFI_SIZE_TO_PAGES (KernelInitialSize));
> -  if (KernelBuf == NULL) {
> -    DEBUG ((EFI_D_ERROR, "Unable to allocate memory for kernel!\n"));
> -    Status = EFI_OUT_OF_RESOURCES;
> -    goto FreeAndReturn;
> -  }
> -
> -  DEBUG ((EFI_D_INFO, "Kernel size: 0x%x\n", (UINT32) KernelSize));
> -  DEBUG ((EFI_D_INFO, "Reading kernel image ..."));
> -  QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
> -  QemuFwCfgReadBytes (KernelSize, KernelBuf);
> -  DEBUG ((EFI_D_INFO, " [done]\n"));
> -
> -  QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
> -  CommandLineSize = (UINTN) QemuFwCfgRead64 ();
> -
> -  if (CommandLineSize > 0) {
> -    CommandLine = LoadLinuxAllocateCommandLinePages (
> -                    EFI_SIZE_TO_PAGES (CommandLineSize));
> -    QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
> -    QemuFwCfgReadBytes (CommandLineSize, CommandLine);
> -  } else {
> -    CommandLine = NULL;
> -  }
> -
> -  Status = LoadLinuxSetCommandLine (SetupBuf, CommandLine);
> -  if (EFI_ERROR (Status)) {
> -    goto FreeAndReturn;
> -  }
> -
> -  QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
> -  InitrdSize = (UINTN) QemuFwCfgRead64 ();
> -
> -  if (InitrdSize > 0) {
> -    InitrdData = LoadLinuxAllocateInitrdPages (
> -                   SetupBuf,
> -                   EFI_SIZE_TO_PAGES (InitrdSize)
> -                   );
> -    DEBUG ((EFI_D_INFO, "Initrd size: 0x%x\n", (UINT32) InitrdSize));
> -    DEBUG ((EFI_D_INFO, "Reading initrd image ..."));
> -    QemuFwCfgSelectItem (QemuFwCfgItemInitrdData);
> -    QemuFwCfgReadBytes (InitrdSize, InitrdData);
> -    DEBUG ((EFI_D_INFO, " [done]\n"));
> -  } else {
> -    InitrdData = NULL;
> -  }
> -
> -  Status = LoadLinuxSetInitrd (SetupBuf, InitrdData, InitrdSize);
> +  Status = QemuLoadKernelImage (&KernelImageHandle);
>    if (EFI_ERROR (Status)) {
> -    goto FreeAndReturn;
> +    return Status;
>    }
>  
>    //
> @@ -147,22 +35,16 @@ TryRunningQemuKernel (
>    REPORT_STATUS_CODE (EFI_PROGRESS_CODE,
>      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
>  
> -  Status = LoadLinux (KernelBuf, SetupBuf);
> +  //
> +  // Start the image.
> +  //
> +  Status = QemuStartKernelImage (&KernelImageHandle);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: QemuStartKernelImage(): %r\n", __FUNCTION__,
> +      Status));
> +  }
>  
> -FreeAndReturn:
> -  if (SetupBuf != NULL) {
> -    FreePages (SetupBuf, EFI_SIZE_TO_PAGES (SetupSize));
> -  }
> -  if (KernelBuf != NULL) {
> -    FreePages (KernelBuf, EFI_SIZE_TO_PAGES (KernelInitialSize));
> -  }
> -  if (CommandLine != NULL) {
> -    FreePages (CommandLine, EFI_SIZE_TO_PAGES (CommandLineSize));
> -  }
> -  if (InitrdData != NULL) {
> -    FreePages (InitrdData, EFI_SIZE_TO_PAGES (InitrdSize));
> -  }
> +  QemuUnloadKernelImage (KernelImageHandle);
>  
>    return Status;
>  }
> -
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path
  2020-03-04  9:52 ` [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
@ 2020-03-05 13:19   ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 13:19 UTC (permalink / raw)
  To: Ard Biesheuvel, devel

On 03/04/20 10:52, Ard Biesheuvel wrote:
> Linux v5.7 will introduce a new method to load the initial ramdisk
> (initrd) from the loader, using the LoadFile2 protocol installed on a
> special vendor GUIDed media device path.
> 
> Add support for this to our QEMU command line kernel/initrd loader.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c   | 79 ++++++++++++++++++++
>  OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf |  2 +
>  2 files changed, 81 insertions(+)
> 
> diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> index 8ccb1983170c..f43b4c0db0ec 100644
> --- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> +++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.c
> @@ -13,15 +13,18 @@
>  #include <Guid/FileInfo.h>
>  #include <Guid/FileSystemInfo.h>
>  #include <Guid/FileSystemVolumeLabelInfo.h>
> +#include <Guid/LinuxEfiInitrdMedia.h>
>  #include <Guid/QemuKernelLoaderFsMedia.h>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/DebugLib.h>
> +#include <Library/DevicePathLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/QemuFwCfgLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
>  #include <Library/UefiRuntimeServicesTableLib.h>
>  #include <Protocol/DevicePath.h>
> +#include <Protocol/LoadFile2.h>
>  #include <Protocol/SimpleFileSystem.h>
>  
>  //
> @@ -84,6 +87,19 @@ STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mFileSystemDevicePath = {
>    }
>  };
>  
> +STATIC CONST SINGLE_VENMEDIA_NODE_DEVPATH mInitrdDevicePath = {
> +  {
> +    {
> +      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
> +      { sizeof (VENDOR_DEVICE_PATH) }
> +    },
> +    LINUX_EFI_INITRD_MEDIA_GUID
> +  }, {
> +    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
> +  }
> +};
> +
>  //
>  // The "file in the EFI stub filesystem" abstraction.
>  //
> @@ -839,6 +855,48 @@ STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
>    StubFileSystemOpenVolume
>  };
>  
> +STATIC
> +EFI_STATUS
> +EFIAPI
> +InitrdLoadFile2 (
> +  IN EFI_LOAD_FILE2_PROTOCOL          *This,
> +  IN EFI_DEVICE_PATH_PROTOCOL         *FilePath,
> +  IN BOOLEAN                          BootPolicy,
> +  IN OUT UINTN                        *BufferSize,

(1) You might want to beautify the columns here, similarly to commit
2632178bc683 ("OvmfPkg: add 'initrd' shell command to expose Linux
initrd via device path", 2020-03-04). Up to you.

Reviewed-by: Laszlo Ersek <lersek@redhat.com>

Thanks
Laszlo

> +  IN VOID                             *Buffer OPTIONAL
> +  )
> +{
> +  CONST KERNEL_BLOB   *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
> +
> +  ASSERT (InitrdBlob->Size > 0);
> +
> +  if (BootPolicy) {
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  if (BufferSize == NULL || !IsDevicePathValid (FilePath, 0)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (FilePath->Type != END_DEVICE_PATH_TYPE ||
> +      FilePath->SubType != END_ENTIRE_DEVICE_PATH_SUBTYPE) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  if (Buffer == NULL || *BufferSize < InitrdBlob->Size) {
> +    *BufferSize = InitrdBlob->Size;
> +    return EFI_BUFFER_TOO_SMALL;
> +  }
> +
> +  CopyMem (Buffer, InitrdBlob->Data, InitrdBlob->Size);
> +
> +  *BufferSize = InitrdBlob->Size;
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC CONST EFI_LOAD_FILE2_PROTOCOL     mInitrdLoadFile2 = {
> +  InitrdLoadFile2,
> +};
>  
>  //
>  // Utility functions.
> @@ -949,6 +1007,7 @@ QemuKernelLoaderFsDxeEntrypoint (
>    KERNEL_BLOB               *KernelBlob;
>    EFI_STATUS                Status;
>    EFI_HANDLE                FileSystemHandle;
> +  EFI_HANDLE                InitrdLoadFile2Handle;
>  
>    if (!QemuFwCfgIsAvailable ()) {
>      return EFI_NOT_FOUND;
> @@ -993,8 +1052,28 @@ QemuKernelLoaderFsDxeEntrypoint (
>      goto FreeBlobs;
>    }
>  
> +  if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
> +    InitrdLoadFile2Handle = NULL;
> +    Status = gBS->InstallMultipleProtocolInterfaces (&InitrdLoadFile2Handle,
> +                    &gEfiDevicePathProtocolGuid,  &mInitrdDevicePath,
> +                    &gEfiLoadFile2ProtocolGuid,   &mInitrdLoadFile2,
> +                    NULL);
> +    if (EFI_ERROR (Status)) {
> +      DEBUG ((DEBUG_ERROR, "%a: InstallMultipleProtocolInterfaces(): %r\n",
> +        __FUNCTION__, Status));
> +      goto UninstallFileSystemHandle;
> +    }
> +  }
> +
>    return EFI_SUCCESS;
>  
> +UninstallFileSystemHandle:
> +  Status = gBS->UninstallMultipleProtocolInterfaces (FileSystemHandle,
> +                  &gEfiDevicePathProtocolGuid,       &mFileSystemDevicePath,
> +                  &gEfiSimpleFileSystemProtocolGuid, &mFileSystem,
> +                  NULL);
> +  ASSERT_EFI_ERROR (Status);
> +
>  FreeBlobs:
>    while (BlobType > 0) {
>      CurrentBlob = &mKernelBlob[--BlobType];
> diff --git a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
> index 5ba88063def0..7b35adb8e034 100644
> --- a/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
> +++ b/OvmfPkg/QemuKernelLoaderFsDxe/QemuKernelLoaderFsDxe.inf
> @@ -28,6 +28,7 @@ [LibraryClasses]
>    BaseLib
>    BaseMemoryLib
>    DebugLib
> +  DevicePathLib
>    MemoryAllocationLib
>    QemuFwCfgLib
>    UefiBootServicesTableLib
> @@ -42,6 +43,7 @@ [Guids]
>  
>  [Protocols]
>    gEfiDevicePathProtocolGuid                ## PRODUCES
> +  gEfiLoadFile2ProtocolGuid                 ## PRODUCES
>    gEfiSimpleFileSystemProtocolGuid          ## PRODUCES
>  
>  [Depex]
> 


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [edk2-devel] [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images
  2020-03-05 10:40     ` Ard Biesheuvel
@ 2020-03-05 14:29       ` Laszlo Ersek
  0 siblings, 0 replies; 29+ messages in thread
From: Laszlo Ersek @ 2020-03-05 14:29 UTC (permalink / raw)
  To: Ard Biesheuvel, edk2-devel-groups-io

On 03/05/20 11:40, Ard Biesheuvel wrote:
> On Thu, 5 Mar 2020 at 11:31, Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> On 03/04/20 10:52, Ard Biesheuvel wrote:
>>> In preparation of moving the legacy x86 loading to an implementation
>>> of the QEMU load image library class, introduce a protocol header
>>> and GUID that we will use to identify legacy loaded images in the
>>> protocol database.
>>>
>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>> ---
>>>  OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h | 19 +++++++++++++++++++
>>>  OvmfPkg/OvmfPkg.dec                                 |  1 +
>>>  2 files changed, 20 insertions(+)
>>>
>>> diff --git a/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
>>> new file mode 100644
>>> index 000000000000..7e1bebaa6a07
>>> --- /dev/null
>>> +++ b/OvmfPkg/Include/Protocol/X86QemuKernelLoadedImage.h
>>> @@ -0,0 +1,19 @@
>>> +/** @file
>>> +  Protocol/GUID definition to describe a kernel image loaded by the legacy X86
>>> +  loader from the file specified on the QEMU command line via the -kernel
>>> +  option.
>>
>> (1) Please add a comment that the interface structure associated with
>> this protocol GUID is subject to change, and should not be used outside
>> of the EDK II tree.
>>
>> (I'm requesting this comment regardless of point (5) below.)
>>
> 
> Now that we're bikeshedding: :-)

I don't feel we are :) All the things I've asked for are existing
practice in edk2. In particular (1) would mirror the note in
"VirtioDevice.h".

> 
> Given the internal nature of this protocol, perhaps the name should
> reflect it? And if we're changing it, perhaps make it more precise?
> 
> It is internal to OVMF so
> 
> gOvmfLoadedX86LinuxKernelProtocolGuid
> 
> and for the type
> 
> OVMF_LOADED_X86_LINUX_KERNEL
> 
> (given that the only thing it can represent is a loaded x86 Linux
> kernel, but that is not specific to QEMU in principle)
> 
> This ignores the initrd aspect as well as the command line, but EFI's
> loaded image subsumes the command line as well, so I think that is
> fine.

Great suggestions, I like them.

Thanks!
Laszlo


^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2020-03-05 14:29 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-04  9:52 [PATCH v2 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
2020-03-05  9:37   ` [edk2-devel] " Laszlo Ersek
2020-03-05  9:39     ` Laszlo Ersek
2020-03-05 10:22       ` Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
2020-03-05  9:51   ` [edk2-devel] " Laszlo Ersek
2020-03-05 11:29     ` Laszlo Ersek
2020-03-05 11:37       ` Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
2020-03-05 10:01   ` [edk2-devel] " Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
2020-03-05 10:12   ` [edk2-devel] " Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 09/14] OvmfPkg: create protocol and GUID header for legacy loaded images Ard Biesheuvel
2020-03-05 10:31   ` [edk2-devel] " Laszlo Ersek
2020-03-05 10:40     ` Ard Biesheuvel
2020-03-05 14:29       ` Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
2020-03-05 12:33   ` [edk2-devel] " Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 11/14] OvmfPkg: add new QEMU kernel image loader components Ard Biesheuvel
2020-03-04  9:52 ` [PATCH v2 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
2020-03-05 12:57   ` [edk2-devel] " Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
2020-03-05 13:19   ` Laszlo Ersek
2020-03-04  9:52 ` [PATCH v2 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox