public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images
@ 2020-03-05 13:45 Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
                   ` (14 more replies)
  0 siblings, 15 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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 (now #13 adds the new Linux specific initrd loadfile2 protocol that
aims to simplify initrd loading from Linux when booting via the PE stub.

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

Changes since [v2]:
- rename gX86QemuKernelLoadedImageGuid to gOvmfLoadedX86LinuxKernelProtocolGuid,
  and define the associated struct type OVMF_LOADED_X86_LINUX_KERNEL in the
  protocol header file
- mention that the new protocol is internal ABI and subject to backward
  incompatible change at any time
- align legacy loader logic more closely with the generic one
- modify legacy mixed mode handling to prevent returning a stale handle
- add Laszlo's ack to #4, #6, #8, #12 and #13
- fix up some style issues and out of date/inaccurate comments (Laszlo)

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 (*)

(*) v2+ numbering

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
https://github.com/ardbiesheuvel/edk2/tree/ovmf-loadimage-startimage-v3

[v1] http://mid.mail-archive.com/20200302072936.29221-1-ard.biesheuvel@linaro.org
[v2] http://mid.mail-archive.com/20200304095233.21046-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 loaded x86 Linux kernels
  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/OvmfLoadedX86LinuxKernel.h       |   32 +
 .../GenericQemuLoadImageLib.c                 |  276 +++++
 .../GenericQemuLoadImageLib.inf               |   38 +
 .../PlatformBootManagerLib.inf                |    2 +-
 .../PlatformBootManagerLib/QemuKernel.c       |  144 +--
 .../X86QemuLoadImageLib/X86QemuLoadImageLib.c |  567 +++++++++
 .../X86QemuLoadImageLib.inf                   |   42 +
 OvmfPkg/OvmfPkg.dec                           |   57 +-
 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, 1354 insertions(+), 1419 deletions(-)
 create mode 100644 OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h
 create mode 100644 OvmfPkg/Include/Library/QemuLoadImageLib.h
 create mode 100644 OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.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] 30+ messages in thread

* [PATCH v3 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver Ard Biesheuvel
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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] 30+ messages in thread

* [PATCH v3 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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] 30+ messages in thread

* [PATCH v3 03/14] OvmfPkg: introduce QemuLoadImageLib library class
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 01/14] OvmfPkg: add GUID for the QEMU kernel loader fs media device path Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 02/14] OvmfPkg: export abstract QEMU blob filesystem in standalone driver Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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..746b74f73c40
--- /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] 30+ messages in thread

* [PATCH v3 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2020-03-05 13:45 ` [PATCH v3 03/14] OvmfPkg: introduce QemuLoadImageLib library class Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library Ard Biesheuvel
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c   | 276 ++++++++++++++++++++
 OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.inf |  38 +++
 2 files changed, 314 insertions(+)

