OVMF is a modern UEFI firmware implementation adapted to run inside virtual environments such as QEMU or KVM. It replaces legacy BIOS and provides the guest operating system with a standardized interface for booting and interacting with virtual hardware during the pre-OS stage.
The primary use case for OVMF is running operating systems that require UEFI inside virtual machines. The technology is a standard component for KVM and QEMU hypervisors and is actively used in cloud and enterprise environments. It is essential for PCI device passthrough to a guest OS, booting from GPT disks, and guest environment features such as Secure Boot and TPM protocol support.
Typical problems
The most common difficulties when using OVMF relate to memory management and security settings. The default address space limitation prevents devices with large amounts of video memory from working correctly, causing error Code 12 in guest systems. Incorrect NVRAM storage configuration can lead to integrity violations, especially in builds with Secure Boot support. Device driver compatibility issues also occur if the build does not include the required components.
Operating principle
The OVMF operation process follows the standard UEFI Platform Initialization (PI) sequence and consists of several clearly defined phases. After power is applied to the virtual machine, the Security Phase (SEC) is launched, with its code written in assembly. Its task is to switch the processor from 16-bit real mode to 32-bit mode, and then to 64-bit protected mode, while simultaneously locating the Boot Firmware Volume (BFV) in memory and handing control over to the next stage core.
The next stage, Pre-EFI Initialization or PEI, runs from the core discovered during the SEC phase. The main task of PEI is the early initialization of critical hardware, primarily the memory controller and processor interfaces. In OVMF, this stage also involves decompressing the main DXE volume from a compact image into temporary RAM. The culmination of the PEI phase is the launch of a special DXE IPL loader, which locates the DXE core and transfers control to it, switching processor modes again if necessary to transition to a full 64-bit environment.
The Driver Execution Environment (DXE) phase is the foundation of the firmware. At this stage, the DXE core sequentially loads and executes hundreds of drivers from the firmware image. These drivers are responsible for initializing all remaining hardware platform components: from PCI, USB, and SATA controllers to network cards and graphics adapters. Each driver publishes a set of protocols, interfaces that other system components can use. When all necessary architectural protocols (for example, for disk access, file systems, and console) become available, the final stage, Boot Device Selection (BDS), is launched.
During the BDS stage, the firmware determines which media to boot the operating system from. The boot manager analyzes global UEFI variables stored in non-volatile NVRAM memory and searches for available boot entries. If automatic boot is configured, OVMF passes control to the operating system loader. In case of failure or upon user request, the built-in UEFI Shell can be launched, providing a command-line interface for diagnostics and manual boot management.
OVMF functionality
- Decomposition of the image into Firmware Device and Firmware Volume. The final OVMF build artifact is a Firmware Device (FD) image. The FD is a binary file that is flashed into the virtual machine’s flash memory. The internal structure of the FD is divided into logical containers called Firmware Volumes (FV), each containing a specific class of executable modules or data.
- Block structure and alignment of Firmware Volume. Each FV within the FD has its own attributes, including base address, size, and block size. The block structure is critically important for the operation of Fault Tolerant Write (FTW) services, which ensure atomicity of variable updates. The space inside the FV is organized sequentially: files are packed one after another, and all unused gaps are filled with the value
0xFFin accordance with the specifics of flash memory erasure. - Security Phase (SEC Phase) and reset vector. The earliest initialization phase, the Security Phase, is located at the beginning of the image. The ResetVector module executes the initial processor instructions after reset. Its task is to switch the processor from 16-bit real mode to 32-bit flat protected mode, and then to 64-bit Long Mode, if supported by the architecture.
- Firmware Volume location and validation. The assembly code located in the ResetVector performs a memory scan to discover the base address of the Boot Firmware Volume (BFV). The algorithm searches for the FV signature within a specific address range. Once the BFV is found, the entry point into the SEC Core is located, to which control is handed for further platform initialization.
- PEI Core initialization and Memory Reference Code. The Pre-EFI Initialization (PEI) phase launches the PEI Core, located in the PeiMain module. At this stage, a critically important function is the initialization of the memory controller (Memory Reference Code), described through HOBs (Hand-Off Blocks). A Platform PEIM, such as PlatformPei, determines the amount of available RAM in the guest system and creates a Resource Descriptor HOB.
- Address map and SMRAM region reservation. The QemuInitializeRam function in PEI forms the primary system memory descriptor. If the platform is configured with SMM support, Platform PEI modifies the memory map: the SMRAM region (TSEG) is carved out of the general available RAM pool and reserved as inaccessible to the operating system by creating a special HOB of type
EfiReservedMemoryType. - Setting the SMBASE default address. To support hot-plugging of virtual CPUs, an additional SMRAM region is reserved at the default SMBASE address (physical address
0x30000). This 128 KB region is used to place the initial SMI handler for new processors. The reservation must occur as early as possible to prevent this memory from being handed over to the OS. - Handoff to DXE Core. The culmination of PEI is the loading of the DXE Core. A special DXE IPL (Initial Program Load) module finds the DXE core in another Firmware Volume, converts the HOB list into UEFI tables, and transfers control. If PEI was launched in 32-bit mode and DXE is 64-bit, the final processor mode switch occurs during this transition.
- Non-volatile variable driver and NvVars emulation. In the DXE environment, the non-volatile variable management driver is launched. If the OVMF image is loaded in ROM mode (read-only), the standard flash memory mechanism is unavailable. The variable management function in this case switches to emulation via an NvVars file, creating a virtual store of UEFI variables in system memory.
- Fault Tolerant Write services and work space. To ensure variable integrity when writing to flash, FTW (Fault Tolerant Write) is used. The mechanism requires allocating a special work space in the FV layout, the size of which must strictly correspond to the flash memory erase block size (usually
0x1000). FTW writes data to a spare block and, upon transaction completion, atomically switches pointers, guaranteeing fault tolerance. - Separation of the image into code and variables. The build configuration with the
-D FD_SIZE_2MBflag generates two separate files:OVMF_CODE.fdandOVMF_VARS.fd. The code file contains the non-executable SEC, PEI, and DXE components and is mounted as a read-only device. The variables file contains an NV storage template with empty but valid internal structures and is connected as a separate writable pflash device. - SMRAM access interface via PEI SMM Access PPI. During the PEI stage, the
PEI_SMM_ACCESS_PPI(PEIM-to-PEIM Interface) is published, encapsulating theOpen,Close, andLockmethods for managing TSEG. TheLockfunction is called during the S3 Resume process before executing the boot script to close access to SMRAM before handing control to the operating system during the resume stage. - SMRAM access interface via DXE SMM Access Protocol. In DXE, the
EFI_SMM_ACCESS2_PROTOCOLis established, which is an analog of the PEI interface. TheLockfunction in this protocol is called by the SMM IPL core when installing theEFI_DXE_SMM_READY_TO_LOCK_PROTOCOL. This is a synchronization point, after which TSEG and the default SMBASE region are physically locked for writing. - BDS driver and boot policy. Boot Device Selection (BDS) manages the OS boot strategy. The PlatformBootManagerLib function in OVMF iterates over available devices, starting with virtual optical drives and hard disks. BDS is also responsible for initializing console devices, connecting the EFI Shell if present in the image, and processing hotkeys for entering the firmware setup menu.
- Host bridge handling in a multi-platform environment. The PciHostBridgeUtility function determines the chipset type by Device ID. OVMF supports multiple identifiers: standard QEMU (i440FX and Q35), Cloud Hypervisor (
CLOUDHV_DEVICE_ID 0x0d57), and MicroVM. The host bridge selection influences the configuration of Legacy Interrupt registers and the determination of the base addresses for the ACPI timer and reset controller ports. - Abstraction of the shutdown/reset mechanism. Depending on the detected platform, the ResetSystemLib library selects a functional shutdown method. For QEMU/KVM, a write to port
0x604(QEMU ACPI Shutdown) is typically used, while for platforms without a standard fw_cfg mechanism, a write of value5to port0xB004or a Cloud Hypervisor-specific port0x03C0is utilized. The function guarantees correct guest termination in all environments. - Integration of platform ACPI tables. The AcpiPlatformDxe module is responsible for installing ACPI tables into the UEFI configuration table. The function finds and installs the RSDP, RSDT/XSDT, FADT, DSDT, and MADT tables. In QEMU environments, tables are retrieved via the fw_cfg interface, whereas a separate parser is implemented for Cloud Hypervisor, extracting tables directly from guest memory.
- Generation and publication of SMBIOS structures. The SmbiosPlatformDxe driver collects SMBIOS data from various sources. The entry function analyzes fw_cfg (QEMU) or calls the internal Cloud Hypervisor handler (
CloudHv.c) to populate Type 0 (BIOS Information), Type 1 (System Information), and Type 3 (System Enclosure) structures. This data allows the guest OS to identify the hardware platform of the virtual machine. - Secure Boot support and SMM locking. When the
SMM_REQUIREandSECURE_BOOT_ENABLEflags are enabled, OVMF operates in strict isolation mode. Writing to the variable store containing the KEK, db, and dbx keys is only possible via an SMI handler call in SMRAM. The SmmAccessLock function closes and locks TSEG immediately after the ReadyToLock signal, preventing Secure Boot variable tampering by vulnerable guest software. - Firmware Device size configuration. The FD size is determined by defines at build time. The preprocessor function checks the values
FD_SIZE_1MB,FD_SIZE_2MB, orFD_SIZE_4MB. Depending on the selected size, the internal Firmware Volume layout changes: the space for compressed DXE driver module images is increased, or additional logical volumes are added to support an extended feature set.
Comparisons
- OVMF vs Coreboot. OVMF is a full UEFI implementation for virtual machines, providing runtime interfaces. In contrast, Coreboot focuses exclusively on hardware initialization and passes control to a third-party payload. While OVMF contains device drivers and services for the OS within itself, Coreboot eliminates itself after startup, relying on an external bootloader such as SeaBIOS or GRUB.
- SeaBIOS (Hardware initialization and system boot)
- OVMF vs SeaBIOS. SeaBIOS is a classic BIOS implementation (16-bit) providing backward compatibility with older OSes, whereas OVMF is based on the modern UEFI standard. The key difference lies in specification support: OVMF provides UEFI boot and runtime services, while SeaBIOS uses traditional interrupts and BIOS tables. To boot older systems in an OVMF environment, a Compatibility Support Module is used, temporarily engaging SeaBIOS.
- OVMF vs U-Boot (EFI Application). Building U-Boot as an EFI application allows the bootloader to run inside an already initialized UEFI environment (for example, OVMF). In this mode, U-Boot functions on top of UEFI services as a regular program, without direct access to the hardware. OVMF, on the other hand, manages the platform directly. Such a tandem, described in configurations for booting ISO images, turns U-Boot from a competitor into an add-on that uses OVMF file drivers.
- OVMF Legacy Loader vs EFI Stub Boot. OVMF supports two methods for booting Linux: the modern method (via the kernel EFI Stub, with Secure Boot verification) and the legacy Legacy Loader, which directly patches kernel headers. The Legacy Loader allows booting kernels without EFI support, but creates a security risk as it bypasses Secure Boot verification, which is why developers plan to disable it by default.
- OVMF vs DUET. Both OVMF and DUET are based on the TianoCore (edk2) codebase, but OVMF is a standalone firmware for virtual environments, whereas DUET was created to run UEFI applications on top of Legacy BIOS. DUET required SeaBIOS to function, making the architecture cumbersome and dependent on low-level emulation, unlike the self-contained OVMF execution environment for QEMU and KVM.
OS and driver support
Guest OS support in OVMF is implemented through the modular DXE driver system of EDK II: booting legacy systems (Windows 7, OpenBSD) without UEFI requires embedding SeaBIOS as a Compatibility Support Module (CSM) to translate 16-bit BIOS calls, while in pure UEFI environments, native SCSI device support is achieved by including specific drivers such as VMware PVSCSI (OvmfPkg/PvScsiDxe sources) at compile time or through dynamic attachment of PCI ROM options bypassing discrete routing tables.
Security
Cryptographic verification and measurement of components in OVMF are based on static library linking via the SecurityStubDxe module: Secure Boot is activated by the SECURE_BOOT_ENABLE build flag and the insertion of DxeImageVerificationLib to verify EFI image signatures, while Trusted Platform Module (TPM2) functions are implemented by the DxeTpm2MeasureBootLib library, which uses the Security Management Handler to intercept the loading of third-party UEFI drivers and PCI ROM options during the BDS stage for measurement into the PCR registers of the TPM 2.0 chip before passing control to the OS kernel.
Logging
Debug output from OVMF functions by redirecting the EDK II DEBUG() stream to a virtual serial port: the standard route uses isa-debugcon emulation with the allocation of I/O port 0x402 and data forwarding to a host file via the QEMU chardev backend, whereas for outputting logs directly to the guest console without a dedicated debug channel, the firmware is rebuilt with the -D DEBUG_ON_SERIAL_PORT flag, which changes the target port to the standard COM interface of the virtual machine.
Limitations
A fundamental architectural limitation of OVMF is the incompatibility of Secure Boot mode with the Compatibility Support Module: when signature verification (SECURE_BOOT_ENABLE) is enabled, the CSM subsystem is disabled, depriving the guest OS of access to legacy video BIOS (VGA ROM) and leaving only the basic GOP resolution until guest OS drivers are loaded, because the complex interface of 16-bit thunking interaction creates an unacceptably large attack vector for the reference UEFI security implementation.
History and development
The OVMF project originated as a reference open-source UEFI implementation based on the EDK II (TianoCore) build environment for QEMU/KVM virtual machines and initially integrated basic boot protocols; its evolution includes a transition from monolithic Platform builds to a modular decomposition of device drivers (extraction of PvScsiDxe from the common pool in 2020), and in 2023, the integration of confidential computing via TDX_MEASUREMENTS_DATA structures in the WorkArea for Intel TDX guests, where external input data (TdHob, CFV) is measured into RTMR registers during the SEC stage before the memory manager is initialized.