Sorry, you need to enable JavaScript to visit this website.

Accessing UEFI Variables from Linux

This article gives a summary of the two methods Linux provides for accessing UEFI runtime variables, along with the tradeoffs and a little bit of history.

The Legacy efivars Interface

The original interface, written by Matt Domsch, for interacting with UEFI variables is exported via the all-purpose Linux kernel sysfs filesystem. This interface was created in the days of EFI, before UEFI, for use with Itanium machines and so comes with a certain amount of historical baggage.

The legacy efivars interface is exported via the path "firmware/efi/vars/" relative to the mount point of sysfs. Assuming that sysfs is mounted at /sys, the directory containing the efivars files will be,

/sys/firmware/efi/vars/

Apart from the special files 'new_var' and 'del_var', each entry in the above mount point is itself a directory - one directory for every UEFI variable that is accessible at runtime,

Boot0000-12345678-abcd-abcd-abcd-123456789abc/
Boot0001-12345678-abcd-abcd-abcd-123456789abc/
BootCurrent-12345678-abcd-abcd-abcd-123456789abc/
BootOrder-12345678-abcd-abcd-abcd-123456789abc/
BootSetup-12345678-abcd-abcd-abcd-123456789abc/
del_var
Lang-12345678-abcd-abcd-abcd-123456789abc/
LangCodes-12345678-abcd-abcd-abcd-123456789abc/
new_var
Setup-12345678-abcd-abcd-abcd-123456789abc/

The directory name for a UEFI variable is composed of the variable name and the variable's Globally Unique Identifier (GUID). This example:

Boot0000-12345678-abcd-abcd-abcd-123456789abc/

could be the directory for the first UEFI Boot Variable. Within each directory the following files can be found,

attributes
data
guid
raw_var
size

The contents of most of these files are human readable, and correspond to the UEFI variable parameters of the same name. The exception being the 'raw_var' file, which contains binary data. For instance, the 'attributes' file for the above Boot entry would contain something like the following ASCII strings,

EFI_VARIABLE_NON_VOLATILE
EFI_VARIABLE_BOOTSERVICE_ACCESS
EFI_VARIABLE_RUNTIME_ACCESS

to indicate that the variable is non-volatile, and accessible both before and after calling the UEFI Boot Service, ExitBootServices(). It's not possible to write to these human readable files - their only purpose is to provide users with details of the variable.

'raw_var' allows the UEFI variable binary data structure used within the kernel to be read/written from user space, and is a core piece of the legacy interface. All modifications to existing variables are performed via this file by passing a 'struct efi_variable' object,

struct efi_variable {

efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
efi_guid_t VendorGuid;
unsigned long DataSize;
__u8 Data[1024];
efi_status_t Status;
__u32 Attributes;

} __attribute__((packed));

The special files 'new_var' and 'del_var' in the top directory are used, as the names imply, for creating and deleting UEFI variables. These files do not use human-readable text. Instead, 'struct efi_variable' objects are passed back and forth between the kernel and user space, to either create new, or delete existing UEFI variables.

The primary reason for keeping the efivars interface around in the Linux kernel is that there are still tools that will only use this interface: the efibootmgr tool, which is available on all Linux distributions to
control the boot order on UEFI systems, still uses this legacy interface.

However, there are some limitations of the legacy efivars interface which, overtime, have started to become a major headache.

The most apparent shortcoming is that there is an upper limit on the size of UEFI variable data that can be read/written. Because of the way that the kernel data structures were designed, it is not possible to read or write more than 1024 bytes of variable data, and for some use cases, that limit is a problem.

Furthermore, the efivars interface intrinsically requires tools to manipulate UEFI variables because the interface only deals with reading and writing copies of the non-trivial 'struct efi_variable' data structure for a UEFI variable via the 'new_var', 'del_var' and 'raw_var' special files. It is not possible to delete a UEFI variable without building a 'struct efi_variable' object and writing it to the 'del_var' file.

The efivarfs file system

To sidestep the limitations of the legacy efivar interface a brand new Linux file system was created by Matthew Garrett and Jeremy Kerr. This new file system was named "efivarfs" and was part of the Linux kernel v3.10 release.

Like all other Linux file systems, efivarfs must be mounted somewhere to access its files, which can be done by issuing the following command,

mount -t efivarfs none /sys/firmware/efi/efivars

Instead of directories, efivarfs contains files whose names are built from the UEFI variables' name and GUID,

Boot0000-12345678-abcd-abcd-abcd-123456789abc
Boot0001-12345678-abcd-abcd-abcd-123456789abc
BootCurrent-12345678-abcd-abcd-abcd-123456789abc
BootOrder-12345678-abcd-abcd-abcd-123456789abc
BootSetup-12345678-abcd-abcd-abcd-123456789abc

Even though each of the files contains binary data (like the 'new_var', 'del_var' of the legacy interface), the data structure for efivarfs is much simpler, consisting only of 4 bytes for the UEFI variable attributes bitmask, and the rest is the UEFI variable data, e.g.

struct new_efi_variable {

u32 attributes;
u8 data[0];

};

All other pieces of information, such as the variable name, GUID and size are inferred from the filename being read/written. This makes it trivial to create, or delete a UEFI variable by creating or deleting files.

For example, the following shell command creates a new variable,

printf "\x07\x00\x00\x00\x00" > myvar-12345678-1234-1234-1234-123456789abc

named 'myvar' with the GUID '12345678-1234-1234-1234-123456789abc', and the EFI_VARIABLE_NON_VOLATILE, EFI_VARIABLE_BOOTSERVICE_ACCESS and EFI_VARIABLE_RUNTIME_ACCESS bits set in the attribute bitmask, followed by 1 byte of data (the final \x00).

The size of a variable, plus the 4 bytes of attribute data, can be found by using any of the usual methods for getting the size of a file. For example, running the following shell command,

du -b myvar-12345678-1234-1234-1234-12345678abc

will print '5' - that's 4 bytes for the variable attribute bitmask, plus one byte of data.

To delete the variable, simply remove it from the efivarfs file system,

rm myvar-12345678-1234-1234-1234-12345678abc

Clearly, this is a much more intuitive interface for accessing UEFI variables from the command line and from shell scripts. Most importantly, there's no limit on the amount of data that can be read/written for a UEFI variable, unlike with the legacy interface.

Of course, even though the data structure used by efivarfs is much simpler than the legacy interface, it is still read/written as binary data and requires more mental processing than the human readable files provided by the legacy interface.

In this article we have briefly discussed the two solutions that Linux provides for accessing UEFI variables at runtime. While the new efivarfs file system provides a useful interface for accessing UEFI variables from shell scripts (and even from the command line), the legacy interface is still used by some tools, and in some situations the human readable files can be much more useful than the binary only interface of efivarfs.

Matt Fleming is a software engineer at Intel's Open Source Technology Center and the Linux kernel (U)EFI maintainer.