How OS Kernel Locates Root Filesystem via UEFI Variables

When a modern computer boots, the operating system kernel relies on a chain of execution initiated by the Unified Extensible Firmware Interface (UEFI). The firmware uses non-volatile RAM (NVRAM) variables—specifically boot options defined in the UEFI specification—to determine which binary to execute and which parameters to pass. By reading these variables, either directly through the Linux EFI Boot Stub or indirectly via a bootloader, the kernel receives the precise identifier of the storage device and partition hosting the root filesystem, allowing the initial RAM disk to locate and mount it.

1. UEFI Boot Variables and NVRAM Storage

UEFI systems store boot configuration in non-volatile storage known as NVRAM. The firmware utilizes specific standardized variables to orchestrate startup:

  • BootOrder: An array of 16-bit integers defining the sequence in which boot options are attempted.
  • BootNext: An optional variable specifying a one-time boot override.
  • BootCurrent: A variable set by the firmware indicating which boot entry was successfully loaded.
  • Boot####: Individual entries (e.g., Boot0001, Boot0002) structured as EFI_LOAD_OPTION descriptors.

Each EFI_LOAD_OPTION contains several critical fields: attributes, a human-readable description, a UEFI device path pointing to the executable file (typically on the EFI System Partition, or ESP), and an OptionalData binary buffer.

2. Passing Boot Parameters via OptionalData

The OptionalData field in a Boot#### variable acts as a command-line carrier. System utilities like efibootmgr can populate this field with kernel parameters such as:

root=UUID=4f9c8b72-1234-4a5b-8c9d-0123456789ab rw

Alternatively, partition identifiers can be used:

root=PARTUUID=a1b2c3d4-e5f6-7890-abcd-ef0123456789

When the UEFI Boot Manager executes the binary specified in the device path, it encapsulates these parameters inside an EFI_LOADED_IMAGE_PROTOCOL structure. The executable receives access to this structure, specifically reading the LoadOptions and LoadOptionsSize fields, which contain the exact string stored in the NVRAM OptionalData.

3. Handoff to the Kernel: Direct Boot vs. Bootloader

There are two primary ways the kernel acquires these parameters:

  • Direct Boot (EFI Boot Stub): When compiled with CONFIG_EFI_STUB, the Linux kernel binary functions as a native PE/COFF UEFI executable. The firmware loads the kernel directly. The kernel's stub code queries the EFI_LOADED_IMAGE_PROTOCOL for LoadOptions, extracts the command-line string containing the root= parameter, and integrates it into the kernel's internal command buffer before exiting UEFI Boot Services.
  • Bootloader Handoff (GRUB, systemd-boot): The firmware loads the bootloader first. The bootloader inspects the boot variables, determines the boot entry, merges any user configuration with the variables, loads the kernel and initramfs into memory, and passes the synthesized command line to the kernel via the boot protocol. Bootloaders like systemd-boot also set additional UEFI variables (e.g., LoaderDevicePartUUID) to inform the OS where it booted from.

4. Reading UEFI Variables from Userspace and Initramfs

Once the kernel takes control and terminates UEFI Boot Services, direct calls to the UEFI firmware interface are largely replaced by UEFI Runtime Services.

The kernel exposes these services to user space via the efivarfs pseudo-filesystem, typically mounted at /sys/firmware/efi/efivars. This allows early boot components in the initial RAM disk (initramfs) to inspect NVRAM variables dynamically if required by the boot scheme (for example, discovering system-token variables or partition identifiers generated by the bootloader).

5. Identification and Mounting of the Root Filesystem

The actual discovery and mounting of the root filesystem proceed through the initramfs:

  1. Parameter Parsing: The initramfs parses the kernel command line received from the UEFI environment to find the root= specifier.
  2. Device Enumeration: The kernel initializes storage controllers (NVMe, SATA, USB) and registers block devices.
  3. Udev Detection: The udev daemon inside the initramfs listens for kernel uevents as storage devices are registered. It reads partition headers (GPT) and filesystem superblocks, generating symlinks under /dev/disk/by-uuid/ and /dev/disk/by-partuuid/.
  4. Resolution: The initramfs matches the target UUID or PARTUUID provided in the UEFI-originating command line with the detected device nodes.
  5. Mount and Switch: The root device is mounted to a temporary target (such as /sysroot). Once mounted, the initramfs transfers execution using switch_root or pivot_root, making the targeted storage volume the active root directory of the operating system.