diff --git a/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
new file mode 100644
index 000000000000..f7f9a205f99d
--- /dev/null
+++ b/OvmfPkg/Library/GenericQemuLoadImageLib/GenericQemuLoadImageLib.c
@@ -0,0 +1,276 @@
+/**  @file
+  Generic implementation of QemuLoadImageLib library class interface.
+
+  Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+
+#include <Base.h>
+#include <Guid/QemuKernelLoaderFsMedia.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/QemuFwCfgLib.h>
+#include <Library/QemuLoadImageLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/LoadedImage.h>
+
+#pragma pack (1)
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  FilePathHeader;
+  CHAR16                    FilePath[ARRAY_SIZE (L"kernel")];
+} KERNEL_FILE_DEVPATH;
+
+typedef struct {
+  VENDOR_DEVICE_PATH        VenMediaNode;
+  KERNEL_FILE_DEVPATH       FileNode;
+  EFI_DEVICE_PATH_PROTOCOL  EndNode;
+} KERNEL_VENMEDIA_FILE_DEVPATH;
+#pragma pack ()
+
+STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
+  {
+    {
+      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+      { sizeof (VENDOR_DEVICE_PATH) }
+    },
+    QEMU_KERNEL_LOADER_FS_MEDIA_GUID
+  }, {
+    {
+      MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,
+      { sizeof (KERNEL_FILE_DEVPATH) }
+    },
+    L"kernel",
+  }, {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
+  }
+};
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. The kernel will be instructed via its command line to load
+  the initrd from the same Simple FileSystem where the kernel was loaded from.
+
+  @param[out] ImageHandle       The image handle that was allocated for
+                                loading the image
+
+  @retval EFI_SUCCESS           The image was loaded successfully.
+  @retval EFI_NOT_FOUND         Kernel image was not found.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
+  @retval EFI_ACCESS_DENIED     The underlying LoadImage boot service call
+                                returned EFI_SECURITY_VIOLATION, and the image
+                                was unloaded again.
+
+  @return                       Error codes from any of the underlying
+                                functions.
+**/
+EFI_STATUS
+EFIAPI
+QemuLoadKernelImage (
+  OUT EFI_HANDLE                  *ImageHandle
+  )
+{
+  EFI_STATUS                Status;
+  EFI_HANDLE                KernelImageHandle;
+  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
+  UINTN                     CommandLineSize;
+  CHAR8                     *CommandLine;
+  UINTN                     InitrdSize;
+
+  //
+  // Load the image. This should call back into the QEMU EFI loader file system.
+  //
+  Status = gBS->LoadImage (
+                  FALSE,                    // BootPolicy: exact match required
+                  gImageHandle,             // ParentImageHandle
+                  (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,
+                  NULL,                     // SourceBuffer
+                  0,                        // SourceSize
+                  &KernelImageHandle
+                  );
+  switch (Status) {
+  case EFI_SUCCESS:
+    break;
+
+  case EFI_SECURITY_VIOLATION:
+    //
+    // In this case, the image was loaded but failed to authenticate.
+    //
+    Status = EFI_ACCESS_DENIED;
+    goto UnloadImage;
+
+  default:
+    DEBUG ((DEBUG_ERROR, "%a: LoadImage(): %r\n", __FUNCTION__, Status));
+    return Status;
+  }
+
+  //
+  // Construct the kernel command line.
+  //
+  Status = gBS->OpenProtocol (
+                  KernelImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&KernelLoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
+  CommandLineSize = (UINTN)QemuFwCfgRead32 ();
+
+  if (CommandLineSize == 0) {
+    KernelLoadedImage->LoadOptionsSize = 0;
+  } else {
+    CommandLine = AllocatePool (CommandLineSize);
+    if (CommandLine == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto UnloadImage;
+    }
+
+    QemuFwCfgSelectItem (QemuFwCfgItemCommandLineData);
+    QemuFwCfgReadBytes (CommandLineSize, CommandLine);
+
+    //
+    // Verify NUL-termination of the command line.
+    //
+    if (CommandLine[CommandLineSize - 1] != '\0') {
+      DEBUG ((DEBUG_ERROR, "%a: kernel command line is not NUL-terminated\n",
+        __FUNCTION__));
+      Status = EFI_PROTOCOL_ERROR;
+      goto FreeCommandLine;
+    }
+
+    //
+    // Drop the terminating NUL, convert to UTF-16.
+    //
+    KernelLoadedImage->LoadOptionsSize = (CommandLineSize - 1) * 2;
+  }
+
+  QemuFwCfgSelectItem (QemuFwCfgItemInitrdSize);
+  InitrdSize = (UINTN)QemuFwCfgRead32 ();
+
+  if (InitrdSize > 0) {
+    //
+    // Append ' initrd=initrd' in UTF-16.
+    //
+    KernelLoadedImage->LoadOptionsSize += sizeof (L" initrd=initrd") - 2;
+  }
+
+  if (KernelLoadedImage->LoadOptionsSize == 0) {
+    KernelLoadedImage->LoadOptions = NULL;
+  } else {
+    //
+    // NUL-terminate in UTF-16.
+    //
+    KernelLoadedImage->LoadOptionsSize += 2;
+
+    KernelLoadedImage->LoadOptions = AllocatePool (
+                                       KernelLoadedImage->LoadOptionsSize);
+    if (KernelLoadedImage->LoadOptions == NULL) {
+      KernelLoadedImage->LoadOptionsSize = 0;
+      Status = EFI_OUT_OF_RESOURCES;
+      goto FreeCommandLine;
+    }
+
+    UnicodeSPrintAsciiFormat (
+      KernelLoadedImage->LoadOptions,
+      KernelLoadedImage->LoadOptionsSize,
+      "%a%a",
+      (CommandLineSize == 0) ?  "" : CommandLine,
+      (InitrdSize == 0)      ?  "" : " initrd=initrd"
+      );
+    DEBUG ((DEBUG_INFO, "%a: command line: \"%s\"\n", __FUNCTION__,
+      (CHAR16 *)KernelLoadedImage->LoadOptions));
+  }
+
+  *ImageHandle = KernelImageHandle;
+  return EFI_SUCCESS;
+
+FreeCommandLine:
+  if (CommandLineSize > 0) {
+    FreePool (CommandLine);
+  }
+UnloadImage:
+  gBS->UnloadImage (KernelImageHandle);
+
+  return Status;
+}
+
+/**
+  Transfer control to a kernel image loaded with QemuLoadKernelImage ()
+
+  @param[in,out]  ImageHandle     Handle of image to be started. May assume a
+                                  different value on return if the image was
+                                  reloaded.
+
+  @retval EFI_INVALID_PARAMETER   ImageHandle is either an invalid image handle
+                                  or the image has already been initialized with
+                                  StartImage
+  @retval EFI_SECURITY_VIOLATION  The current platform policy specifies that the
+                                  image should not be started.
+
+  @return                         Error codes returned by the started image
+**/
+EFI_STATUS
+EFIAPI
+QemuStartKernelImage (
+  IN  OUT EFI_HANDLE          *ImageHandle
+  )
+{
+  return gBS->StartImage (
+                *ImageHandle,
+                NULL,              // ExitDataSize
+                NULL               // ExitData
+                );
+}
+
+/**
+  Unloads an image loaded with QemuLoadKernelImage ().
+
+  @param  ImageHandle             Handle that identifies the image to be
+                                  unloaded.
+
+  @retval EFI_SUCCESS             The image has been unloaded.
+  @retval EFI_UNSUPPORTED         The image has been started, and does not
+                                  support unload.
+  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
+
+  @return                         Exit code from the image's unload function.
+**/
+EFI_STATUS
+EFIAPI
+QemuUnloadKernelImage (
+  IN  EFI_HANDLE          ImageHandle
+  )
+{
+  EFI_LOADED_IMAGE_PROTOCOL   *KernelLoadedImage;
+  EFI_STATUS                  Status;
+
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&KernelLoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (KernelLoadedImage->LoadOptions != NULL) {
+    FreePool (KernelLoadedImage->LoadOptions);
+    KernelLoadedImage->LoadOptions = NULL;
+  }
+  KernelLoadedImage->LoadOptionsSize = 0;
+
+  return gBS->UnloadImage (ImageHandle);
+}
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] 30+ messages in thread

* [PATCH v3 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2020-03-05 13:45 ` [PATCH v3 04/14] OvmfPkg: provide a generic implementation of QemuLoadImageLib Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:45 ` [PATCH v3 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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] 30+ messages in thread

* [PATCH v3 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2020-03-05 13:45 ` [PATCH v3 05/14] ArmVirtPkg: incorporate the new QEMU kernel loader driver and library Ard Biesheuvel
@ 2020-03-05 13:45 ` Ard Biesheuvel
  2020-03-05 13:46 ` [PATCH v3 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line Ard Biesheuvel
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:45 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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 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 6fe0a1bb122b..11f52e019bc3 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,19 +63,13 @@ [Pcd]
   gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
 
 [Guids]
-  gEfiFileInfoGuid
-  gEfiFileSystemInfoGuid
-  gEfiFileSystemVolumeLabelInfoIdGuid
   gEfiEndOfDxeEventGroupGuid
   gEfiGlobalVariableGuid
   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] 30+ messages in thread

* [PATCH v3 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (5 preceding siblings ...)
  2020-03-05 13:45 ` [PATCH v3 06/14] ArmVirtPkg/PlatformBootManagerLib: switch to separate QEMU loader Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 13:46 ` [PATCH v3 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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] 30+ messages in thread

* [PATCH v3 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (6 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 07/14] OvmfPkg/QemuKernelLoaderFsDxe: don't expose kernel command line Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 13:46 ` [PATCH v3 09/14] OvmfPkg: create protocol and GUID header for loaded x86 Linux kernels Ard Biesheuvel
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 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] 30+ messages in thread

* [PATCH v3 09/14] OvmfPkg: create protocol and GUID header for loaded x86 Linux kernels
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (7 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 08/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for the kernel setup block Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 16:01   ` [edk2-devel] " Laszlo Ersek
  2020-03-05 13:46 ` [PATCH v3 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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 x86 Linux kernels
in the protocol database.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h | 32 ++++++++++++
 OvmfPkg/OvmfPkg.dec                                 | 53 ++++++++++----------
 2 files changed, 59 insertions(+), 26 deletions(-)

diff --git a/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h b/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h
new file mode 100644
index 000000000000..01cfd9d189b4
--- /dev/null
+++ b/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h
@@ -0,0 +1,32 @@
+/** @file
+  Protocol/GUID definition to describe a x86 Linux kernel image loaded
+  into memory.
+
+  Note that this protocol is considered internal ABI, and may be change
+  structure at any time without regard for backward compatibility.
+
+  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef OVMF_LOADED_X86_LINUX_KERNEL_H__
+#define OVMF_LOADED_X86_LINUX_KERNEL_H__
+
+#define OVMF_LOADED_X86_LINUX_KERNEL_PROTOCOL_GUID \
+  {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
+
+typedef struct {
+  VOID    *SetupBuf;
+  VOID    *KernelBuf;
+  CHAR8   *CommandLine;
+  VOID    *InitrdData;
+  UINTN   SetupSize;
+  UINTN   KernelInitialSize;
+  UINTN   InitrdSize;
+  UINTN   CommandLineSize;
+} OVMF_LOADED_X86_LINUX_KERNEL;
+
+extern EFI_GUID gOvmfLoadedX86LinuxKernelProtocolGuid;
+
+#endif
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 055caaa43041..913345d49e1f 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -80,38 +80,39 @@ [LibraryClasses]
   XenPlatformLib|Include/Library/XenPlatformLib.h
 
 [Guids]
-  gUefiOvmfPkgTokenSpaceGuid          = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
-  gEfiXenInfoGuid                     = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
-  gOvmfPkKek1AppPrefixGuid            = {0x4e32566d, 0x8e9e, 0x4f52, {0x81, 0xd3, 0x5b, 0xb9, 0x71, 0x5f, 0x97, 0x27}}
-  gOvmfPlatformConfigGuid             = {0x7235c51c, 0x0c80, 0x4cab, {0x87, 0xac, 0x3b, 0x08, 0x4a, 0x63, 0x04, 0xb1}}
-  gVirtioMmioTransportGuid            = {0x837dca9e, 0xe874, 0x4d82, {0xb2, 0x9a, 0x23, 0xfe, 0x0e, 0x23, 0xd1, 0xe2}}
-  gQemuRamfbGuid                      = {0x557423a1, 0x63ab, 0x406c, {0xbe, 0x7e, 0x91, 0xcd, 0xbc, 0x08, 0xc4, 0x57}}
-  gXenBusRootDeviceGuid               = {0xa732241f, 0x383d, 0x4d9c, {0x8a, 0xe1, 0x8e, 0x09, 0x83, 0x75, 0x89, 0xd7}}
-  gRootBridgesConnectedEventGroupGuid = {0x24a2d66f, 0xeedd, 0x4086, {0x90, 0x42, 0xf2, 0x6e, 0x47, 0x97, 0xee, 0x69}}
-  gMicrosoftVendorGuid                = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}}
-  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}}
+  gUefiOvmfPkgTokenSpaceGuid            = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
+  gEfiXenInfoGuid                       = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
+  gOvmfPkKek1AppPrefixGuid              = {0x4e32566d, 0x8e9e, 0x4f52, {0x81, 0xd3, 0x5b, 0xb9, 0x71, 0x5f, 0x97, 0x27}}
+  gOvmfPlatformConfigGuid               = {0x7235c51c, 0x0c80, 0x4cab, {0x87, 0xac, 0x3b, 0x08, 0x4a, 0x63, 0x04, 0xb1}}
+  gVirtioMmioTransportGuid              = {0x837dca9e, 0xe874, 0x4d82, {0xb2, 0x9a, 0x23, 0xfe, 0x0e, 0x23, 0xd1, 0xe2}}
+  gQemuRamfbGuid                        = {0x557423a1, 0x63ab, 0x406c, {0xbe, 0x7e, 0x91, 0xcd, 0xbc, 0x08, 0xc4, 0x57}}
+  gXenBusRootDeviceGuid                 = {0xa732241f, 0x383d, 0x4d9c, {0x8a, 0xe1, 0x8e, 0x09, 0x83, 0x75, 0x89, 0xd7}}
+  gRootBridgesConnectedEventGroupGuid   = {0x24a2d66f, 0xeedd, 0x4086, {0x90, 0x42, 0xf2, 0x6e, 0x47, 0x97, 0xee, 0x69}}
+  gMicrosoftVendorGuid                  = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}}
+  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
   # has been discovered and recorded
-  gOvmfTpmDiscoveredPpiGuid           = {0xb9a61ad0, 0x2802, 0x41f3, {0xb5, 0x13, 0x96, 0x51, 0xce, 0x6b, 0xd5, 0x75}}
+  gOvmfTpmDiscoveredPpiGuid             = {0xb9a61ad0, 0x2802, 0x41f3, {0xb5, 0x13, 0x96, 0x51, 0xce, 0x6b, 0xd5, 0x75}}
 
 [Protocols]
-  gVirtioDeviceProtocolGuid           = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}}
-  gXenBusProtocolGuid                 = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}}
-  gXenIoProtocolGuid                  = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}}
-  gIoMmuAbsentProtocolGuid            = {0xf8775d50, 0x8abd, 0x4adf, {0x92, 0xac, 0x85, 0x3e, 0x51, 0xf6, 0xc8, 0xdc}}
-  gEfiLegacy8259ProtocolGuid          = {0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1}}
-  gEfiFirmwareVolumeProtocolGuid      = {0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xcd, 0x81, 0x54, 0xbd, 0x27, 0xf8}}
-  gEfiIsaAcpiProtocolGuid             = {0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55}}
-  gEfiIsaIoProtocolGuid               = {0x7ee2bd44, 0x3da0, 0x11d4, {0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d}}
-  gEfiLegacyBiosProtocolGuid          = {0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d}}
-  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}}
+  gVirtioDeviceProtocolGuid             = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}}
+  gXenBusProtocolGuid                   = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}}
+  gXenIoProtocolGuid                    = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}}
+  gIoMmuAbsentProtocolGuid              = {0xf8775d50, 0x8abd, 0x4adf, {0x92, 0xac, 0x85, 0x3e, 0x51, 0xf6, 0xc8, 0xdc}}
+  gEfiLegacy8259ProtocolGuid            = {0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1}}
+  gEfiFirmwareVolumeProtocolGuid        = {0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xcd, 0x81, 0x54, 0xbd, 0x27, 0xf8}}
+  gEfiIsaAcpiProtocolGuid               = {0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55}}
+  gEfiIsaIoProtocolGuid                 = {0x7ee2bd44, 0x3da0, 0x11d4, {0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d}}
+  gEfiLegacyBiosProtocolGuid            = {0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d}}
+  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}}
+  gOvmfLoadedX86LinuxKernelProtocolGuid = {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] 30+ messages in thread

* [PATCH v3 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (8 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 09/14] OvmfPkg: create protocol and GUID header for loaded x86 Linux kernels Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 18:03   ` [edk2-devel] " Laszlo Ersek
  2020-03-05 13:46 ` [PATCH v3 11/14] OvmfPkg: add new QEMU kernel image loader components Ard Biesheuvel
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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 the OVMF_LOADED_X86_LINUX_KERNEL 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
a loaded image solely by a handle.

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

diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
new file mode 100644
index 000000000000..e5979981ff8f
--- /dev/null
+++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
@@ -0,0 +1,567 @@
+/**  @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/OvmfLoadedX86LinuxKernel.h>
+
+#pragma pack (1)
+typedef struct {
+  EFI_DEVICE_PATH_PROTOCOL  FilePathHeader;
+  CHAR16                    FilePath[ARRAY_SIZE (L"kernel")];
+} KERNEL_FILE_DEVPATH;
+
+typedef struct {
+  VENDOR_DEVICE_PATH        VenMediaNode;
+  KERNEL_FILE_DEVPATH       FileNode;
+  EFI_DEVICE_PATH_PROTOCOL  EndNode;
+} KERNEL_VENMEDIA_FILE_DEVPATH;
+#pragma pack ()
+
+STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
+  {
+    {
+      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
+      { sizeof (VENDOR_DEVICE_PATH) }
+    },
+    QEMU_KERNEL_LOADER_FS_MEDIA_GUID
+  }, {
+    {
+      MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,
+      { sizeof (KERNEL_FILE_DEVPATH) }
+    },
+    L"kernel",
+  }, {
+    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
+  }
+};
+
+STATIC
+VOID
+FreeLegacyImage (
+  IN  OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage
+  )
+{
+  if (LoadedImage->SetupBuf != NULL) {
+    FreePages (LoadedImage->SetupBuf,
+      EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));
+  }
+  if (LoadedImage->KernelBuf != NULL) {
+    FreePages (LoadedImage->KernelBuf,
+      EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize));
+  }
+  if (LoadedImage->CommandLine != NULL) {
+    FreePages (LoadedImage->CommandLine,
+      EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize));
+  }
+  if (LoadedImage->InitrdData != NULL) {
+    FreePages (LoadedImage->InitrdData,
+      EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize));
+  }
+}
+
+STATIC
+EFI_STATUS
+QemuLoadLegacyImage (
+  OUT EFI_HANDLE                  *ImageHandle
+  )
+{
+  EFI_STATUS                      Status;
+  UINTN                           KernelSize;
+  UINTN                           SetupSize;
+  OVMF_LOADED_X86_LINUX_KERNEL    *LoadedImage;
+
+  QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
+  KernelSize = (UINTN)QemuFwCfgRead32 ();
+
+  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
+  SetupSize = (UINTN)QemuFwCfgRead32 ();
+
+  if (KernelSize == 0 || SetupSize == 0) {
+    DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));
+  if (LoadedImage == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  LoadedImage->SetupSize = SetupSize;
+  LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (
+                            EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));
+  if (LoadedImage->SetupBuf == NULL) {
+    DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeImageDesc;
+  }
+
+  DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize));
+  DEBUG ((DEBUG_INFO, "Reading kernel setup image ..."));
+  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
+  QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf);
+  DEBUG ((DEBUG_INFO, " [done]\n"));
+
+  Status = LoadLinuxCheckKernelSetup (LoadedImage->SetupBuf,
+             LoadedImage->SetupSize);
+  if (EFI_ERROR (Status)) {
+    goto FreeImage;
+  }
+
+  Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);
+  if (EFI_ERROR (Status)) {
+    goto FreeImage;
+  }
+
+  LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (
+                                     LoadedImage->SetupBuf, KernelSize);
+  if (LoadedImage->KernelInitialSize == 0) {
+    Status = EFI_UNSUPPORTED;
+    goto FreeImage;
+  }
+
+  LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (
+                             LoadedImage->SetupBuf,
+                             EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
+                             );
+  if (LoadedImage->KernelBuf == NULL) {
+    DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeImage;
+  }
+
+  DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize));
+  DEBUG ((DEBUG_INFO, "Reading kernel image ..."));
+  QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
+  QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf);
+  DEBUG ((DEBUG_INFO, " [done]\n"));
+
+  QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
+  LoadedImage->CommandLineSize = (UINTN)QemuFwCfgRead32 ();
+
+  if (LoadedImage->CommandLineSize > 0) {
+    LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (
+                                 EFI_SIZE_TO_PAGES (
+                                   LoadedImage->CommandLineSize));
+    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,
+                  &gOvmfLoadedX86LinuxKernelProtocolGuid, EFI_NATIVE_INTERFACE,
+                  LoadedImage);
+  if (EFI_ERROR (Status)) {
+    goto FreeImage;
+  }
+  return EFI_SUCCESS;
+
+FreeImage:
+  FreeLegacyImage (LoadedImage);
+FreeImageDesc:
+  FreePool (LoadedImage);
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+QemuStartLegacyImage (
+  IN  EFI_HANDLE                ImageHandle
+  )
+{
+  EFI_STATUS                    Status;
+  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
+
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
+                  (VOID **)&LoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf);
+}
+
+STATIC
+EFI_STATUS
+QemuUnloadLegacyImage (
+  IN  EFI_HANDLE          ImageHandle
+  )
+{
+  EFI_STATUS                    Status;
+  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
+
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
+                  (VOID **)&LoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = gBS->UninstallProtocolInterface (ImageHandle,
+                  &gOvmfLoadedX86LinuxKernelProtocolGuid, LoadedImage);
+  ASSERT_EFI_ERROR (Status);
+
+  FreeLegacyImage (LoadedImage);
+  FreePool (LoadedImage);
+  return EFI_SUCCESS;
+}
+
+/**
+  Download the kernel, the initial ramdisk, and the kernel command line from
+  QEMU's fw_cfg. The kernel will be instructed via its command line to load
+  the initrd from the same Simple FileSystem where the kernel was loaded from.
+
+  @param[out] ImageHandle       The image handle that was allocated for
+                                loading the image
+
+  @retval EFI_SUCCESS           The image was loaded successfully.
+  @retval EFI_NOT_FOUND         Kernel image was not found.
+  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
+  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
+
+  @return                       Error codes from any of the underlying
+                                functions.
+**/
+EFI_STATUS
+EFIAPI
+QemuLoadKernelImage (
+  OUT EFI_HANDLE            *ImageHandle
+  )
+{
+  EFI_STATUS                Status;
+  EFI_HANDLE                KernelImageHandle;
+  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
+  UINTN                     CommandLineSize;
+  CHAR8                     *CommandLine;
+  UINTN                     InitrdSize;
+
+  //
+  // Load the image. This should call back into the QEMU EFI loader file system.
+  //
+  Status = gBS->LoadImage (
+                  FALSE,                    // BootPolicy: exact match required
+                  gImageHandle,             // ParentImageHandle
+                  (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,
+                  NULL,                     // SourceBuffer
+                  0,                        // SourceSize
+                  &KernelImageHandle
+                  );
+  switch (Status) {
+  case EFI_SUCCESS:
+    break;
+
+  case EFI_NOT_FOUND:
+    //
+    // The image does not exist - no -kernel image was supplied via the
+    // command line so no point in invoking the legacy fallback
+    //
+    return EFI_NOT_FOUND;
+
+  case EFI_SECURITY_VIOLATION:
+    //
+    // 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);
+    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
+  )
+{
+  EFI_STATUS                    Status;
+  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
+  EFI_HANDLE                    KernelImageHandle;
+
+  Status = gBS->OpenProtocol (
+                  *ImageHandle,
+                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
+                  (VOID **)&LoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    return QemuStartLegacyImage (*ImageHandle);
+  }
+
+  Status = gBS->StartImage (
+                  *ImageHandle,
+                  NULL,              // ExitDataSize
+                  NULL               // ExitData
+                  );
+#ifdef MDE_CPU_IA32
+  if (Status == EFI_UNSUPPORTED) {
+    //
+    // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64 while
+    // we are expecting a IA32 one, and the StartImage () boot service is unable
+    // to handle it, either because the image does not have the special .compat
+    // PE/COFF section that Linux specifies for mixed mode capable images, or
+    // because we are running without the support code for that. So load the
+    // image again, using the legacy loader, and unload the normally loaded
+    // image before starting the legacy one.
+    //
+    Status = QemuLoadLegacyImage (&KernelImageHandle);
+    if (EFI_ERROR (Status)) {
+      //
+      // Note: no change to (*ImageHandle), the caller will release it.
+      //
+      return Status;
+    }
+    //
+    // Swap in the legacy-loaded image.
+    //
+    QemuUnloadKernelImage (*ImageHandle);
+    *ImageHandle = KernelImageHandle;
+    return QemuStartLegacyImage (KernelImageHandle);
+  }
+#endif
+  return Status;
+}
+
+/**
+  Unloads an image loaded with QemuLoadKernelImage ().
+
+  @param  ImageHandle             Handle that identifies the image to be
+                                  unloaded.
+
+  @retval EFI_SUCCESS             The image has been unloaded.
+  @retval EFI_UNSUPPORTED         The image has been started, and does not
+                                  support unload.
+  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
+
+  @return                         Exit code from the image's unload function.
+**/
+EFI_STATUS
+EFIAPI
+QemuUnloadKernelImage (
+  IN  EFI_HANDLE          ImageHandle
+  )
+{
+  EFI_LOADED_IMAGE_PROTOCOL   *KernelLoadedImage;
+  EFI_STATUS                  Status;
+
+  Status = gBS->OpenProtocol (
+                  ImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&KernelLoadedImage,
+                  gImageHandle,                  // AgentHandle
+                  NULL,                          // ControllerHandle
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (Status == EFI_UNSUPPORTED) {
+    //
+    // The handle exists but does not have an instance of the standard loaded
+    // image protocol installed on it. Attempt to unload it as a legacy image
+    // instead.
+    //
+    return QemuUnloadLegacyImage (ImageHandle);
+  }
+
+  if (EFI_ERROR (Status)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // We are unloading a normal, non-legacy loaded image, either on behalf of
+  // an external caller, or called from QemuStartKernelImage() on IA32, while
+  // switching from the normal to the legacy method to load and start a X64
+  // image.
+  //
+  if (KernelLoadedImage->LoadOptions != NULL) {
+    FreePool (KernelLoadedImage->LoadOptions);
+    KernelLoadedImage->LoadOptions = NULL;
+  }
+  KernelLoadedImage->LoadOptionsSize = 0;
+
+  return gBS->UnloadImage (ImageHandle);
+}
diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
new file mode 100644
index 000000000000..e1615badd2ba
--- /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
+  gOvmfLoadedX86LinuxKernelProtocolGuid
+
+[Guids]
+  gQemuKernelLoaderFsMediaGuid
-- 
2.17.1


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

* [PATCH v3 11/14] OvmfPkg: add new QEMU kernel image loader components
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (9 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 10/14] OvmfPkg: implement QEMU loader library for X86 with legacy fallback Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 13:46 ` [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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 53f503b3ed36..ec21d2f3f6cb 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -363,6 +363,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
@@ -716,6 +717,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 56e3ab3df25a..0e98a4dbd24a 100644
--- a/OvmfPkg/OvmfPkgIa32.fdf
+++ b/OvmfPkg/OvmfPkgIa32.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/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index d907465752a6..3c80a18c6086 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -367,6 +367,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
@@ -728,6 +729,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 add188723f3e..1dd431d72113 100644
--- a/OvmfPkg/OvmfPkgIa32X64.fdf
+++ b/OvmfPkg/OvmfPkgIa32X64.fdf
@@ -244,6 +244,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 0c6582a9ed37..63f1f935f4f3 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -367,6 +367,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
@@ -726,6 +727,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 add188723f3e..1dd431d72113 100644
--- a/OvmfPkg/OvmfPkgX64.fdf
+++ b/OvmfPkg/OvmfPkgX64.fdf
@@ -244,6 +244,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] 30+ messages in thread

* [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (10 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 11/14] OvmfPkg: add new QEMU kernel image loader components Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 21:15   ` [edk2-devel] " Laszlo Ersek
  2020-03-05 13:46 ` [PATCH v3 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 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 c479f113b92b..e470b9a6a3e5 100644
--- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
@@ -49,7 +49,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] 30+ messages in thread

* [PATCH v3 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (11 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-03-05 13:46 ` [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel
  2020-03-06  2:01 ` [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Bob Feng
  14 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
---
 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..869549f164f0 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,
+  OUT     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] 30+ messages in thread

* [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (12 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 13/14] OvmfPkg/QemuKernelLoaderFsDxe: add support for new Linux initrd device path Ard Biesheuvel
@ 2020-03-05 13:46 ` Ard Biesheuvel
  2020-06-09  9:51   ` [edk2-devel] " Laszlo Ersek
  2020-03-06  2:01 ` [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Bob Feng
  14 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 13:46 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 ec21d2f3f6cb..8916255df4df 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -363,7 +363,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 3c80a18c6086..342ff96cc279 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 63f1f935f4f3..1fb2de5e0121 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
   Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
   Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
-- 
2.17.1


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

* Re: [edk2-devel] [PATCH v3 09/14] OvmfPkg: create protocol and GUID header for loaded x86 Linux kernels
  2020-03-05 13:46 ` [PATCH v3 09/14] OvmfPkg: create protocol and GUID header for loaded x86 Linux kernels Ard Biesheuvel
@ 2020-03-05 16:01   ` Laszlo Ersek
  0 siblings, 0 replies; 30+ messages in thread
From: Laszlo Ersek @ 2020-03-05 16:01 UTC (permalink / raw)
  To: devel, ard.biesheuvel

On 03/05/20 14:46, 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 x86 Linux kernels
> in the protocol database.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h | 32 ++++++++++++
>  OvmfPkg/OvmfPkg.dec                                 | 53 ++++++++++----------
>  2 files changed, 59 insertions(+), 26 deletions(-)
> 
> diff --git a/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h b/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h
> new file mode 100644
> index 000000000000..01cfd9d189b4
> --- /dev/null
> +++ b/OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.h
> @@ -0,0 +1,32 @@
> +/** @file
> +  Protocol/GUID definition to describe a x86 Linux kernel image loaded
> +  into memory.
> +
> +  Note that this protocol is considered internal ABI, and may be change
> +  structure at any time without regard for backward compatibility.
> +
> +  Copyright (c) 2020, Arm, Ltd. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +**/
> +
> +#ifndef OVMF_LOADED_X86_LINUX_KERNEL_H__
> +#define OVMF_LOADED_X86_LINUX_KERNEL_H__
> +
> +#define OVMF_LOADED_X86_LINUX_KERNEL_PROTOCOL_GUID \
> +  {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
> +
> +typedef struct {
> +  VOID    *SetupBuf;
> +  VOID    *KernelBuf;
> +  CHAR8   *CommandLine;
> +  VOID    *InitrdData;
> +  UINTN   SetupSize;
> +  UINTN   KernelInitialSize;
> +  UINTN   InitrdSize;
> +  UINTN   CommandLineSize;
> +} OVMF_LOADED_X86_LINUX_KERNEL;
> +
> +extern EFI_GUID gOvmfLoadedX86LinuxKernelProtocolGuid;
> +
> +#endif
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 055caaa43041..913345d49e1f 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -80,38 +80,39 @@ [LibraryClasses]
>    XenPlatformLib|Include/Library/XenPlatformLib.h
>  
>  [Guids]
> -  gUefiOvmfPkgTokenSpaceGuid          = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
> -  gEfiXenInfoGuid                     = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
> -  gOvmfPkKek1AppPrefixGuid            = {0x4e32566d, 0x8e9e, 0x4f52, {0x81, 0xd3, 0x5b, 0xb9, 0x71, 0x5f, 0x97, 0x27}}
> -  gOvmfPlatformConfigGuid             = {0x7235c51c, 0x0c80, 0x4cab, {0x87, 0xac, 0x3b, 0x08, 0x4a, 0x63, 0x04, 0xb1}}
> -  gVirtioMmioTransportGuid            = {0x837dca9e, 0xe874, 0x4d82, {0xb2, 0x9a, 0x23, 0xfe, 0x0e, 0x23, 0xd1, 0xe2}}
> -  gQemuRamfbGuid                      = {0x557423a1, 0x63ab, 0x406c, {0xbe, 0x7e, 0x91, 0xcd, 0xbc, 0x08, 0xc4, 0x57}}
> -  gXenBusRootDeviceGuid               = {0xa732241f, 0x383d, 0x4d9c, {0x8a, 0xe1, 0x8e, 0x09, 0x83, 0x75, 0x89, 0xd7}}
> -  gRootBridgesConnectedEventGroupGuid = {0x24a2d66f, 0xeedd, 0x4086, {0x90, 0x42, 0xf2, 0x6e, 0x47, 0x97, 0xee, 0x69}}
> -  gMicrosoftVendorGuid                = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}}
> -  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}}
> +  gUefiOvmfPkgTokenSpaceGuid            = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
> +  gEfiXenInfoGuid                       = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
> +  gOvmfPkKek1AppPrefixGuid              = {0x4e32566d, 0x8e9e, 0x4f52, {0x81, 0xd3, 0x5b, 0xb9, 0x71, 0x5f, 0x97, 0x27}}
> +  gOvmfPlatformConfigGuid               = {0x7235c51c, 0x0c80, 0x4cab, {0x87, 0xac, 0x3b, 0x08, 0x4a, 0x63, 0x04, 0xb1}}
> +  gVirtioMmioTransportGuid              = {0x837dca9e, 0xe874, 0x4d82, {0xb2, 0x9a, 0x23, 0xfe, 0x0e, 0x23, 0xd1, 0xe2}}
> +  gQemuRamfbGuid                        = {0x557423a1, 0x63ab, 0x406c, {0xbe, 0x7e, 0x91, 0xcd, 0xbc, 0x08, 0xc4, 0x57}}
> +  gXenBusRootDeviceGuid                 = {0xa732241f, 0x383d, 0x4d9c, {0x8a, 0xe1, 0x8e, 0x09, 0x83, 0x75, 0x89, 0xd7}}
> +  gRootBridgesConnectedEventGroupGuid   = {0x24a2d66f, 0xeedd, 0x4086, {0x90, 0x42, 0xf2, 0x6e, 0x47, 0x97, 0xee, 0x69}}
> +  gMicrosoftVendorGuid                  = {0x77fa9abd, 0x0359, 0x4d32, {0xbd, 0x60, 0x28, 0xf4, 0xe7, 0x8f, 0x78, 0x4b}}
> +  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
>    # has been discovered and recorded
> -  gOvmfTpmDiscoveredPpiGuid           = {0xb9a61ad0, 0x2802, 0x41f3, {0xb5, 0x13, 0x96, 0x51, 0xce, 0x6b, 0xd5, 0x75}}
> +  gOvmfTpmDiscoveredPpiGuid             = {0xb9a61ad0, 0x2802, 0x41f3, {0xb5, 0x13, 0x96, 0x51, 0xce, 0x6b, 0xd5, 0x75}}
>  
>  [Protocols]
> -  gVirtioDeviceProtocolGuid           = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}}
> -  gXenBusProtocolGuid                 = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}}
> -  gXenIoProtocolGuid                  = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}}
> -  gIoMmuAbsentProtocolGuid            = {0xf8775d50, 0x8abd, 0x4adf, {0x92, 0xac, 0x85, 0x3e, 0x51, 0xf6, 0xc8, 0xdc}}
> -  gEfiLegacy8259ProtocolGuid          = {0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1}}
> -  gEfiFirmwareVolumeProtocolGuid      = {0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xcd, 0x81, 0x54, 0xbd, 0x27, 0xf8}}
> -  gEfiIsaAcpiProtocolGuid             = {0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55}}
> -  gEfiIsaIoProtocolGuid               = {0x7ee2bd44, 0x3da0, 0x11d4, {0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d}}
> -  gEfiLegacyBiosProtocolGuid          = {0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d}}
> -  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}}
> +  gVirtioDeviceProtocolGuid             = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}}
> +  gXenBusProtocolGuid                   = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}}
> +  gXenIoProtocolGuid                    = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}}
> +  gIoMmuAbsentProtocolGuid              = {0xf8775d50, 0x8abd, 0x4adf, {0x92, 0xac, 0x85, 0x3e, 0x51, 0xf6, 0xc8, 0xdc}}
> +  gEfiLegacy8259ProtocolGuid            = {0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1}}
> +  gEfiFirmwareVolumeProtocolGuid        = {0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xcd, 0x81, 0x54, 0xbd, 0x27, 0xf8}}
> +  gEfiIsaAcpiProtocolGuid               = {0x64a892dc, 0x5561, 0x4536, {0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55}}
> +  gEfiIsaIoProtocolGuid                 = {0x7ee2bd44, 0x3da0, 0x11d4, {0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d}}
> +  gEfiLegacyBiosProtocolGuid            = {0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d}}
> +  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}}
> +  gOvmfLoadedX86LinuxKernelProtocolGuid = {0xa3edc05d, 0xb618, 0x4ff6, {0x95, 0x52, 0x76, 0xd7, 0x88, 0x63, 0x43, 0xc8}}
>  
>  [PcdsFixedAtBuild]
>    gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|0x0|UINT32|0
> 

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


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

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

