[PATCH v2 0/6] OvmfPkg: implement initrd shell command and mixed mode loader

Ard Biesheuvel

This is tagged as a v2 since it is a followup to a couple of patches [0][1]
that have already been sent to the list.

This series is part of my effort to define a generic EFI boot protocol for
Linux, i.e,. one that is the same across all different architectures that
are able to boot Linux from EFI, and naturally reused the firmware's
infrastructure for authenticated boot and measured boot.

Path #1 ... #4 implement the 'initrd' dynamic shell command, which takes a
file and exposes it via the LoadFile2 protocol installed on a vendor media
device path with guid LINUX_EFI_INITRD_MEDIA_GUID. This is a Linux specific,
but arch-agnostic way for the OS loader to load an initial ramdisk, while
leaving the firmware (or bootloader) in charge of where the file contents
are served from. This supersedes the currently existing solutions on Linux,
which are either limited to loading from the same volume that the OS loader
was loaded from, or load the initrd into memory first, and use architecture
specific data structures to pass on the information regarding base and size.

Patch #5 is an update to the integration of the PE/COFF emulator protocol,
to align it more closely with how LoadImage() and StartImage() behave today:
LoadImage() is not restricted to images that can execute natively on the
platform, but also permits loading of cross-type supported images. This means
that any judgement on whether an image can be *started* needs to be deferred
until StartImage(), which is why the invocation of the RegisterImage()
callback needs to be deferred as well.

Patch #6 implements the PE/COFF emulator protocol so it can start X64 images
that have been loaded on IA32 firmware. This is needed for Linux's so-called
'mixed mode', which is an elaborate scheme of on-the-fly translation of data
structures and thunking into 32-bit compat mode, allowing X64 Linux kernels
to be used on X64 capable hardware that shipped with IA32 firmware. This
needs support from the loader, and is currently implemented in GRUB (and
OVMF's command line kernel loader) using the EFI handover protocol, which
relies far too much on knowledge of kernel internal data structures, and
circumvents LoadImage and StartImage entirely.
(Note: mixed mode support is mainly targeted at cheap Atom tablets that
shipped with a [cheaper] 32-bit version of Windows, and so this particular
patch is unlikely to help that use case, but it is useful for validation.)

With these changes in place, we can boot x86 mixed-mode Linux straight from
the UEFI Shell

Shell>initrd fs0:\initrd.img
Shell>fs0:\bzImage root=/dev/vda2

Another benefit of this approach is that we can exit cleanly from the loader
(and back to the shell) using the Exit() boot service if any errors occur,
whereas the EFI handover protocol enters a deadloop upon any error that
occurs during execution of the EFI stub.

Changes from v1:
- Use a dynamic UEFI shell command, which is the recommended way of implementing
new shell commands that are not covered by the UEFI shell specification. It
also makes the command more easily usable on existing platforms, since the
driver can be loaded as an ordinary driver.
- split initrd patch into 4, as requested by Laszlo
- add patch to tweak the LoadImage/StartImage behavior wrt the PE/COFF emulator
- return EFI_UNSUPPORTED from PeCoffEmu::RegisterImage() if the image does not
have the required .compat section

[0] https://edk2.groups.io/g/devel/topic/rfc_patch_1_1_ovmfpkg_add/71177416
[1] https://edk2.groups.io/g/devel/topic/patch_1_1_ovmfpkg_ia32_add/71272266

Cc: lersek@redhat.com
Cc: leif@nuviainc.com
Cc: pjones@redhat.com
Cc: mjg59@google.com
Cc: agraf@csgraf.de
Cc: daniel.kiper@oracle.com
Cc: michael.d.kinney@intel.com
Cc: jian.j.wang@intel.com
Cc: hao.a.wu@intel.com
Cc: ray.ni@intel.com
Cc: zhichao.gao@intel.com

Ard Biesheuvel (6):
OvmfPkg: add definition of LINUX_EFI_INITRD_MEDIA_GUID
OvmfPkg: add 'initrd' shell command to expose Linux initrd via device
ArmVirtPkg: add the 'initrd' dynamic shell command
OvmfPkg: add the 'initrd' dynamic shell command
MdeModulePkg/DxeCore: defer PE/COFF emulator registration to
OvmfPkg IA32: add support for loading X64 images

ArmVirtPkg/ArmVirt.dsc.inc | 4 +
ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 1 +
ArmVirtPkg/ArmVirtXen.fdf | 1 +
MdeModulePkg/Core/Dxe/Image/Image.c | 24 +-
.../CompatImageLoaderDxe.c | 140 ++++++
.../CompatImageLoaderDxe.inf | 36 ++
OvmfPkg/Include/Guid/LinuxEfiInitrdMedia.h | 17 +
.../LinuxInitrdDynamicShellCommand.c | 423 ++++++++++++++++++
.../LinuxInitrdDynamicShellCommand.inf | 52 +++
.../LinuxInitrdDynamicShellCommand.uni | 49 ++
OvmfPkg/OvmfPkg.dec | 1 +
OvmfPkg/OvmfPkgIa32.dsc | 9 +
OvmfPkg/OvmfPkgIa32.fdf | 5 +
OvmfPkg/OvmfPkgIa32X64.dsc | 4 +
OvmfPkg/OvmfPkgIa32X64.fdf | 1 +
OvmfPkg/OvmfPkgX64.dsc | 4 +
OvmfPkg/OvmfPkgX64.fdf | 1 +
OvmfPkg/OvmfXen.dsc | 4 +
OvmfPkg/OvmfXen.fdf | 1 +
19 files changed, 766 insertions(+), 11 deletions(-)
create mode 100644 OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c
create mode 100644 OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.inf
create mode 100644 OvmfPkg/Include/Guid/LinuxEfiInitrdMedia.h
create mode 100644 OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.c
create mode 100644 OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.inf
create mode 100644 OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.uni