Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions source/chapter2-uefi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----------------------

Expand Down Expand Up @@ -656,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
Expand Down
147 changes: 140 additions & 7 deletions source/chapter5-variable-storage.rst
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
.. SPDX-License-Identifier: CC-BY-SA-4.0

*************************************
File Format For Storing EFI Variables
*************************************
********************
EFI Variable Storage
********************

.. versionadded:: 2.2.0

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:

Expand Down Expand Up @@ -70,7 +76,7 @@ Variables
not sorted.

Variable entries
================
----------------

Each variable is stored as a structure:

Expand Down Expand Up @@ -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
===========

Expand All @@ -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.