On 03/05/20 14:46, 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 the OVMF_LOADED_X86_LINUX_KERNEL 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
> a loaded image solely by a handle.
> 
> Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2566
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c   | 567 ++++++++++++++++++++
>  OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf |  42 ++
>  2 files changed, 609 insertions(+)

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

Thanks!
Laszlo

> diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
> new file mode 100644
> index 000000000000..e5979981ff8f
> --- /dev/null
> +++ b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.c
> @@ -0,0 +1,567 @@
> +/**  @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/OvmfLoadedX86LinuxKernel.h>
> +
> +#pragma pack (1)
> +typedef struct {
> +  EFI_DEVICE_PATH_PROTOCOL  FilePathHeader;
> +  CHAR16                    FilePath[ARRAY_SIZE (L"kernel")];
> +} KERNEL_FILE_DEVPATH;
> +
> +typedef struct {
> +  VENDOR_DEVICE_PATH        VenMediaNode;
> +  KERNEL_FILE_DEVPATH       FileNode;
> +  EFI_DEVICE_PATH_PROTOCOL  EndNode;
> +} KERNEL_VENMEDIA_FILE_DEVPATH;
> +#pragma pack ()
> +
> +STATIC CONST KERNEL_VENMEDIA_FILE_DEVPATH mKernelDevicePath = {
> +  {
> +    {
> +      MEDIA_DEVICE_PATH, MEDIA_VENDOR_DP,
> +      { sizeof (VENDOR_DEVICE_PATH) }
> +    },
> +    QEMU_KERNEL_LOADER_FS_MEDIA_GUID
> +  }, {
> +    {
> +      MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP,
> +      { sizeof (KERNEL_FILE_DEVPATH) }
> +    },
> +    L"kernel",
> +  }, {
> +    END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    { sizeof (EFI_DEVICE_PATH_PROTOCOL) }
> +  }
> +};
> +
> +STATIC
> +VOID
> +FreeLegacyImage (
> +  IN  OVMF_LOADED_X86_LINUX_KERNEL *LoadedImage
> +  )
> +{
> +  if (LoadedImage->SetupBuf != NULL) {
> +    FreePages (LoadedImage->SetupBuf,
> +      EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));
> +  }
> +  if (LoadedImage->KernelBuf != NULL) {
> +    FreePages (LoadedImage->KernelBuf,
> +      EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize));
> +  }
> +  if (LoadedImage->CommandLine != NULL) {
> +    FreePages (LoadedImage->CommandLine,
> +      EFI_SIZE_TO_PAGES (LoadedImage->CommandLineSize));
> +  }
> +  if (LoadedImage->InitrdData != NULL) {
> +    FreePages (LoadedImage->InitrdData,
> +      EFI_SIZE_TO_PAGES (LoadedImage->InitrdSize));
> +  }
> +}
> +
> +STATIC
> +EFI_STATUS
> +QemuLoadLegacyImage (
> +  OUT EFI_HANDLE                  *ImageHandle
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  UINTN                           KernelSize;
> +  UINTN                           SetupSize;
> +  OVMF_LOADED_X86_LINUX_KERNEL    *LoadedImage;
> +
> +  QemuFwCfgSelectItem (QemuFwCfgItemKernelSize);
> +  KernelSize = (UINTN)QemuFwCfgRead32 ();
> +
> +  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupSize);
> +  SetupSize = (UINTN)QemuFwCfgRead32 ();
> +
> +  if (KernelSize == 0 || SetupSize == 0) {
> +    DEBUG ((DEBUG_INFO, "qemu -kernel was not used.\n"));
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  LoadedImage = AllocateZeroPool (sizeof (*LoadedImage));
> +  if (LoadedImage == NULL) {
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  LoadedImage->SetupSize = SetupSize;
> +  LoadedImage->SetupBuf = LoadLinuxAllocateKernelSetupPages (
> +                            EFI_SIZE_TO_PAGES (LoadedImage->SetupSize));
> +  if (LoadedImage->SetupBuf == NULL) {
> +    DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel setup!\n"));
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto FreeImageDesc;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Setup size: 0x%x\n", (UINT32)LoadedImage->SetupSize));
> +  DEBUG ((DEBUG_INFO, "Reading kernel setup image ..."));
> +  QemuFwCfgSelectItem (QemuFwCfgItemKernelSetupData);
> +  QemuFwCfgReadBytes (LoadedImage->SetupSize, LoadedImage->SetupBuf);
> +  DEBUG ((DEBUG_INFO, " [done]\n"));
> +
> +  Status = LoadLinuxCheckKernelSetup (LoadedImage->SetupBuf,
> +             LoadedImage->SetupSize);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeImage;
> +  }
> +
> +  Status = LoadLinuxInitializeKernelSetup (LoadedImage->SetupBuf);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeImage;
> +  }
> +
> +  LoadedImage->KernelInitialSize = LoadLinuxGetKernelSize (
> +                                     LoadedImage->SetupBuf, KernelSize);
> +  if (LoadedImage->KernelInitialSize == 0) {
> +    Status = EFI_UNSUPPORTED;
> +    goto FreeImage;
> +  }
> +
> +  LoadedImage->KernelBuf = LoadLinuxAllocateKernelPages (
> +                             LoadedImage->SetupBuf,
> +                             EFI_SIZE_TO_PAGES (LoadedImage->KernelInitialSize)
> +                             );
> +  if (LoadedImage->KernelBuf == NULL) {
> +    DEBUG ((DEBUG_ERROR, "Unable to allocate memory for kernel!\n"));
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto FreeImage;
> +  }
> +
> +  DEBUG ((DEBUG_INFO, "Kernel size: 0x%x\n", (UINT32)KernelSize));
> +  DEBUG ((DEBUG_INFO, "Reading kernel image ..."));
> +  QemuFwCfgSelectItem (QemuFwCfgItemKernelData);
> +  QemuFwCfgReadBytes (KernelSize, LoadedImage->KernelBuf);
> +  DEBUG ((DEBUG_INFO, " [done]\n"));
> +
> +  QemuFwCfgSelectItem (QemuFwCfgItemCommandLineSize);
> +  LoadedImage->CommandLineSize = (UINTN)QemuFwCfgRead32 ();
> +
> +  if (LoadedImage->CommandLineSize > 0) {
> +    LoadedImage->CommandLine = LoadLinuxAllocateCommandLinePages (
> +                                 EFI_SIZE_TO_PAGES (
> +                                   LoadedImage->CommandLineSize));
> +    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,
> +                  &gOvmfLoadedX86LinuxKernelProtocolGuid, EFI_NATIVE_INTERFACE,
> +                  LoadedImage);
> +  if (EFI_ERROR (Status)) {
> +    goto FreeImage;
> +  }
> +  return EFI_SUCCESS;
> +
> +FreeImage:
> +  FreeLegacyImage (LoadedImage);
> +FreeImageDesc:
> +  FreePool (LoadedImage);
> +  return Status;
> +}
> +
> +STATIC
> +EFI_STATUS
> +QemuStartLegacyImage (
> +  IN  EFI_HANDLE                ImageHandle
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
> +
> +  Status = gBS->OpenProtocol (
> +                  ImageHandle,
> +                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
> +                  (VOID **)&LoadedImage,
> +                  gImageHandle,                  // AgentHandle
> +                  NULL,                          // ControllerHandle
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return LoadLinux (LoadedImage->KernelBuf, LoadedImage->SetupBuf);
> +}
> +
> +STATIC
> +EFI_STATUS
> +QemuUnloadLegacyImage (
> +  IN  EFI_HANDLE          ImageHandle
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
> +
> +  Status = gBS->OpenProtocol (
> +                  ImageHandle,
> +                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
> +                  (VOID **)&LoadedImage,
> +                  gImageHandle,                  // AgentHandle
> +                  NULL,                          // ControllerHandle
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  Status = gBS->UninstallProtocolInterface (ImageHandle,
> +                  &gOvmfLoadedX86LinuxKernelProtocolGuid, LoadedImage);
> +  ASSERT_EFI_ERROR (Status);
> +
> +  FreeLegacyImage (LoadedImage);
> +  FreePool (LoadedImage);
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Download the kernel, the initial ramdisk, and the kernel command line from
> +  QEMU's fw_cfg. The kernel will be instructed via its command line to load
> +  the initrd from the same Simple FileSystem where the kernel was loaded from.
> +
> +  @param[out] ImageHandle       The image handle that was allocated for
> +                                loading the image
> +
> +  @retval EFI_SUCCESS           The image was loaded successfully.
> +  @retval EFI_NOT_FOUND         Kernel image was not found.
> +  @retval EFI_OUT_OF_RESOURCES  Memory allocation failed.
> +  @retval EFI_PROTOCOL_ERROR    Unterminated kernel command line.
> +
> +  @return                       Error codes from any of the underlying
> +                                functions.
> +**/
> +EFI_STATUS
> +EFIAPI
> +QemuLoadKernelImage (
> +  OUT EFI_HANDLE            *ImageHandle
> +  )
> +{
> +  EFI_STATUS                Status;
> +  EFI_HANDLE                KernelImageHandle;
> +  EFI_LOADED_IMAGE_PROTOCOL *KernelLoadedImage;
> +  UINTN                     CommandLineSize;
> +  CHAR8                     *CommandLine;
> +  UINTN                     InitrdSize;
> +
> +  //
> +  // Load the image. This should call back into the QEMU EFI loader file system.
> +  //
> +  Status = gBS->LoadImage (
> +                  FALSE,                    // BootPolicy: exact match required
> +                  gImageHandle,             // ParentImageHandle
> +                  (EFI_DEVICE_PATH_PROTOCOL *)&mKernelDevicePath,
> +                  NULL,                     // SourceBuffer
> +                  0,                        // SourceSize
> +                  &KernelImageHandle
> +                  );
> +  switch (Status) {
> +  case EFI_SUCCESS:
> +    break;
> +
> +  case EFI_NOT_FOUND:
> +    //
> +    // The image does not exist - no -kernel image was supplied via the
> +    // command line so no point in invoking the legacy fallback
> +    //
> +    return EFI_NOT_FOUND;
> +
> +  case EFI_SECURITY_VIOLATION:
> +    //
> +    // 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);
> +    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
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  OVMF_LOADED_X86_LINUX_KERNEL  *LoadedImage;
> +  EFI_HANDLE                    KernelImageHandle;
> +
> +  Status = gBS->OpenProtocol (
> +                  *ImageHandle,
> +                  &gOvmfLoadedX86LinuxKernelProtocolGuid,
> +                  (VOID **)&LoadedImage,
> +                  gImageHandle,                  // AgentHandle
> +                  NULL,                          // ControllerHandle
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    return QemuStartLegacyImage (*ImageHandle);
> +  }
> +
> +  Status = gBS->StartImage (
> +                  *ImageHandle,
> +                  NULL,              // ExitDataSize
> +                  NULL               // ExitData
> +                  );
> +#ifdef MDE_CPU_IA32
> +  if (Status == EFI_UNSUPPORTED) {
> +    //
> +    // On IA32, EFI_UNSUPPORTED means that the image's machine type is X64 while
> +    // we are expecting a IA32 one, and the StartImage () boot service is unable
> +    // to handle it, either because the image does not have the special .compat
> +    // PE/COFF section that Linux specifies for mixed mode capable images, or
> +    // because we are running without the support code for that. So load the
> +    // image again, using the legacy loader, and unload the normally loaded
> +    // image before starting the legacy one.
> +    //
> +    Status = QemuLoadLegacyImage (&KernelImageHandle);
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Note: no change to (*ImageHandle), the caller will release it.
> +      //
> +      return Status;
> +    }
> +    //
> +    // Swap in the legacy-loaded image.
> +    //
> +    QemuUnloadKernelImage (*ImageHandle);
> +    *ImageHandle = KernelImageHandle;
> +    return QemuStartLegacyImage (KernelImageHandle);
> +  }
> +#endif
> +  return Status;
> +}
> +
> +/**
> +  Unloads an image loaded with QemuLoadKernelImage ().
> +
> +  @param  ImageHandle             Handle that identifies the image to be
> +                                  unloaded.
> +
> +  @retval EFI_SUCCESS             The image has been unloaded.
> +  @retval EFI_UNSUPPORTED         The image has been started, and does not
> +                                  support unload.
> +  @retval EFI_INVALID_PARAMETER   ImageHandle is not a valid image handle.
> +
> +  @return                         Exit code from the image's unload function.
> +**/
> +EFI_STATUS
> +EFIAPI
> +QemuUnloadKernelImage (
> +  IN  EFI_HANDLE          ImageHandle
> +  )
> +{
> +  EFI_LOADED_IMAGE_PROTOCOL   *KernelLoadedImage;
> +  EFI_STATUS                  Status;
> +
> +  Status = gBS->OpenProtocol (
> +                  ImageHandle,
> +                  &gEfiLoadedImageProtocolGuid,
> +                  (VOID **)&KernelLoadedImage,
> +                  gImageHandle,                  // AgentHandle
> +                  NULL,                          // ControllerHandle
> +                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
> +                  );
> +  if (Status == EFI_UNSUPPORTED) {
> +    //
> +    // The handle exists but does not have an instance of the standard loaded
> +    // image protocol installed on it. Attempt to unload it as a legacy image
> +    // instead.
> +    //
> +    return QemuUnloadLegacyImage (ImageHandle);
> +  }
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  //
> +  // We are unloading a normal, non-legacy loaded image, either on behalf of
> +  // an external caller, or called from QemuStartKernelImage() on IA32, while
> +  // switching from the normal to the legacy method to load and start a X64
> +  // image.
> +  //
> +  if (KernelLoadedImage->LoadOptions != NULL) {
> +    FreePool (KernelLoadedImage->LoadOptions);
> +    KernelLoadedImage->LoadOptions = NULL;
> +  }
> +  KernelLoadedImage->LoadOptionsSize = 0;
> +
> +  return gBS->UnloadImage (ImageHandle);
> +}
> diff --git a/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf b/OvmfPkg/Library/X86QemuLoadImageLib/X86QemuLoadImageLib.inf
> new file mode 100644
> index 000000000000..e1615badd2ba
> --- /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
> +  gOvmfLoadedX86LinuxKernelProtocolGuid
> +
> +[Guids]
> +  gQemuKernelLoaderFsMediaGuid
> 


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

