From 5e9c9b18d7e655e78c967f0af8e8012d839f235b Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Tue, 6 Oct 2026 22:08:56 +0000 Subject: [PATCH 1/2] chapter5: describe runtime access to file-backed variable stores Firmware that stores EFI variables in a file cannot write that file once the OS controls the storage device. U-Boot can keep servicing the variable runtime services from a memory-backed store and delegate persisting it to the OS: the RTStorageVolatile variable names the store file on the ESP and VarToFile exports the content the file must have. libefivar supports the mechanism (rhboot/efivar#282), but it is not documented outside of the U-Boot sources. Describe the mechanism in a non-normative section, as an example of how the variable store file can be updated at runtime, with U-Boot and libefivar as example implementations of the firmware and OS sides, without making it, or the variables it relies on, an EBBR requirement, and record its limitations: only modifications made by software aware of the mechanism persist across reset. While at it, retitle the chapter, whose scope now goes beyond the store file format, and add the chapter 2 anchor the new section refers to. This follows up on the discussion in #143. Suggested-by: Ilias Apalodimas Signed-off-by: Ricardo Salveti --- source/chapter2-uefi.rst | 2 + source/chapter5-variable-storage.rst | 147 +++++++++++++++++++++++++-- 2 files changed, 142 insertions(+), 7 deletions(-) diff --git a/source/chapter2-uefi.rst b/source/chapter2-uefi.rst index 1921c7cc..5fd3f76f 100644 --- a/source/chapter2-uefi.rst +++ b/source/chapter2-uefi.rst @@ -620,6 +620,8 @@ On AArch64 platforms, if `ResetSystem()` is not implemented then the Operating System should fall back to making a [PSCI]_ call to reset or shutdown the system. +.. _section-runtime-variable-access: + Runtime Variable Access ----------------------- diff --git a/source/chapter5-variable-storage.rst b/source/chapter5-variable-storage.rst index fb80a7c9..103bda77 100644 --- a/source/chapter5-variable-storage.rst +++ b/source/chapter5-variable-storage.rst @@ -1,8 +1,8 @@ .. SPDX-License-Identifier: CC-BY-SA-4.0 -************************************* -File Format For Storing EFI Variables -************************************* +******************** +EFI Variable Storage +******************** .. versionadded:: 2.2.0 @@ -10,13 +10,19 @@ Some UEFI enabled devices can only store EFI variables as a file on a block device. This implies that at runtime the operating system must manage changes to the EFI variables by updating the file. -This chapter defines a file-format for EFI variables that both the firmware -and the operating system can rely on. +This chapter defines a file format for EFI variables that both the firmware +and the operating system can rely on, and describes, as an example, a +mechanism that keeps the variable runtime services available with such a +file-backed variable store, as implemented by U-Boot and the libefivar +library. + +File Format For Storing EFI Variables +===================================== All integer fields are stored in little-endian byte order. File header -=========== +----------- The following byte sequence is used to identify the file format: @@ -70,7 +76,7 @@ Variables not sorted. Variable entries -================ +---------------- Each variable is stored as a structure: @@ -105,6 +111,120 @@ Data vendor’s variable followed by `DataSize` bytes of actual content of the variable. +.. _section-runtime-var-handover: + +Runtime Access to File-Backed Variables (non-normative) +======================================================= + +This section is non-normative. It describes, as an example, a mechanism that +keeps the variable runtime services available with a file-backed variable +store: the firmware services the variable runtime services from a copy of the +variable store held in memory, and the operating system writes the modified +variable store back to the EFI System Partition. U-Boot, which implements the +firmware side of the mechanism since release v2024.07, and the libefivar +library, which implements the operating system side, are used as example +implementations throughout this section. Other firmware implements the same +mechanism, e.g., the EDK II based firmware of Qualcomm platforms. This +specification requires neither firmware nor operating systems to implement +this mechanism, including the variables described below. See section +:ref:`section-runtime-variable-access` for the requirements on the variable +runtime services. + +Firmware that stores EFI variables in a file usually cannot write to that +file after `ExitBootServices()`: the file resides on a storage device that is +controlled by the operating system at runtime, and any firmware access would +conflict with transactions initiated by the OS. + +The firmware keeps a copy of the variable store in `EfiRuntimeServicesData` +memory, services `GetVariable()`, `GetNextVariableName()` and `SetVariable()` +from that copy during runtime services, and advertises `SetVariable()` as +supported in the `EFI_RT_PROPERTIES_TABLE`. Calls to `SetVariable()` during +runtime services only modify the in-memory copy, without accessing the +variable store file. The modifications are therefore volatile, including +those to variables carrying the `EFI_VARIABLE_NON_VOLATILE` attribute, until +the operating system writes the variable store back to the file as described +below. U-Boot implements this when built with the `EFI_RT_VOLATILE_STORE` +configuration option. + +Which modifications are accepted during runtime services is up to the +implementation. U-Boot only accepts modifications of non-volatile variables +having the `EFI_VARIABLE_RUNTIME_ACCESS` attribute: authenticated variables +are not supported, volatile variables cannot be created or modified, +variables without the `EFI_VARIABLE_RUNTIME_ACCESS` attribute are hidden from +`GetVariable()` and `GetNextVariableName()` and cannot be created or +modified, and the attributes of an existing variable cannot be changed. + +Variables +--------- + +The firmware exposes the variable store file to the operating system through +the two variables described below, under the vendor GUID +`b2ac5fc9-92b7-4acd-aeac-11e818c3130c`, which U-Boot defines as +`U_BOOT_EFI_RT_VAR_FILE_GUID`: + +.. code-block:: c + + #define U_BOOT_EFI_RT_VAR_FILE_GUID \ + EFI_GUID(0xb2ac5fc9, 0x92b7, 0x4acd, \ + 0xae, 0xac, 0x11, 0xe8, 0x18, 0xc3, 0x13, 0x0c) + +Both variables have the `EFI_VARIABLE_BOOTSERVICE_ACCESS` and +`EFI_VARIABLE_RUNTIME_ACCESS` attributes, are volatile, and are read-only: +calls to `SetVariable()` targeting them fail with `EFI_WRITE_PROTECTED`. + +RTStorageVolatile + This variable contains the path of the variable store file, relative to + the root directory of the EFI System Partition, as a NUL terminated ASCII + string. Any file path on the EFI System Partition can be used: + `ubootefi.var`, in the root directory, is the file name U-Boot uses. + +VarToFile + This variable contains the complete content the variable store file needs + to hold in order to persist the current state of all variables carrying + the `EFI_VARIABLE_NON_VOLATILE` attribute, as an `EFI_VARIABLE_FILE` + image in the format defined in this chapter. The firmware regenerates + the content every time the variable is read, so that it reflects all + preceding `SetVariable()` calls, including calls made during runtime + services. + +Persisting variable modifications +--------------------------------- + +To persist a variable modification performed during runtime services, the +operating system reads `RTStorageVolatile` to obtain the path of the variable +store file, reads `VarToFile` after the modification, and writes its content +to the variable store file on the EFI System Partition. + +The libefivar library, which Linux tools such as efibootmgr use to access EFI +variables, implements the operating system side: it detects the mechanism by +looking up `RTStorageVolatile` under the GUID above, and performs this +write-back after each variable modification or deletion it carries out, so +that the tools built on it persist their modifications transparently. +[#LibefivarNote]_ It only updates an existing variable store file, which it +locates by probing the usual mount points of the EFI System Partition. + +.. [#LibefivarNote] libefivar commit 68daa046 ("efivarfs: Update a file + variable store On SetVariable RT"), + https://github.com/rhboot/efivar/commit/68daa04654acbe1bbaa17ebfc23c371b39e69c6b + + At the time of writing, this support is not yet part of a tagged release + of libefivar. + +Writing the new content to a temporary file on the same partition, flushing +it to the storage device, then renaming it over the variable store file, +limits the exposure to an interrupted update: the content is complete before +the rename, which the file system performs as a single operation, and an +update interrupted before the rename leaves the variable store file +untouched. On Linux, `rename()` provides this on FAT file systems like on +any other file system, and since Linux 6.0 the FAT driver also supports the +`RENAME_EXCHANGE` flag of `renameat2()`, which exchanges the temporary file +and the variable store file in a single operation, as transactional as a +file system without a journal allows. [#RenameExchangeNote]_ + +.. [#RenameExchangeNote] Linux commit da87e1725ae2 ("fat: add renameat2 + RENAME_EXCHANGE flag support"), + https://git.kernel.org/linus/da87e1725ae2136baeb9aac04c572c283afc917f + Limitations =========== @@ -119,3 +239,16 @@ signing certificates of nonce-based authenticated variables. [#CertNote]_ .. [#CertNote] Tianocore EDK II keeps signer certificates of authenticated variables in variables `certdb` and `certdbv`. + +The mechanism described in section :ref:`section-runtime-var-handover` does +not provide generic `SetVariable()` support during runtime services: only the +modifications performed through software implementing the operating system +side of the mechanism are persisted, which at the time of writing means only +the modifications performed by tools using libefivar, such as efibootmgr. +Modifications performed by other means, e.g., by an application writing +directly to the `efivarfs` file system of the Linux kernel, or by an +operating system without support for the mechanism, are lost when the system +resets. Additionally, on systems with multiple EFI System Partitions, +`RTStorageVolatile` names the variable store file but not the partition +holding it, so identifying the correct partition is left to the operating +system. From 9ba1042bc44240a88ccb6d5dce00851b605d31e6 Mon Sep 17 00:00:00 2001 From: Ricardo Salveti Date: Tue, 6 Oct 2026 22:09:25 +0000 Subject: [PATCH 2/2] chapter2: mention runtime variable updates through the OS The Runtime Variable Access section recommends caching the variables in memory so that GetVariable() and GetNextVariableName() keep working when SetVariable() is not supported during runtime services. Add a note mentioning that firmware can go one step further and also accept SetVariable() on the cached copy, relying on the OS to persist the variable store, and point to the example now described in chapter 5. This is not a generic solution and is not required by EBBR: the runtime services requirements are unchanged. Signed-off-by: Ricardo Salveti --- source/chapter2-uefi.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/chapter2-uefi.rst b/source/chapter2-uefi.rst index 5fd3f76f..eb3b72c2 100644 --- a/source/chapter2-uefi.rst +++ b/source/chapter2-uefi.rst @@ -658,6 +658,15 @@ Even when `SetVariable()` is not supported during runtime services, firmware should cache variable names and values in `EfiRuntimeServicesData` memory so that `GetVariable()` and `GetNextVariableName()` can behave as specified. +.. note:: Firmware caching the variables in memory can go one step further + and accept `SetVariable()` calls during runtime services on the cached + copy, relying on the operating system to write the resulting variable + store back to the storage media. + This only persists the modifications performed by software aware of the + mechanism, and is not required by this specification. + Section :ref:`section-runtime-var-handover` describes such a mechanism, + with U-Boot and libefivar as example implementations. + .. _section-fw-update: Firmware Update