For our work on an EFI-based fault injector, we researched the EFI / UEFI support in the Windows operating system family. Here are the results collected from an introduction document, a requirement specification , a presentation from the UEFI plug fest, another presentation on the web, and the Windows Research Kernel documentation project.
Windows version
The support for EFI / UEFI for Windows began in 2002. It is only available for 64-bit processor architectures:
- Windows XP (X64): Can at least boot from an EFI firmware, since the according NVRAM boot option manipulation tools are documented.
- Windows Server 2003 (IA-64): EFI 1.10 support
- Windows Server 2008 (IA-64): EFI 1.10 support
- Windows Server 2008 (X64): UEFI 2.0 support
- Windows Server 2008 R2: UEFI 2.3 ‘non-removable media boot behavior’ support
- Vista SP1 (X64): UEFI 2.0 support
- Windows 7 (X64): UEFI 2.0 support
There are only a few official remarks about the usefullness of EFI for Windows features beside booting. Microsoft claims ‘multicast deployment’ and ‘faster hibernate’ as examples. The standard system table with both boot services and runtime services is expected to be fully implemented by the firmware. Windows makes use of the EFI PXE support, the device path protocol, and the block I/O protocol at boot time and on hibernation resume. Furthermore, a built-in TPM module is expected to be usable through the according EFI protocols.
Windows always prefers native drivers over ACPI runtime support over EFI runtime support functions. The currently documented amount of EFI support fits to this policy.
Boot support
Windows officially switched to the firmware-independent Boot Configuration Data (BCD) approach since Windows Vista, which means that the Windows boot manager (bootmgfw.efi) has its own storage facility for boot options and ordering. The BCD store is located as file on the EFI partition. The boot loader EFI application uses the Block I/O protocol to read the file, and later to bring up the OS loader. In general, it seems like the BCD store and NVRAM variables for booting are kept in sync. If this is the case, the BCD editing during runtime *could* lead ultimately to calls into the UEFI runtime variable service – we still need to check that. The presentation from the plug fest claims GetVariable, SetVariable, and GetNextVariableName to be the only EFI functions used at runtime. Another document lists QueryVariableInfo as another function used at runtime. The purpose seems to be related to WHEA, we are still looking into this one too.
On boot time, Windows is able to use either the EFI 1.10 universal graphics adapter protocol (UGA), the UEFI 2.0 graphics output protocol (GOP), or the standard simple text output protocol. Windows Server 2008 R2 and Windows 7 show a high-resolution version of the startup animation if GOP is supported.
Runtime services (Updated)
The investigated documentation underlines the impression that EFI runtime services are respected and protected by the Windows operating system, including the support for EFI’s GetMemoryMap(). The neccessary ExitBootServices() and SetVirtualAddressMap() calls are performed by the Windows OS loader, which runs after the boot manager got a choice for the OS installation to be started.
A representation of EFI runtime services in Linux is given by it’s efivars module. For Windows, our crawling of MSDN finally lead to the well-hidden GetFirmwareEnvironmentVariable and SetFirmwareEnvironmentVariable functions. Disassembling their implementation on Windows XP 32-bit showed that GetFirmwareEnvironmentVariable maps to NtQuerySystemEnvironmentValueEx, and SetFirmwareEnvironmentVariable maps to NtSetSystemEnvironmentVariableEx. Both kernel functions are declared in NtExApi.h and implemented as part of sysenv.obj in a Windows kernel build, making them ultimately a part of ntoskrnl.exe.
In the Windows XP 32-bit case, both kernel functions map to the same implementation that just returns STATUS_NOT_IMPLEMENTED. This fits to the MSDN documentation, which declares support for the user mode functions starting from Windows XP SP1 – but this relates only to the export of the according symbols in kernel32.lib. Therefore, the EFI support levels described in the first part of this article still apply. Applications need to check (with the procedure described for GetFirmwareEnvironmentVariable) if the functions are implemented.
We are currently about to disassemble the Windows kernel behavior on a true EFI system, in order to get a better feeling of the call flow when the implementation is there.