This directory provides support code for building UEFI applications using the
efi_executable() GN template. The UEFI build environment provided here is basically similar to the
phys environment for
zbi_executable(), but somewhat less constrained. The kernel's basic libc and the
ktl subset of standard C++ library features are available.
//zircon/kernel/phys/efi:main target provides entry code that calls the standard C
main function with
main will be called with
argc == 0 when booted directly from the UEFI Boot Manager, but gets full arguments when launched from the UEFI Shell.
UEFI code can use dynamic relocation freely, and can have static constructors and destructors. (Destructors are called only if
main returns. There is no standard C
Though meant for low-level situations, the UEFI API is just a bunch of C data structures and function pointers. So it's eminently amenable to mocking for unit tests. The
//zircon/kernel/lib/efi/testing library works with gmock and gtest to make this easy. So most
phys/efi code is written to allow compilation on host platforms for the benefit of unit tests. To this end, it uses standard C++ headers and
std:: symbols directly rather than using
<ktl/....h> headers and
ktl:: symbols as kernel code normally does. Like library code shared between kernel and other contexts, it must adhere to the strict subset of standard C++ library features that have
ktl counterparts defined.
UEFI supports standard disk partitioning and the VFAT filesystem format, which is a traditional MS-DOS/Window filesystem format that‘s what’s usually used on USB thumb drives. On most UEFI systems, any attached disk (USB, etc.) in this format will be available to boot or run UEFI applications from. VFAT file names are case-insensitive but case-preserving.
When booting from a VFAT filesystem, UEFI firmware will look for the file
X64 on x86 and
AA64 on ARM64. If this file exists, it will be run directly. If no such file exists, some systems will fall back to running the UEFI Shell.
Some UEFI systems support the UEFI Shell, including the EDK2 reference implementation used with QEMU and other emulators. This provides a simple command-line interface that can launch UEFI applications, pass them arguments, etc. as well as simple MS-DOS/Unix-like commands for filesystem access and so on. When booted into the UEFI shell, UEFI applications can be run directly by filesystem path, using the extension
.EFI (explicit or implicit):
UEFI applications run this way can take command-line arguments:
Shell> efi-hello-world-test arg1 "argument 2"
When the application exits, it will return to the shell prompt. However, tests that crash may wedge the system so physical reset (or killing the emulator) is required.
The UEFI Shell command
reset can be used to reboot the machine or exit the emulator.
The Fuchsia checkout includes UEFI firmware images usable with QEMU or other emulators (with or without KVM). To run UEFI binaries under QEMU, launch QEMU manually as normal (e.g. using the same switches
fx qemu prints out) but with a few different switches.
First, discard any
-initrd ..., or
-append ... switches, as these will not have any effect. Replace them with the
-bios switch giving the path to the UEFI firmware image:
The QEMU virtual machine will attempt to boot from disk or network just like a real UEFI-based PC would. If you have a disk image as would go onto a USB thumb drive, you can use QEMU switches such as
-hda ... to point at it. QEMU also offers a convenient feature to mock up a VFAT filesystem image on a virtual disk device directly from your host filesystem. To use this, first populate a small directory with the files you want visible to UEFI. For example:
mkdir qemu-efi-root (cd qemu-efi-root; ln -snf ../out/default/kernel.efi_x64/*.efi .)
mkdir -p qemu-efi-root/efi/boot ln out/default/kernel.efi_x64/efi-hello-world-test.efi qemu-efi-root/efi/boot/bootx64.efi
Then invoke QEMU with this additional switch, providing the path to your directory after
Don‘t put too much into the directory, or the virtual filesystem image will be too big for QEMU to handle. (It likely won’t work to just point it at your whole build directory, for example.) Once QEMU starts, you shouldn‘t modify the contents of that directory. You’ll probably need to restart QEMU after any changes to the directory or the files in it.