* Re: [edk2-devel] [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-05 13:46 ` [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib Ard Biesheuvel
@ 2020-03-05 21:15   ` Laszlo Ersek
  2020-03-05 21:20     ` Ard Biesheuvel
  0 siblings, 1 reply; 30+ messages in thread
From: Laszlo Ersek @ 2020-03-05 21:15 UTC (permalink / raw)
  To: devel, ard.biesheuvel

Hi Ard,

On 03/05/20 14:46, 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>
> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> ---
>  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 c479f113b92b..e470b9a6a3e5 100644
> --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> @@ -49,7 +49,7 @@ [LibraryClasses]
>    NvVarsFileLib
>    QemuFwCfgLib
>    QemuFwCfgS3Lib
> -  LoadLinuxLib
> +  QemuLoadImageLib
>    QemuBootOrderLib
>    ReportStatusCodeLib
>    UefiLib

This hunk (in commit 859b55443a42) seems to break the OvmfXen platform build:

Active Platform          = OvmfPkg/OvmfXen.dsc

build.py...
OvmfPkg/OvmfXen.dsc(...): error 4000: Instance of library class [QemuLoadImageLib] is not found
        in [OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf] [X64]
        consumed by module [MdeModulePkg/Universal/BdsDxe/BdsDxe.inf]

Can you please send a patch?

I think resolving the lib class to the generic instance suffices. gBS->LoadImage() will return EFI_NOT_FOUND from QemuLoadKernelImage(), because OvmfPkg/QemuKernelLoaderFsDxe is not included in the Xen platform.

An alternative fix that's larger in source code, but lighter in binary code, would be to add a Null instance of QemuLoadImageLib, and use that in the Xen platform.

For the future, please include OvmfXen.dsc in your build / CI scripts.

Thanks!
Laszlo


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

* Re: [edk2-devel] [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-05 21:15   ` [edk2-devel] " Laszlo Ersek
@ 2020-03-05 21:20     ` Ard Biesheuvel
  2020-03-05 23:42       ` Laszlo Ersek
  0 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-05 21:20 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel-groups-io

On Thu, 5 Mar 2020 at 22:15, Laszlo Ersek <lersek@redhat.com> wrote:
>
> Hi Ard,
>
> On 03/05/20 14:46, 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>
> > Reviewed-by: Laszlo Ersek <lersek@redhat.com>
> > ---
> >  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 c479f113b92b..e470b9a6a3e5 100644
> > --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> > +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
> > @@ -49,7 +49,7 @@ [LibraryClasses]
> >    NvVarsFileLib
> >    QemuFwCfgLib
> >    QemuFwCfgS3Lib
> > -  LoadLinuxLib
> > +  QemuLoadImageLib
> >    QemuBootOrderLib
> >    ReportStatusCodeLib
> >    UefiLib
>
> This hunk (in commit 859b55443a42) seems to break the OvmfXen platform build:
>
> Active Platform          = OvmfPkg/OvmfXen.dsc
>
> build.py...
> OvmfPkg/OvmfXen.dsc(...): error 4000: Instance of library class [QemuLoadImageLib] is not found
>         in [OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf] [X64]
>         consumed by module [MdeModulePkg/Universal/BdsDxe/BdsDxe.inf]
>
> Can you please send a patch?
>
> I think resolving the lib class to the generic instance suffices. gBS->LoadImage() will return EFI_NOT_FOUND from QemuLoadKernelImage(), because OvmfPkg/QemuKernelLoaderFsDxe is not included in the Xen platform.
>
> An alternative fix that's larger in source code, but lighter in binary code, would be to add a Null instance of QemuLoadImageLib, and use that in the Xen platform.
>
> For the future, please include OvmfXen.dsc in your build / CI scripts.
>

Apologies - I will fix it right away. It never occurred to me that
'TryRunningQemuKernel ()' is live code on OvmfXen.

Being able to drop LoadLinuxLib from the Xen build is a win in itself,
so I will leave the Null library class for another day, if you don't
mind.

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

* Re: [edk2-devel] [PATCH v3 12/14] OvmfPkg/PlatformBootManagerLib: switch to QemuLoadImageLib
  2020-03-05 21:20     ` Ard Biesheuvel
@ 2020-03-05 23:42       ` Laszlo Ersek
  0 siblings, 0 replies; 30+ messages in thread
From: Laszlo Ersek @ 2020-03-05 23:42 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: edk2-devel-groups-io

On 03/05/20 22:20, Ard Biesheuvel wrote:
> On Thu, 5 Mar 2020 at 22:15, Laszlo Ersek <lersek@redhat.com> wrote:
>>
>> Hi Ard,
>>
>> On 03/05/20 14:46, 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>
>>> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
>>> ---
>>>  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 c479f113b92b..e470b9a6a3e5 100644
>>> --- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>>> +++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
>>> @@ -49,7 +49,7 @@ [LibraryClasses]
>>>    NvVarsFileLib
>>>    QemuFwCfgLib
>>>    QemuFwCfgS3Lib
>>> -  LoadLinuxLib
>>> +  QemuLoadImageLib
>>>    QemuBootOrderLib
>>>    ReportStatusCodeLib
>>>    UefiLib
>>
>> This hunk (in commit 859b55443a42) seems to break the OvmfXen platform build:
>>
>> Active Platform          = OvmfPkg/OvmfXen.dsc
>>
>> build.py...
>> OvmfPkg/OvmfXen.dsc(...): error 4000: Instance of library class [QemuLoadImageLib] is not found
>>         in [OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf] [X64]
>>         consumed by module [MdeModulePkg/Universal/BdsDxe/BdsDxe.inf]
>>
>> Can you please send a patch?
>>
>> I think resolving the lib class to the generic instance suffices. gBS->LoadImage() will return EFI_NOT_FOUND from QemuLoadKernelImage(), because OvmfPkg/QemuKernelLoaderFsDxe is not included in the Xen platform.
>>
>> An alternative fix that's larger in source code, but lighter in binary code, would be to add a Null instance of QemuLoadImageLib, and use that in the Xen platform.
>>
>> For the future, please include OvmfXen.dsc in your build / CI scripts.
>>
> 
> Apologies - I will fix it right away. It never occurred to me that
> 'TryRunningQemuKernel ()' is live code on OvmfXen.

Right. Such surprises are going to disappear after
<https://bugzilla.tianocore.org/show_bug.cgi?id=2122> is fixed,
hopefully around August 2020.

> Being able to drop LoadLinuxLib from the Xen build is a win in itself,

Good point, I didn't realize!

> so I will leave the Null library class for another day, if you don't
> mind.
> 

Sure, that's absolutely fine.

Thanks!
Laszlo


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

* Re: [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images
  2020-03-05 13:45 [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Ard Biesheuvel
                   ` (13 preceding siblings ...)
  2020-03-05 13:46 ` [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel
@ 2020-03-06  2:01 ` Bob Feng
  2020-03-06  7:42   ` Ard Biesheuvel
  14 siblings, 1 reply; 30+ messages in thread
From: Bob Feng @ 2020-03-06  2:01 UTC (permalink / raw)
  To: devel@edk2.groups.io, ard.biesheuvel@linaro.org; +Cc: lersek@redhat.com

Hi Ard,

I found this patch set cause Ovmf platform build failure on windows with VS2017. 

The error message is as following:

Generating code
d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.c(130): error C2220: warning treated as error - no 'object' file generated
d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.c(130): warning C4132: 'mEfiFileProtocolTemplate': const object should be initialized
TcpTimer.c
Finished generating code
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86\cl.exe"' : return code '0x2'
Stop.


build.py...
 : error 7000: Failed to execute command
        C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86\nmake.exe /nologo tbuild [d:\edk2\Build\OvmfIa32\DEBUG_VS2017\IA32\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe]


build.py...
 : error F002: Failed to build module
        d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.inf [IA32, VS2017, DEBUG]


Please help to provide patch to fix it.

Thanks,
Bob


-----Original Message-----
From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Ard Biesheuvel
Sent: Thursday, March 5, 2020 9:46 PM
To: devel@edk2.groups.io
Cc: lersek@redhat.com; Ard Biesheuvel <ard.biesheuvel@linaro.org>
Subject: [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images

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 (now #13 adds the new Linux specific initrd loadfile2 protocol that aims to simplify initrd loading from Linux when booting via the PE stub.

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

Changes since [v2]:
- rename gX86QemuKernelLoadedImageGuid to gOvmfLoadedX86LinuxKernelProtocolGuid,
  and define the associated struct type OVMF_LOADED_X86_LINUX_KERNEL in the
  protocol header file
- mention that the new protocol is internal ABI and subject to backward
  incompatible change at any time
- align legacy loader logic more closely with the generic one
- modify legacy mixed mode handling to prevent returning a stale handle
- add Laszlo's ack to #4, #6, #8, #12 and #13
- fix up some style issues and out of date/inaccurate comments (Laszlo)

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 (*)

(*) v2+ numbering

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
https://github.com/ardbiesheuvel/edk2/tree/ovmf-loadimage-startimage-v3

[v1] http://mid.mail-archive.com/20200302072936.29221-1-ard.biesheuvel@linaro.org
[v2] http://mid.mail-archive.com/20200304095233.21046-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 loaded x86 Linux kernels
  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/OvmfLoadedX86LinuxKernel.h       |   32 +
 .../GenericQemuLoadImageLib.c                 |  276 +++++
 .../GenericQemuLoadImageLib.inf               |   38 +
 .../PlatformBootManagerLib.inf                |    2 +-
 .../PlatformBootManagerLib/QemuKernel.c       |  144 +--
 .../X86QemuLoadImageLib/X86QemuLoadImageLib.c |  567 +++++++++
 .../X86QemuLoadImageLib.inf                   |   42 +
 OvmfPkg/OvmfPkg.dec                           |   57 +-
 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, 1354 insertions(+), 1419 deletions(-)  create mode 100644 OvmfPkg/Include/Guid/QemuKernelLoaderFsMedia.h
 create mode 100644 OvmfPkg/Include/Library/QemuLoadImageLib.h
 create mode 100644 OvmfPkg/Include/Protocol/OvmfLoadedX86LinuxKernel.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] 30+ messages in thread

* Re: [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images
  2020-03-06  2:01 ` [edk2-devel] [PATCH v3 00/14] Ovmf: use LoadImage/StartImage for loading command line images Bob Feng
@ 2020-03-06  7:42   ` Ard Biesheuvel
  0 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-03-06  7:42 UTC (permalink / raw)
  To: Feng, Bob C, lersek@redhat.com; +Cc: devel@edk2.groups.io

On Fri, 6 Mar 2020 at 03:01, Feng, Bob C <bob.c.feng@intel.com> wrote:
>
> Hi Ard,
>
> I found this patch set cause Ovmf platform build failure on windows with VS2017.
>
> The error message is as following:
>
> Generating code
> d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.c(130): error C2220: warning treated as error - no 'object' file generated
> d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.c(130): warning C4132: 'mEfiFileProtocolTemplate': const object should be initialized
> TcpTimer.c
> Finished generating code
> NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86\cl.exe"' : return code '0x2'
> Stop.
>
>
> build.py...
>  : error 7000: Failed to execute command
>         C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\bin\Hostx86\x86\nmake.exe /nologo tbuild [d:\edk2\Build\OvmfIa32\DEBUG_VS2017\IA32\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe]
>
>
> build.py...
>  : error F002: Failed to build module
>         d:\edk2\OvmfPkg\QemuKernelLoaderFsDxe\QemuKernelLoaderFsDxe.inf [IA32, VS2017, DEBUG]
>
>
> Please help to provide patch to fix it.
>

Interesting. That code was moved from an ARM only source file to one
that is shared between all architectures.

GCC and Clang have no problem with that, and I think a tentative
definitive of a const object is permitted by the spec.

Anyway, I sent a patch to fix it. Please confirm whether it works for you.

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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-03-05 13:46 ` [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds Ard Biesheuvel
@ 2020-06-09  9:51   ` Laszlo Ersek
  2020-06-09 10:45     ` Ard Biesheuvel
  0 siblings, 1 reply; 30+ messages in thread
From: Laszlo Ersek @ 2020-06-09  9:51 UTC (permalink / raw)
  To: ard.biesheuvel; +Cc: devel, Philippe Mathieu-Daudé

Hi Ard,

On 03/05/20 14:46, Ard Biesheuvel wrote:
> 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 ec21d2f3f6cb..8916255df4df 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -363,7 +363,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 $(TPM_ENABLE) == TRUE
>    Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>    Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 3c80a18c6086..342ff96cc279 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>    Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>    Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index 63f1f935f4f3..1fb2de5e0121 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>    Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>    Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
> 

this patch (commit ced77332cab6) breaks the following use case (on X64):

(1) we're defining (installing) a new libvirt domain with

  virt-install --location NETWORK-URL

where NETWORK-URL identifies a remote (e.g. https) "exploded" Linux
distro tree,

(2) in the variable store template file, from which the new domain will
have its variable store instantiated, the Microsoft certs had been
enrolled (by running EnrollDefaultKeys),

(3) the guest kernel ("vmlinuz") downloaded in step (1) is only signed
by the distro vendor, not by Microsoft.

When installing a distro with "virt-install" from a UEFI-bootable ISO
image (exposed to the guest e.g. via virtio-scsi), that is, not from a
remote "exploded" OS tree like above, then "shim" is booted first. Shim
is accepted by an MS certificate. Then shim/grub boot the guest kernel,
and thanks to shim, the vendor signature on that kernel is accepted.
This is why "shim" exists.

However, when installing the guest with "virt-install --location
NETWORK-URL", then virt-install first downloads the broken-out vmlinuz
and initrd files from the remote (e.g. https) OS tree, to local
temporary files, and launches the guest (for installation) with a direct
(fw_cfg) kernel boot. Because "vmlinuz" is only signed by the OS vendor,
and "shim" is not used at all, and the varstore only has the MS certs,
the guest (installer) now fails to boot.

This used to work before, and there's an argument to be made that it
wasn't insecure. Because -- as I understand it anyway --, the usage is
not unlike "audit mode / deployed mode":

- When you boot the guest for the very first time, you make the guest
firmware blindly trust the guest kernel, in effect -- because, you are
providing the kernel from a source whose trustworthiness is guaranteed
by other means (for example, you pass such an https NETWORK-URL to
virt-install on the host side that you trust).

- Once the guest is installed, and either rebooted from within, or shut
down altogether and relaunched, then the fw-cfg "bypass" won't happen
again. It's also not needed any more, because with the installation
completed, "shim" has also become part of the boot process (from the
virtual disk).

Do you have any ideas to make this scenario work again? Or else, can we
predicate this patch for the DSC files on a build flag that's different
from SECURE_BOOT_ENABLE?

(Put more formally: right now, the EFI_SECURITY_VIOLATION branch, and
the EFI_ACCESS_DENIED branch that I posted for TianoCore#2785 earlier,
in X86QemuLoadImageLib, are dead code. Because, those conditions are
only possible when SECURE_BOOT_ENABLE is defined -- but in that case, we
(currently) don't use X86QemuLoadImageLib at all.)

I do see that the *exact* virt-install scenario above has never worked
in ArmVirtQemu / AARCH64. (Given that ArmVirtQemu has always used
gBS->LoadImage() for fw_cfg kernel boot.) However, to us (RH) anyway,
that difference between AARCH64 and X64 isn't a practical one. That's
because we have never set SECURE_BOOT_ENABLE for ArmVirtQemu in the
first place, due to not having an SMM-like pflash protection on AARCH64.

... Unfortunately, when I reviewed this patch, I failed to recall that
"virt-install --location NETWORK-URL" relied on fw_cfg kernel boot. And
I failed to realize that, by extension, virt-install relied on fw_cfg
kernel boot bypassing Secure Boot. :(

Thanks,
Laszlo


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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-09  9:51   ` [edk2-devel] " Laszlo Ersek
@ 2020-06-09 10:45     ` Ard Biesheuvel
  2020-06-10  9:22       ` Laszlo Ersek
  0 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-06-09 10:45 UTC (permalink / raw)
  To: devel, lersek; +Cc: Philippe Mathieu-Daudé

On 6/9/20 11:51 AM, Laszlo Ersek via groups.io wrote:
> Hi Ard,
> 
> On 03/05/20 14:46, Ard Biesheuvel wrote:
>> 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 ec21d2f3f6cb..8916255df4df 100644
>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>> @@ -363,7 +363,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 $(TPM_ENABLE) == TRUE
>>     Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>     Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>> index 3c80a18c6086..342ff96cc279 100644
>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>     Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>     Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>> index 63f1f935f4f3..1fb2de5e0121 100644
>> --- a/OvmfPkg/OvmfPkgX64.dsc
>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>     Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>     Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>
> 
> this patch (commit ced77332cab6) breaks the following use case (on X64):
> 
> (1) we're defining (installing) a new libvirt domain with
> 
>    virt-install --location NETWORK-URL
> 
> where NETWORK-URL identifies a remote (e.g. https) "exploded" Linux
> distro tree,
> 
> (2) in the variable store template file, from which the new domain will
> have its variable store instantiated, the Microsoft certs had been
> enrolled (by running EnrollDefaultKeys),
> 
> (3) the guest kernel ("vmlinuz") downloaded in step (1) is only signed
> by the distro vendor, not by Microsoft.
> 
> When installing a distro with "virt-install" from a UEFI-bootable ISO
> image (exposed to the guest e.g. via virtio-scsi), that is, not from a
> remote "exploded" OS tree like above, then "shim" is booted first. Shim
> is accepted by an MS certificate. Then shim/grub boot the guest kernel,
> and thanks to shim, the vendor signature on that kernel is accepted.
> This is why "shim" exists.
> 
> However, when installing the guest with "virt-install --location
> NETWORK-URL", then virt-install first downloads the broken-out vmlinuz
> and initrd files from the remote (e.g. https) OS tree, to local
> temporary files, and launches the guest (for installation) with a direct
> (fw_cfg) kernel boot. Because "vmlinuz" is only signed by the OS vendor,
> and "shim" is not used at all, and the varstore only has the MS certs,
> the guest (installer) now fails to boot.
> 
> This used to work before, and there's an argument to be made that it
> wasn't insecure. Because -- as I understand it anyway --, the usage is
> not unlike "audit mode / deployed mode":
> 
> - When you boot the guest for the very first time, you make the guest
> firmware blindly trust the guest kernel, in effect -- because, you are
> providing the kernel from a source whose trustworthiness is guaranteed
> by other means (for example, you pass such an https NETWORK-URL to
> virt-install on the host side that you trust).
> 
> - Once the guest is installed, and either rebooted from within, or shut
> down altogether and relaunched, then the fw-cfg "bypass" won't happen
> again. It's also not needed any more, because with the installation
> completed, "shim" has also become part of the boot process (from the
> virtual disk).
> 
> Do you have any ideas to make this scenario work again? Or else, can we
> predicate this patch for the DSC files on a build flag that's different
> from SECURE_BOOT_ENABLE?
> 
> (Put more formally: right now, the EFI_SECURITY_VIOLATION branch, and
> the EFI_ACCESS_DENIED branch that I posted for TianoCore#2785 earlier,
> in X86QemuLoadImageLib, are dead code. Because, those conditions are
> only possible when SECURE_BOOT_ENABLE is defined -- but in that case, we
> (currently) don't use X86QemuLoadImageLib at all.)
> 

Hmm, I did wonder about that and then forgot again ...

> I do see that the *exact* virt-install scenario above has never worked
> in ArmVirtQemu / AARCH64. (Given that ArmVirtQemu has always used
> gBS->LoadImage() for fw_cfg kernel boot.) However, to us (RH) anyway,
> that difference between AARCH64 and X64 isn't a practical one. That's
> because we have never set SECURE_BOOT_ENABLE for ArmVirtQemu in the
> first place, due to not having an SMM-like pflash protection on AARCH64.
> 
> ... Unfortunately, when I reviewed this patch, I failed to recall that
> "virt-install --location NETWORK-URL" relied on fw_cfg kernel boot. And
> I failed to realize that, by extension, virt-install relied on fw_cfg
> kernel boot bypassing Secure Boot. :(
> 

I would argue that the cleanest way to deal with this is to introduce 
something like

gEfiSecurityPkgTokenSpaceGuid.PcdHttpsLoadedImageVerificationPolicy

so that you can mark HTTPS loaded images as trusted. In my opinion, a 
HTTPS loaded image is sufficiently different from the other classes of 
images that it warrants a separate policy.

But I suppose this could be a difficult sell, and it will take more time 
than you are willing to spend on it?

So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if 
you cannot start the image anyway? Because I would prefer it if we could 
start the image anyway, Unfortunately, the only way seems to be to use 
the loaded image protocol data (base and size in memory) and do another 
LoadImage() after adding the hash to "db", and this is also more 
elaborate than I would like.

Of course, the *correct* fix is to add the vendor cert to db - you are 
loading a signed image from a known source, and this whole dance with 
shim and the MS certs is ridiculous, and I am still hoping we can avoid 
this mess on ARM









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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-09 10:45     ` Ard Biesheuvel
@ 2020-06-10  9:22       ` Laszlo Ersek
  2020-06-10  9:32         ` Ard Biesheuvel
  0 siblings, 1 reply; 30+ messages in thread
From: Laszlo Ersek @ 2020-06-10  9:22 UTC (permalink / raw)
  To: devel, ard.biesheuvel; +Cc: Philippe Mathieu-Daudé

On 06/09/20 12:45, Ard Biesheuvel wrote:
> On 6/9/20 11:51 AM, Laszlo Ersek via groups.io wrote:
>> Hi Ard,
>>
>> On 03/05/20 14:46, Ard Biesheuvel wrote:
>>> 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 ec21d2f3f6cb..8916255df4df 100644
>>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>>> @@ -363,7 +363,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 $(TPM_ENABLE) == TRUE
>>>    
>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>
>>>    
>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>
>>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>>> index 3c80a18c6086..342ff96cc279 100644
>>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>>    
>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>
>>>    
>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>
>>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>>> index 63f1f935f4f3..1fb2de5e0121 100644
>>> --- a/OvmfPkg/OvmfPkgX64.dsc
>>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>>    
>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>
>>>    
>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>
>>>
>>
>> this patch (commit ced77332cab6) breaks the following use case (on X64):
>>
>> (1) we're defining (installing) a new libvirt domain with
>>
>>    virt-install --location NETWORK-URL
>>
>> where NETWORK-URL identifies a remote (e.g. https) "exploded" Linux
>> distro tree,
>>
>> (2) in the variable store template file, from which the new domain will
>> have its variable store instantiated, the Microsoft certs had been
>> enrolled (by running EnrollDefaultKeys),
>>
>> (3) the guest kernel ("vmlinuz") downloaded in step (1) is only signed
>> by the distro vendor, not by Microsoft.
>>
>> When installing a distro with "virt-install" from a UEFI-bootable ISO
>> image (exposed to the guest e.g. via virtio-scsi), that is, not from a
>> remote "exploded" OS tree like above, then "shim" is booted first. Shim
>> is accepted by an MS certificate. Then shim/grub boot the guest kernel,
>> and thanks to shim, the vendor signature on that kernel is accepted.
>> This is why "shim" exists.
>>
>> However, when installing the guest with "virt-install --location
>> NETWORK-URL", then virt-install first downloads the broken-out vmlinuz
>> and initrd files from the remote (e.g. https) OS tree, to local
>> temporary files, and launches the guest (for installation) with a direct
>> (fw_cfg) kernel boot. Because "vmlinuz" is only signed by the OS vendor,
>> and "shim" is not used at all, and the varstore only has the MS certs,
>> the guest (installer) now fails to boot.
>>
>> This used to work before, and there's an argument to be made that it
>> wasn't insecure. Because -- as I understand it anyway --, the usage is
>> not unlike "audit mode / deployed mode":
>>
>> - When you boot the guest for the very first time, you make the guest
>> firmware blindly trust the guest kernel, in effect -- because, you are
>> providing the kernel from a source whose trustworthiness is guaranteed
>> by other means (for example, you pass such an https NETWORK-URL to
>> virt-install on the host side that you trust).
>>
>> - Once the guest is installed, and either rebooted from within, or shut
>> down altogether and relaunched, then the fw-cfg "bypass" won't happen
>> again. It's also not needed any more, because with the installation
>> completed, "shim" has also become part of the boot process (from the
>> virtual disk).
>>
>> Do you have any ideas to make this scenario work again? Or else, can we
>> predicate this patch for the DSC files on a build flag that's different
>> from SECURE_BOOT_ENABLE?
>>
>> (Put more formally: right now, the EFI_SECURITY_VIOLATION branch, and
>> the EFI_ACCESS_DENIED branch that I posted for TianoCore#2785 earlier,
>> in X86QemuLoadImageLib, are dead code. Because, those conditions are
>> only possible when SECURE_BOOT_ENABLE is defined -- but in that case, we
>> (currently) don't use X86QemuLoadImageLib at all.)
>>
> 
> Hmm, I did wonder about that and then forgot again ...
> 
>> I do see that the *exact* virt-install scenario above has never worked
>> in ArmVirtQemu / AARCH64. (Given that ArmVirtQemu has always used
>> gBS->LoadImage() for fw_cfg kernel boot.) However, to us (RH) anyway,
>> that difference between AARCH64 and X64 isn't a practical one. That's
>> because we have never set SECURE_BOOT_ENABLE for ArmVirtQemu in the
>> first place, due to not having an SMM-like pflash protection on AARCH64.
>>
>> ... Unfortunately, when I reviewed this patch, I failed to recall that
>> "virt-install --location NETWORK-URL" relied on fw_cfg kernel boot. And
>> I failed to realize that, by extension, virt-install relied on fw_cfg
>> kernel boot bypassing Secure Boot. :(
>>
> 
> I would argue that the cleanest way to deal with this is to introduce
> something like
> 
> gEfiSecurityPkgTokenSpaceGuid.PcdHttpsLoadedImageVerificationPolicy
> 
> so that you can mark HTTPS loaded images as trusted. In my opinion, a
> HTTPS loaded image is sufficiently different from the other classes of
> images that it warrants a separate policy.
> 
> But I suppose this could be a difficult sell, and it will take more time
> than you are willing to spend on it?

Primarily, I wouldn't suggest including "https" in the name of the PCD,
as "https" is just an example above. If NETWORK-URL is in the "http"
(not "https"), or even "ftp" scheme, but is served from localhost (for
example), it could be considered secure.

More generally, the guest firmware need not know where the kernel/initrd
over fw_cfg originate from, only that they should be trusted.

The PCD idea looks nice to me; I'd just make it an OvmfPkg PCD. Options:

(1) make it a FeaturePCD, and introduce a new build flag (-D) for
controlling it

(2) make it a FeaturePCD, and do not introduce a new flag (-D), instead,
let users rely on the already available "--pcd" option of "build" to
control it

(3) make it a dynamic boolean PCD, and use the recently introduced
fw_cfg control interface


In all three options, the OVMF DSC files would unconditionally use the
X86QemuLoadImageLib instance, we'd just predicate the fallback to the
legacy Linux/x86 boot protocol on:

  SecureBoot disabled || FallbackPcd

(where "SecureBoot disabled" means that the SecureBoot standard UEFI
variable doesn't exist, or has zero value).

I think option (2) means the least churn, and it would be "good enough"
functionally.

Does this look palatable to you?


> So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if
> you cannot start the image anyway?

Honestly: I'm not sure!

> Because I would prefer it if we could
> start the image anyway, Unfortunately, the only way seems to be

Right; it seems like the EFI_SECURITY_VIOLATION status would get saved
in the private LoadImageStatus field, and that would cause StartImage()
to fail early as well. I couldn't find a spot to "re-set" LoadImageStatus.

> to use
> the loaded image protocol data (base and size in memory) and do another
> LoadImage() after adding the hash to "db", and this is also more
> elaborate than I would like.

Agreed. We shouldn't mess with "db".

> Of course, the *correct* fix is to add the vendor cert to db - you are
> loading a signed image from a known source, and this whole dance with
> shim and the MS certs is ridiculous, and I am still hoping we can avoid
> this mess on ARM

I considered this. It didn't look feasible to me at first sight (how
many vendors?), but now that you mention it and I've looked at it more
closely, it does look feasible. Selfishly (!), if I look at the guest OS
types officially supported on RHEL8 hosts:

- https://access.redhat.com/articles/973133
- https://access.redhat.com/articles/973163

then all we (RH) would need are two patches for (upstream)
OvmfPkg/EnrollDefaultKeys. Namely, we should enroll two more DB entries:

- SUSE's CA certificate to which the key(s) chain that they use for
signing their kernels

- Red Hat's CA certificate to which the key(s) chain that we use for
signing our kernels.

That would strictly be an improvement even for upstream OVMF (more
vendors accepted).

Ultimately I think the right way is to pick option (3) -- dynamic PCD --
*and* add the SUSE and RH CA certs to OvmfPkg/EnrollDefaultKeys. That
means SUSE and RH signed kernels can be booted at once, with secure
verification, and users would still have a QEMU command line option for
opting *into* the legacy boot protocol fallback.

Do you agree? Would you be OK with patches to this effect?

(I think I'd post the RH CA cert patch after some internal discussions,
and CC Gary so that he could follow suit with their own CA cert.)

Thanks!
Laszlo


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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-10  9:22       ` Laszlo Ersek
@ 2020-06-10  9:32         ` Ard Biesheuvel
  2020-06-11 14:55           ` Laszlo Ersek
  0 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-06-10  9:32 UTC (permalink / raw)
  To: Laszlo Ersek, devel; +Cc: Philippe Mathieu-Daudé

On 6/10/20 11:22 AM, Laszlo Ersek wrote:
> On 06/09/20 12:45, Ard Biesheuvel wrote:
>> On 6/9/20 11:51 AM, Laszlo Ersek via groups.io wrote:
>>> Hi Ard,
>>>
>>> On 03/05/20 14:46, Ard Biesheuvel wrote:
>>>> 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 ec21d2f3f6cb..8916255df4df 100644
>>>> --- a/OvmfPkg/OvmfPkgIa32.dsc
>>>> +++ b/OvmfPkg/OvmfPkgIa32.dsc
>>>> @@ -363,7 +363,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 $(TPM_ENABLE) == TRUE
>>>>   Â
>>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>>
>>>>   Â
>>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>>
>>>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
>>>> index 3c80a18c6086..342ff96cc279 100644
>>>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
>>>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
>>>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>>>   Â
>>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>>
>>>>   Â
>>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>>
>>>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
>>>> index 63f1f935f4f3..1fb2de5e0121 100644
>>>> --- a/OvmfPkg/OvmfPkgX64.dsc
>>>> +++ b/OvmfPkg/OvmfPkgX64.dsc
>>>> @@ -367,7 +367,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 $(TPM_ENABLE) == TRUE
>>>>   Â
>>>> Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
>>>>
>>>>   Â
>>>> Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
>>>>
>>>>
>>>
>>> this patch (commit ced77332cab6) breaks the following use case (on X64):
>>>
>>> (1) we're defining (installing) a new libvirt domain with
>>>
>>>    virt-install --location NETWORK-URL
>>>
>>> where NETWORK-URL identifies a remote (e.g. https) "exploded" Linux
>>> distro tree,
>>>
>>> (2) in the variable store template file, from which the new domain will
>>> have its variable store instantiated, the Microsoft certs had been
>>> enrolled (by running EnrollDefaultKeys),
>>>
>>> (3) the guest kernel ("vmlinuz") downloaded in step (1) is only signed
>>> by the distro vendor, not by Microsoft.
>>>
>>> When installing a distro with "virt-install" from a UEFI-bootable ISO
>>> image (exposed to the guest e.g. via virtio-scsi), that is, not from a
>>> remote "exploded" OS tree like above, then "shim" is booted first. Shim
>>> is accepted by an MS certificate. Then shim/grub boot the guest kernel,
>>> and thanks to shim, the vendor signature on that kernel is accepted.
>>> This is why "shim" exists.
>>>
>>> However, when installing the guest with "virt-install --location
>>> NETWORK-URL", then virt-install first downloads the broken-out vmlinuz
>>> and initrd files from the remote (e.g. https) OS tree, to local
>>> temporary files, and launches the guest (for installation) with a direct
>>> (fw_cfg) kernel boot. Because "vmlinuz" is only signed by the OS vendor,
>>> and "shim" is not used at all, and the varstore only has the MS certs,
>>> the guest (installer) now fails to boot.
>>>
>>> This used to work before, and there's an argument to be made that it
>>> wasn't insecure. Because -- as I understand it anyway --, the usage is
>>> not unlike "audit mode / deployed mode":
>>>
>>> - When you boot the guest for the very first time, you make the guest
>>> firmware blindly trust the guest kernel, in effect -- because, you are
>>> providing the kernel from a source whose trustworthiness is guaranteed
>>> by other means (for example, you pass such an https NETWORK-URL to
>>> virt-install on the host side that you trust).
>>>
>>> - Once the guest is installed, and either rebooted from within, or shut
>>> down altogether and relaunched, then the fw-cfg "bypass" won't happen
>>> again. It's also not needed any more, because with the installation
>>> completed, "shim" has also become part of the boot process (from the
>>> virtual disk).
>>>
>>> Do you have any ideas to make this scenario work again? Or else, can we
>>> predicate this patch for the DSC files on a build flag that's different
>>> from SECURE_BOOT_ENABLE?
>>>
>>> (Put more formally: right now, the EFI_SECURITY_VIOLATION branch, and
>>> the EFI_ACCESS_DENIED branch that I posted for TianoCore#2785 earlier,
>>> in X86QemuLoadImageLib, are dead code. Because, those conditions are
>>> only possible when SECURE_BOOT_ENABLE is defined -- but in that case, we
>>> (currently) don't use X86QemuLoadImageLib at all.)
>>>
>>
>> Hmm, I did wonder about that and then forgot again ...
>>
>>> I do see that the *exact* virt-install scenario above has never worked
>>> in ArmVirtQemu / AARCH64. (Given that ArmVirtQemu has always used
>>> gBS->LoadImage() for fw_cfg kernel boot.) However, to us (RH) anyway,
>>> that difference between AARCH64 and X64 isn't a practical one. That's
>>> because we have never set SECURE_BOOT_ENABLE for ArmVirtQemu in the
>>> first place, due to not having an SMM-like pflash protection on AARCH64.
>>>
>>> ... Unfortunately, when I reviewed this patch, I failed to recall that
>>> "virt-install --location NETWORK-URL" relied on fw_cfg kernel boot. And
>>> I failed to realize that, by extension, virt-install relied on fw_cfg
>>> kernel boot bypassing Secure Boot. :(
>>>
>>
>> I would argue that the cleanest way to deal with this is to introduce
>> something like
>>
>> gEfiSecurityPkgTokenSpaceGuid.PcdHttpsLoadedImageVerificationPolicy
>>
>> so that you can mark HTTPS loaded images as trusted. In my opinion, a
>> HTTPS loaded image is sufficiently different from the other classes of
>> images that it warrants a separate policy.
>>
>> But I suppose this could be a difficult sell, and it will take more time
>> than you are willing to spend on it?
> 
> Primarily, I wouldn't suggest including "https" in the name of the PCD,
> as "https" is just an example above. If NETWORK-URL is in the "http"
> (not "https"), or even "ftp" scheme, but is served from localhost (for
> example), it could be considered secure.
> 
> More generally, the guest firmware need not know where the kernel/initrd
> over fw_cfg originate from, only that they should be trusted.
> 
> The PCD idea looks nice to me; I'd just make it an OvmfPkg PCD. Options:
> 
> (1) make it a FeaturePCD, and introduce a new build flag (-D) for
> controlling it
> 
> (2) make it a FeaturePCD, and do not introduce a new flag (-D), instead,
> let users rely on the already available "--pcd" option of "build" to
> control it
> 
> (3) make it a dynamic boolean PCD, and use the recently introduced
> fw_cfg control interface
> 
> 
> In all three options, the OVMF DSC files would unconditionally use the
> X86QemuLoadImageLib instance, we'd just predicate the fallback to the
> legacy Linux/x86 boot protocol on:
> 
>    SecureBoot disabled || FallbackPcd
> 
> (where "SecureBoot disabled" means that the SecureBoot standard UEFI
> variable doesn't exist, or has zero value).
> 
> I think option (2) means the least churn, and it would be "good enough"
> functionally.
> 
> Does this look palatable to you?
> 
> 
>> So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if
>> you cannot start the image anyway?
> 
> Honestly: I'm not sure!
> 
>> Because I would prefer it if we could
>> start the image anyway, Unfortunately, the only way seems to be
> 
> Right; it seems like the EFI_SECURITY_VIOLATION status would get saved
> in the private LoadImageStatus field, and that would cause StartImage()
> to fail early as well. I couldn't find a spot to "re-set" LoadImageStatus.
> 
>> to use
>> the loaded image protocol data (base and size in memory) and do another
>> LoadImage() after adding the hash to "db", and this is also more
>> elaborate than I would like.
> 
> Agreed. We shouldn't mess with "db".
> 
>> Of course, the *correct* fix is to add the vendor cert to db - you are
>> loading a signed image from a known source, and this whole dance with
>> shim and the MS certs is ridiculous, and I am still hoping we can avoid
>> this mess on ARM
> 
> I considered this. It didn't look feasible to me at first sight (how
> many vendors?), but now that you mention it and I've looked at it more
> closely, it does look feasible. Selfishly (!), if I look at the guest OS
> types officially supported on RHEL8 hosts:
> 
> - https://access.redhat.com/articles/973133
> - https://access.redhat.com/articles/973163
> 
> then all we (RH) would need are two patches for (upstream)
> OvmfPkg/EnrollDefaultKeys. Namely, we should enroll two more DB entries:
> 
> - SUSE's CA certificate to which the key(s) chain that they use for
> signing their kernels
> 
> - Red Hat's CA certificate to which the key(s) chain that we use for
> signing our kernels.
> 
> That would strictly be an improvement even for upstream OVMF (more
> vendors accepted).
> 
> Ultimately I think the right way is to pick option (3) -- dynamic PCD --
> *and* add the SUSE and RH CA certs to OvmfPkg/EnrollDefaultKeys. That
> means SUSE and RH signed kernels can be booted at once, with secure
> verification, and users would still have a QEMU command line option for
> opting *into* the legacy boot protocol fallback.
> 
> Do you agree? Would you be OK with patches to this effect?
> 

Yes, option #3 looks reasonable to me. And adding the certs is the right 
thing to do regardless - going around installing the MS certs everywhere 
is a recipe for disaster, and AIUI, MS now requires you to remove them 
in some cases?? (for DeviceGuard support or sth like that)



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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-10  9:32         ` Ard Biesheuvel
@ 2020-06-11 14:55           ` Laszlo Ersek
  2020-06-11 15:05             ` Ard Biesheuvel
  0 siblings, 1 reply; 30+ messages in thread
From: Laszlo Ersek @ 2020-06-11 14:55 UTC (permalink / raw)
  To: Ard Biesheuvel, devel; +Cc: Philippe Mathieu-Daudé

Hi Ard,

On 06/10/20 11:32, Ard Biesheuvel wrote:
> On 6/10/20 11:22 AM, Laszlo Ersek wrote:

>> (3) make it a dynamic boolean PCD, and use the recently introduced
>> fw_cfg control interface
>>
>>
>> In all three options, the OVMF DSC files would unconditionally use the
>> X86QemuLoadImageLib instance, we'd just predicate the fallback to the
>> legacy Linux/x86 boot protocol on:
>>
>>    SecureBoot disabled || FallbackPcd
>>
>> (where "SecureBoot disabled" means that the SecureBoot standard UEFI
>> variable doesn't exist, or has zero value).
>>
>> I think option (2) means the least churn, and it would be "good enough"
>> functionally.
>>
>> Does this look palatable to you?
>>
>>
>>> So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if
>>> you cannot start the image anyway?
>>
>> Honestly: I'm not sure!
>>
>>> Because I would prefer it if we could
>>> start the image anyway, Unfortunately, the only way seems to be
>>
>> Right; it seems like the EFI_SECURITY_VIOLATION status would get saved
>> in the private LoadImageStatus field, and that would cause StartImage()
>> to fail early as well. I couldn't find a spot to "re-set"
>> LoadImageStatus.
>>
>>> to use
>>> the loaded image protocol data (base and size in memory) and do another
>>> LoadImage() after adding the hash to "db", and this is also more
>>> elaborate than I would like.
>>
>> Agreed. We shouldn't mess with "db".
>>
>>> Of course, the *correct* fix is to add the vendor cert to db - you are
>>> loading a signed image from a known source, and this whole dance with
>>> shim and the MS certs is ridiculous, and I am still hoping we can avoid
>>> this mess on ARM
>>
>> I considered this. It didn't look feasible to me at first sight (how
>> many vendors?), but now that you mention it and I've looked at it more
>> closely, it does look feasible. Selfishly (!), if I look at the guest OS
>> types officially supported on RHEL8 hosts:
>>
>> - https://access.redhat.com/articles/973133
>> - https://access.redhat.com/articles/973163
>>
>> then all we (RH) would need are two patches for (upstream)
>> OvmfPkg/EnrollDefaultKeys. Namely, we should enroll two more DB entries:
>>
>> - SUSE's CA certificate to which the key(s) chain that they use for
>> signing their kernels
>>
>> - Red Hat's CA certificate to which the key(s) chain that we use for
>> signing our kernels.
>>
>> That would strictly be an improvement even for upstream OVMF (more
>> vendors accepted).
>>
>> Ultimately I think the right way is to pick option (3) -- dynamic PCD --
>> *and* add the SUSE and RH CA certs to OvmfPkg/EnrollDefaultKeys. That
>> means SUSE and RH signed kernels can be booted at once, with secure
>> verification, and users would still have a QEMU command line option for
>> opting *into* the legacy boot protocol fallback.
>>
>> Do you agree? Would you be OK with patches to this effect?
>>
> 
> Yes, option #3 looks reasonable to me. And adding the certs is the right
> thing to do regardless - going around installing the MS certs everywhere
> is a recipe for disaster, and AIUI, MS now requires you to remove them
> in some cases?? (for DeviceGuard support or sth like that)

I've "escalated" this internally to other virt team engineers, and they
seem to consider this a plain regression. They suggested we should
revert the patch, because:

- the problem will affect every guest distro different from SUSE and RH
out there, and every host distro providing KVM hypervisor,

- the change isn't fixing a practical security issue.

(I'm quite stressed about bringing this internal feedback to you,
admittedly...)

Thanks,
Laszlo


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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-11 14:55           ` Laszlo Ersek
@ 2020-06-11 15:05             ` Ard Biesheuvel
  2020-06-11 18:13               ` Laszlo Ersek
  0 siblings, 1 reply; 30+ messages in thread
From: Ard Biesheuvel @ 2020-06-11 15:05 UTC (permalink / raw)
  To: Laszlo Ersek, devel; +Cc: Philippe Mathieu-Daudé

On 6/11/20 4:55 PM, Laszlo Ersek wrote:
> Hi Ard,
> 
> On 06/10/20 11:32, Ard Biesheuvel wrote:
>> On 6/10/20 11:22 AM, Laszlo Ersek wrote:
> 
>>> (3) make it a dynamic boolean PCD, and use the recently introduced
>>> fw_cfg control interface
>>>
>>>
>>> In all three options, the OVMF DSC files would unconditionally use the
>>> X86QemuLoadImageLib instance, we'd just predicate the fallback to the
>>> legacy Linux/x86 boot protocol on:
>>>
>>>    SecureBoot disabled || FallbackPcd
>>>
>>> (where "SecureBoot disabled" means that the SecureBoot standard UEFI
>>> variable doesn't exist, or has zero value).
>>>
>>> I think option (2) means the least churn, and it would be "good enough"
>>> functionally.
>>>
>>> Does this look palatable to you?
>>>
>>>
>>>> So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if
>>>> you cannot start the image anyway?
>>>
>>> Honestly: I'm not sure!
>>>
>>>> Because I would prefer it if we could
>>>> start the image anyway, Unfortunately, the only way seems to be
>>>
>>> Right; it seems like the EFI_SECURITY_VIOLATION status would get saved
>>> in the private LoadImageStatus field, and that would cause StartImage()
>>> to fail early as well. I couldn't find a spot to "re-set"
>>> LoadImageStatus.
>>>
>>>> to use
>>>> the loaded image protocol data (base and size in memory) and do another
>>>> LoadImage() after adding the hash to "db", and this is also more
>>>> elaborate than I would like.
>>>
>>> Agreed. We shouldn't mess with "db".
>>>
>>>> Of course, the *correct* fix is to add the vendor cert to db - you are
>>>> loading a signed image from a known source, and this whole dance with
>>>> shim and the MS certs is ridiculous, and I am still hoping we can avoid
>>>> this mess on ARM
>>>
>>> I considered this. It didn't look feasible to me at first sight (how
>>> many vendors?), but now that you mention it and I've looked at it more
>>> closely, it does look feasible. Selfishly (!), if I look at the guest OS
>>> types officially supported on RHEL8 hosts:
>>>
>>> - https://access.redhat.com/articles/973133
>>> - https://access.redhat.com/articles/973163
>>>
>>> then all we (RH) would need are two patches for (upstream)
>>> OvmfPkg/EnrollDefaultKeys. Namely, we should enroll two more DB entries:
>>>
>>> - SUSE's CA certificate to which the key(s) chain that they use for
>>> signing their kernels
>>>
>>> - Red Hat's CA certificate to which the key(s) chain that we use for
>>> signing our kernels.
>>>
>>> That would strictly be an improvement even for upstream OVMF (more
>>> vendors accepted).
>>>
>>> Ultimately I think the right way is to pick option (3) -- dynamic PCD --
>>> *and* add the SUSE and RH CA certs to OvmfPkg/EnrollDefaultKeys. That
>>> means SUSE and RH signed kernels can be booted at once, with secure
>>> verification, and users would still have a QEMU command line option for
>>> opting *into* the legacy boot protocol fallback.
>>>
>>> Do you agree? Would you be OK with patches to this effect?
>>>
>>
>> Yes, option #3 looks reasonable to me. And adding the certs is the right
>> thing to do regardless - going around installing the MS certs everywhere
>> is a recipe for disaster, and AIUI, MS now requires you to remove them
>> in some cases?? (for DeviceGuard support or sth like that)
> 
> I've "escalated" this internally to other virt team engineers, and they
> seem to consider this a plain regression. They suggested we should
> revert the patch, because:
> 
> - the problem will affect every guest distro different from SUSE and RH
> out there, and every host distro providing KVM hypervisor,
> 
> - the change isn't fixing a practical security issue.
> 
> (I'm quite stressed about bringing this internal feedback to you,
> admittedly...)
> 

Don't worry about it.

If we can ensure that the only bootable images that are exempt from the 
secure boot checks are ones that were provided directly by the host 
userspace, then I think their position is not unreasonable, given that 
the guest is at its mercy anyway.


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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-11 15:05             ` Ard Biesheuvel
@ 2020-06-11 18:13               ` Laszlo Ersek
  2020-06-11 19:07                 ` Ard Biesheuvel
  0 siblings, 1 reply; 30+ messages in thread
From: Laszlo Ersek @ 2020-06-11 18:13 UTC (permalink / raw)
  To: Ard Biesheuvel, devel; +Cc: Philippe Mathieu-Daudé

On 06/11/20 17:05, Ard Biesheuvel wrote:
> On 6/11/20 4:55 PM, Laszlo Ersek wrote:
>> Hi Ard,
>>
>> On 06/10/20 11:32, Ard Biesheuvel wrote:
>>> On 6/10/20 11:22 AM, Laszlo Ersek wrote:
>>
>>>> (3) make it a dynamic boolean PCD, and use the recently introduced
>>>> fw_cfg control interface
>>>>
>>>>
>>>> In all three options, the OVMF DSC files would unconditionally use the
>>>> X86QemuLoadImageLib instance, we'd just predicate the fallback to the
>>>> legacy Linux/x86 boot protocol on:
>>>>
>>>>    SecureBoot disabled || FallbackPcd
>>>>
>>>> (where "SecureBoot disabled" means that the SecureBoot standard UEFI
>>>> variable doesn't exist, or has zero value).
>>>>
>>>> I think option (2) means the least churn, and it would be "good enough"
>>>> functionally.
>>>>
>>>> Does this look palatable to you?
>>>>
>>>>
>>>>> So what is the point of DEFER_EXECUTE_ON_SECURITY_VIOLATION anyway, if
>>>>> you cannot start the image anyway?
>>>>
>>>> Honestly: I'm not sure!
>>>>
>>>>> Because I would prefer it if we could
>>>>> start the image anyway, Unfortunately, the only way seems to be
>>>>
>>>> Right; it seems like the EFI_SECURITY_VIOLATION status would get saved
>>>> in the private LoadImageStatus field, and that would cause StartImage()
>>>> to fail early as well. I couldn't find a spot to "re-set"
>>>> LoadImageStatus.
>>>>
>>>>> to use
>>>>> the loaded image protocol data (base and size in memory) and do
>>>>> another
>>>>> LoadImage() after adding the hash to "db", and this is also more
>>>>> elaborate than I would like.
>>>>
>>>> Agreed. We shouldn't mess with "db".
>>>>
>>>>> Of course, the *correct* fix is to add the vendor cert to db - you are
>>>>> loading a signed image from a known source, and this whole dance with
>>>>> shim and the MS certs is ridiculous, and I am still hoping we can
>>>>> avoid
>>>>> this mess on ARM
>>>>
>>>> I considered this. It didn't look feasible to me at first sight (how
>>>> many vendors?), but now that you mention it and I've looked at it more
>>>> closely, it does look feasible. Selfishly (!), if I look at the
>>>> guest OS
>>>> types officially supported on RHEL8 hosts:
>>>>
>>>> - https://access.redhat.com/articles/973133
>>>> - https://access.redhat.com/articles/973163
>>>>
>>>> then all we (RH) would need are two patches for (upstream)
>>>> OvmfPkg/EnrollDefaultKeys. Namely, we should enroll two more DB
>>>> entries:
>>>>
>>>> - SUSE's CA certificate to which the key(s) chain that they use for
>>>> signing their kernels
>>>>
>>>> - Red Hat's CA certificate to which the key(s) chain that we use for
>>>> signing our kernels.
>>>>
>>>> That would strictly be an improvement even for upstream OVMF (more
>>>> vendors accepted).
>>>>
>>>> Ultimately I think the right way is to pick option (3) -- dynamic
>>>> PCD --
>>>> *and* add the SUSE and RH CA certs to OvmfPkg/EnrollDefaultKeys. That
>>>> means SUSE and RH signed kernels can be booted at once, with secure
>>>> verification, and users would still have a QEMU command line option for
>>>> opting *into* the legacy boot protocol fallback.
>>>>
>>>> Do you agree? Would you be OK with patches to this effect?
>>>>
>>>
>>> Yes, option #3 looks reasonable to me. And adding the certs is the right
>>> thing to do regardless - going around installing the MS certs everywhere
>>> is a recipe for disaster, and AIUI, MS now requires you to remove them
>>> in some cases?? (for DeviceGuard support or sth like that)
>>
>> I've "escalated" this internally to other virt team engineers, and they
>> seem to consider this a plain regression. They suggested we should
>> revert the patch, because:
>>
>> - the problem will affect every guest distro different from SUSE and RH
>> out there, and every host distro providing KVM hypervisor,
>>
>> - the change isn't fixing a practical security issue.
>>
>> (I'm quite stressed about bringing this internal feedback to you,
>> admittedly...)
>>
> 
> Don't worry about it.
> 
> If we can ensure that the only bootable images that are exempt from the
> secure boot checks are ones that were provided directly by the host
> userspace, then I think their position is not unreasonable, given that
> the guest is at its mercy anyway.
> 

Thanks.

So... reverting this patch would only affect the behavior of the
QemuLoadKernelImage() API, and that API only consumes fw_cfg. Fw_cfg is
under the control of the host userspace (QEMU implements the fw_cfg
"platform hardware). Does that satisfy your condition ("provided
directly by the host userspace"), or are you referring to any "farther"
origin on the host side, from where the fw_cfg content is originally taken?

IOW would you involve in this decision the question where on the network
the kernel image is downloaded from (on the host), for example? (I
wouldn't -- for me, the fact that fw_cfg is technically controlled by
QEMU is enough.)

FWIW I've reverted the patch downstream (a deadline forced my hand
before we could conclude this upstream thread, and the use cases that
had regressed are considered important), but I really dislike that
divergence from upstream. I'd like to eliminate that downstream patch
when we rebase to a subsequent stable tag.

Thanks,
Laszlo


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

* Re: [edk2-devel] [PATCH v3 14/14] OvmfPkg: use generic QEMU image loader for secure boot enabled builds
  2020-06-11 18:13               ` Laszlo Ersek
@ 2020-06-11 19:07                 ` Ard Biesheuvel
  0 siblings, 0 replies; 30+ messages in thread
From: Ard Biesheuvel @ 2020-06-11 19:07 UTC (permalink / raw)
  To: Laszlo Ersek, devel; +Cc: Philippe Mathieu-Daudé

On 6/11/20 8:13 PM, Laszlo Ersek wrote:
> On 06/11/20 17:05, Ard Biesheuvel wrote:
...
>>
>> If we can ensure that the only bootable images that are exempt from the
>> secure boot checks are ones that were provided directly by the host
>> userspace, then I think their position is not unreasonable, given that
>> the guest is at its mercy anyway.
>>
> 
> Thanks.
> 
> So... reverting this patch would only affect the behavior of the
> QemuLoadKernelImage() API, and that API only consumes fw_cfg. Fw_cfg is
> under the control of the host userspace (QEMU implements the fw_cfg
> "platform hardware). Does that satisfy your condition ("provided
> directly by the host userspace"), or are you referring to any "farther"
> origin on the host side, from where the fw_cfg content is originally taken?
> 

No, that is fine. I am just slightly unhappy that any code that happily 
circumvents the normal secure/measured boot flow entirely is even 
present in the image.

> IOW would you involve in this decision the question where on the network
> the kernel image is downloaded from (on the host), for example? (I
> wouldn't -- for me, the fact that fw_cfg is technically controlled by
> QEMU is enough.)
> 

Yes.

> FWIW I've reverted the patch downstream (a deadline forced my hand
> before we could conclude this upstream thread, and the use cases that
> had regressed are considered important), but I really dislike that
> divergence from upstream. I'd like to eliminate that downstream patch
> when we rebase to a subsequent stable tag.
> 

Since we're on list:

Acked-by: Ard Biesheuvel <ard.biesheuvel@arm.com>

on a revert of ced77332cab626f35fbdb36630be27303d289d79. Merge it 
whenever you see fit.


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

end of thread, other threads:[~2020-06-11 19:07 UTC | newest]

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

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