Recently a new filesystem was added to the 3.8 Linux kernel and backported to the Fedora kernel-3.6.10-4.fc18 and others. Here is the scant documentation for it:
efivarfs - a (U)EFI variable filesystem The efivarfs filesystem was created to address the shortcomings of using entries in sysfs to maintain EFI variables. The old sysfs EFI variables code only supported variables of up to 1024 bytes. This limitation existed in version 0.99 of the EFI specification, but was removed before any full releases. Since variables can now be larger than a single page, sysfs isn't the best interface for this. Variables can be created, deleted and modified with the efivarfs filesystem. efivarfs is typically mounted like this, mount -t efivarfs none /sys/firmware/efi/efivars
Currently this filesystem is not automatically mounted on my version of Fedora 18 Beta but probably should be as the appropriate entry should have been added to systemd’s mount-setup.c by now. For the moment, just manually mount it if you wish to use this filesystem.
Here is a simple C program which demonstrates how to use efivarfs to write out an EFI variable to NVRAM, or read or delete an EFI variable from NVRAM.
// // Copyright (c) 2012 Finnbarr P. Murphy. All rights reserved. // // Demo the use of efivarfs to read, write and delete EFI NVRAM variables. // // Parts of the code taken from mokutil and EDK1. // // Writes 12345 to an EFI variable called FPMURPHY with a GUID of EFI_FPMURPHY_GUID // Alternatively read or delete the variable. // #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define EFI_ERROR(x) ((x) | (1L << (BITS_PER_LONG - 1))) #define EFI_SUCCESS 0 #define EFI_INVALID_PARAMETER EFI_ERROR(2) #define EFI_UNSUPPORTED EFI_ERROR(3) #define EFI_BAD_BUFFER_SIZE EFI_ERROR(4) #define EFI_BUFFER_TOO_SMALL EFI_ERROR(5) #define EFI_NOT_FOUND EFI_ERROR(14) #define EFI_OUT_OF_RESOURCES EFI_ERROR(15) #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 typedef struct { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; } efi_guid_t; typedef unsigned long efi_status_t; typedef struct _efi_variable_t { const char *VariableName; efi_guid_t VendorGuid; uint32_t DataSize; uint8_t *Data; uint32_t Attributes; } __attribute__((packed)) efi_variable_t; #define SYSFS_EFI_VARS "/sys/firmware/efi/efivars" #define EFI_FPMURPHY_GUID \ (efi_guid_t) {0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xe8, 0x15, 0xcd, 0x8e, 0x26}} int variable_to_name(efi_variable_t *var, char *name) { char *p = name; efi_guid_t *guid = &(var->VendorGuid); if (!var->VariableName) return -1; strcpy (p, var->VariableName); p += strlen (p); p += sprintf (p, "-"); sprintf(p, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->data1, guid->data2, guid->data3, guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7] ); return strlen (name); } efi_status_t read_variable (efi_variable_t *var) { char name[PATH_MAX]; char filename[PATH_MAX]; int fd; struct stat buf; size_t readsize, datasize; void *buffer; if (!var) return EFI_INVALID_PARAMETER; variable_to_name (var, name); snprintf (filename, PATH_MAX-1, "%s/%s", SYSFS_EFI_VARS, name); fd = open (filename, O_RDONLY); if (fd == -1) { return EFI_NOT_FOUND; } if (fstat (fd, &buf) != 0) { close (fd); return EFI_INVALID_PARAMETER; } readsize = read (fd, &var->Attributes, sizeof(uint32_t)); if (readsize != sizeof(uint32_t)) { close (fd); return EFI_INVALID_PARAMETER; } datasize = buf.st_size - sizeof(uint32_t); buffer = malloc (datasize); if (buffer == NULL) { close (fd); return EFI_OUT_OF_RESOURCES; } readsize = read (fd, buffer, datasize); if (readsize != datasize) { close (fd); free (buffer); return EFI_INVALID_PARAMETER; } var->Data = buffer; var->DataSize = datasize; close (fd); return EFI_SUCCESS; } efi_status_t write_variable (efi_variable_t *var) { int fd; size_t writesize; void *buffer; unsigned long total; char name[PATH_MAX]; char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; variable_to_name(var, name); snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_EFI_VARS, name); if (!filename ) return EFI_INVALID_PARAMETER; buffer = malloc(var->DataSize + sizeof(uint32_t)); if (buffer == NULL) { return EFI_OUT_OF_RESOURCES; } memcpy (buffer, &var->Attributes, sizeof(uint32_t)); memcpy (buffer + sizeof(uint32_t), var->Data, var->DataSize); total = var->DataSize + sizeof(uint32_t); fd = open (filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { free (buffer); return EFI_INVALID_PARAMETER; } writesize = write (fd, buffer, total); if (writesize != total) { free (buffer); close (fd); return EFI_INVALID_PARAMETER; } close (fd); free (buffer); return EFI_SUCCESS; } efi_status_t delete_variable(efi_variable_t *var) { char name[PATH_MAX]; char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; variable_to_name(var, name); snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_EFI_VARS, name); if (unlink (filename) == 0) return EFI_SUCCESS; return EFI_OUT_OF_RESOURCES; } int usage(char *name) { fprintf(stderr, "usage: %s [ -w | --write | -r | --read | -d | --delete]\n", name); exit(1); } int main(int argc, char *argv[]) { efi_variable_t var; uint8_t auth[5]; int status = EFI_SUCCESS; auth[0] = 0; auth[1] = 1; auth[2] = 2; auth[3] = 3; auth[4] = 4; if (argc == 2) { memset (&var, 0, sizeof(var)); var.VariableName = "FPMURPHY"; var.VendorGuid = EFI_FPMURPHY_GUID; if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) { usage(argv[0]); } else if (strcmp (argv[1], "-w") == 0 || strcmp (argv[1], "--write") == 0) { var.Data = auth; var.DataSize = 5; var.Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; if (write_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to write variable: %s\n", var.VariableName); status = 1; } } else if (strcmp (argv[1], "-r") == 0 || strcmp (argv[1], "--read") == 0) { if (read_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to read variable: %s\n", var.VariableName); status = 2; } } else if (strcmp (argv[1], "-d") == 0 || strcmp (argv[1], "--delete") == 0) { if (delete_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to delete variable: %s\n", var.VariableName); status = 3; } } else usage(argv[0]); } else usage(argv[0]); exit(status); }
You need to be root to run this program.
Here is what the EFI dmpstore utility displays for the FPMURPHY variable:
Variable NV+RT+BS '605DAB50-E046-4300-ABB6-3DE815CD8E26:FPMURPHY' DataSize = 5 00000000: 00 01 02 03 04 *.....*
Prior to efivarfs, the “approved” way to access EFI boot variables was by means of the older efivars mechanism created by Matt Domsch starting in 2001. See …/drivers/firmware/efivars.c. This kernel module displays EFI variables in separate directories under /sys/firmware/efi/vars.
Here is the documentation on that module:
This directory exposes interfaces for interactive with EFI variables. For more information on EFI variables, see 'Variable Services' in the UEFI specification (section 7.2 in specification version 2.3 Errata D). In summary, EFI variables are named, and are classified into separate namespaces through the use of a vendor GUID. They also have an arbitrary binary value associated with them. The efivars module enumerates these variables and creates a separate directory for each one found. Each directory has a name of the form "- " and contains the following files: attributes: A read-only text file enumerating the EFI variable flags. Potential values include: EFI_VARIABLE_NON_VOLATILE EFI_VARIABLE_BOOTSERVICE_ACCESS EFI_VARIABLE_RUNTIME_ACCESS EFI_VARIABLE_HARDWARE_ERROR_RECORD EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS See the EFI documentation for an explanation of each of these variables. data: A read-only binary file that can be read to attain the value of the EFI variable guid: The vendor GUID of the variable. This should always match the GUID in the variable's name. raw_var: A binary file that can be read to obtain a structure that contains everything there is to know about the variable. For structure definition see "struct efi_variable" in the kernel sources. This file can also be written to in order to update the value of a variable. For this to work however, all fields of the "struct efi_variable" passed must match byte for byte with the structure read out of the file, save for the value portion. **Note** the efi_variable structure read/written with this file contains a 'long' type that may change widths depending on your underlying architecture. size: As ASCII representation of the size of the variable's value. In addition, two other magic binary files are provided in the top-level directory and are used for adding and removing variables: new_var: Takes a "struct efi_variable" and instructs the EFI firmware to create a new variable. del_var: Takes a "struct efi_variable" and instructs the EFI firmware to remove any variable that has a matching vendor GUID and variable key name.
Here is sample output from /sys/firmware/efi/vars/:
$ ls -F Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c/ BootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c/ BootOptionSupport-8be4df61-93ca-11d2-aa0d-00e098032b8c/ BootOrder-8be4df61-93ca-11d2-aa0d-00e098032b8c/ ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c/ ConInDev-8be4df61-93ca-11d2-aa0d-00e098032b8c/ ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c/ ConOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c/ ErrOutDev-8be4df61-93ca-11d2-aa0d-00e098032b8c/ Lang-8be4df61-93ca-11d2-aa0d-00e098032b8c/ LangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c/ MTC-eb704011-1402-11d3-8e77-00a0c969723b/ MemoryTypeInformation-4c19049f-4137-4dd3-9c10-8b97a83ffdfa/ PlatformLang-8be4df61-93ca-11d2-aa0d-00e098032b8c/ PlatformLangCodes-8be4df61-93ca-11d2-aa0d-00e098032b8c/ RTC-378d7b65-8da9-4773-b6e4-a47826a833e1/ del_var new_var
Note the del_var, new_var and raw_var files! These are special and are binary files.
$ ls -l *_var --w------- 1 root root 0 Dec 25 18:39 del_var --w------- 1 root root 0 Dec 25 18:16 new_var $ cd ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c/ $ ls -l -r-------- 1 root root 4096 Dec 26 15:00 attributes -r-------- 1 root root 4096 Dec 26 15:00 data -r-------- 1 root root 4096 Dec 26 15:00 guid -rw------- 1 root root 4096 Dec 26 15:00 raw_var -r-------- 1 root root 4096 Dec 26 15:00 size
Here is a simple C program which sets the globally defined UEFI boot manager Timeout variable, or reads or deletes the variable, using the efivars mechanism.
// // Copyright (c) 2012 Finnbarr P. Murphy. All rights reserved. // // Demo the use of sysfs to read, write and delete UEFI Timeout variable. // // Parts of the code taken from efibootmgr and EDK1. // #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define EFI_ERROR(x) ((x) | (1L << (BITS_PER_LONG - 1))) #define EFI_SUCCESS 0 #define EFI_INVALID_PARAMETER EFI_ERROR(2) #define EFI_UNSUPPORTED EFI_ERROR(3) #define EFI_BAD_BUFFER_SIZE EFI_ERROR(4) #define EFI_BUFFER_TOO_SMALL EFI_ERROR(5) #define EFI_NOT_FOUND EFI_ERROR(14) #define EFI_OUT_OF_RESOURCES EFI_ERROR(15) #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 typedef struct { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; } efi_guid_t; typedef unsigned long efi_status_t; typedef uint16_t efi_char16_t; /* UCS-2 */ typedef struct _efi_variable_t { efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; unsigned long DataSize; uint8_t Data[1024]; efi_status_t Status; uint32_t Attributes; } __attribute__((packed)) efi_variable_t; #define EFI_GLOBAL_VARIABLE \ (efi_guid_t) {0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C}} #define SYSFS_EFI_VARS "/sys/firmware/efi/vars" unsigned long efichar_from_char(efi_char16_t *dest, const char *src, size_t dest_len) { int i, src_len = strlen(src); for (i = 0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) dest[i] = src[i]; dest[i] = 0; return (i * sizeof(*dest)); } unsigned long efichar_to_char(char *dest, const efi_char16_t *src, size_t dest_len) { int i, src_len = efichar_strlen(src, -1); for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) dest[i] = src[i]; dest[i] = 0; return i; } int efichar_strlen(const efi_char16_t *p, int max) { int len = 0; const efi_char16_t *start = p; if (!p || !*p) return 0; while ((max < 0 || p - start < max) && *(p+len)) ++len; return len; } void guid_to_string(efi_guid_t *guid, char *out) { sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->data1, guid->data2, guid->data3, guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3], guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7] ); } int variable_to_name(efi_variable_t *var, char *name) { char *p = name; efi_guid_t *guid = &(var->VendorGuid); if (!var->VariableName) return -1; efichar_to_char(p, var->VariableName, PATH_MAX); p += strlen (p); p += sprintf (p, "-"); guid_to_string(guid, p); return strlen (name); } void fill_var(efi_variable_t *var, const char *name) { efi_guid_t guid = EFI_GLOBAL_VARIABLE; efichar_from_char(var->VariableName, name, 1024); memcpy(&var->VendorGuid, &guid, sizeof(guid)); var->Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; } efi_status_t read_variable(const char *name, efi_variable_t *var) { char filename[PATH_MAX]; int fd; size_t readsize; if (!name || !var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_EFI_VARS, name); fd = open(filename, O_RDONLY); if (fd == -1) { return EFI_NOT_FOUND; } readsize = read(fd, var, sizeof(*var)); if (readsize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return var->Status; } efi_status_t write_variable(const char *filename, efi_variable_t *var) { int fd; size_t writesize; char buffer[PATH_MAX+40]; if (!filename || !var) return EFI_INVALID_PARAMETER; memset(buffer, 0, sizeof(buffer)); fd = open(filename, O_WRONLY); if (fd == -1) { return EFI_INVALID_PARAMETER; } writesize = write(fd, var, sizeof(*var)); if (writesize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return EFI_SUCCESS; } efi_status_t edit_variable(efi_variable_t *var) { char name[PATH_MAX]; char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; variable_to_name(var, name); snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_EFI_VARS,name); return write_variable(filename, var); } efi_status_t create_variable(efi_variable_t *var) { char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_EFI_VARS,"new_var"); return write_variable(filename, var); } efi_status_t delete_variable(const char *name) { efi_variable_t var; char filename[PATH_MAX]; memset(&var, 0, sizeof(var)); fill_var(&var, name); if (!&var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_EFI_VARS,"del_var"); return write_variable(filename, &var); } efi_status_t create_or_edit_variable(efi_variable_t *var) { efi_variable_t testvar; char name[PATH_MAX]; memcpy(&testvar, var, sizeof(*var)); variable_to_name(var, name); if (read_variable(name, &testvar) == EFI_SUCCESS) return edit_variable(var); else return create_variable(var); } efi_status_t set_timeout(uint16_t num) { efi_variable_t var; uint16_t *n = (uint16_t *)var.Data; memset(&var, 0, sizeof(var)); fill_var(&var, "Timeout"); *n = num; var.DataSize = sizeof(uint16_t); return create_or_edit_variable(&var); } int get_timeout() { efi_guid_t guid = EFI_GLOBAL_VARIABLE; efi_status_t status; efi_variable_t var; char name_guid[PATH_MAX]; uint16_t *n = (uint16_t *)(var.Data); char timeout_uuid[40]; memset(&var, 0, sizeof(var)); guid_to_string(&guid, timeout_uuid); snprintf(name_guid, sizeof(name_guid), "%s-%s", "Timeout", timeout_uuid); status = read_variable(name_guid, &var); if (status) return -1; return *n; } int usage(char *name) { fprintf(stderr, "usage: %s [ -w | --write | -r | --read | -d | --delete]\n", name); exit(1); } int main(int argc, char *argv[]) { efi_variable_t var; efi_guid_t guid = EFI_GLOBAL_VARIABLE; int status = EFI_SUCCESS; int num; if (argc == 2) { if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) { usage(argv[0]); } else if (strcmp (argv[1], "-w") == 0 || strcmp (argv[1], "--write") == 0) { set_timeout(5); } else if (strcmp (argv[1], "-r") == 0 || strcmp (argv[1], "--read") == 0) { num = get_timeout(); if (num != -1) { printf("Timeout: %u seconds\n", num); } } else if (strcmp (argv[1], "-d") == 0 || strcmp (argv[1], "--delete") == 0) { delete_variable("Timeout"); } else usage(argv[0]); } else usage(argv[0]); exit(status); }
Note the maximum size of VariableName + Data = 1024 in efivars. This comes from an older EFI specification (0.99).
In my opinion, the older efivars mechanism should be retired and utilities which make use of this mechanism should be re-written to use efivarfs. A number of lines of code could then be removed from the kernel source! As far as I can ascertain, only the following utilities and tools use the efivars mechanism:
- efibootmgr – Written by Matt XXXXXX. Used to create, modify or delete UEFI boot variables.
- uefivars – Written by me. ~imply dumps the UEFI Boot variables.
- Ubuntu Firmware Test Suite – fwts, uefidump.
Note that you cannot use efivars for writing your own EFI variables to NVRAM. This is because the kernel module does extensive checking to ensure only a specific set of variables (EFI boot-related variables) can be accessed.
static const struct variable_validate variable_validate[] = { { "BootNext", validate_uint16 }, { "BootOrder", validate_boot_order }, { "DriverOrder", validate_boot_order }, { "Boot*", validate_load_option }, { "Driver*", validate_load_option }, { "ConIn", validate_device_path }, { "ConInDev", validate_device_path }, { "ConOut", validate_device_path }, { "ConOutDev", validate_device_path }, { "ErrOut", validate_device_path }, { "ErrOutDev", validate_device_path }, { "Timeout", validate_uint16 }, { "Lang", validate_ascii_string }, { "PlatformLang", validate_ascii_string }, { "", NULL }, };
And for each of these “permitted” variables, extensive validation is performed in the kernel module on the value that you wish to set the variable to. For example, here is the validate_load_option validation routine for BootXXXX and DriverXXXX variables:
static bool validate_load_option(struct efi_variable *var, int match, u8 *buffer, unsigned long len) { u16 filepathlength; int i, desclength = 0, namelen; namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName)); /* Either "Boot" or "Driver" followed by four digits of hex */ for (i = match; i < match+4; i++) { if (var->VariableName[i] > 127 || hex_to_bin(var->VariableName[i] & 0xff) < 0) return true; } /* Reject it if there's 4 digits of hex and then further content */ if (namelen > match + 4) return false; /* A valid entry must be at least 8 bytes */ if (len < 8) return false; filepathlength = buffer[4] | buffer[5] << 8; /* * There's no stored length for the description, so it has to be * found by hand */ desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; /* Each boot entry must have a descriptor */ if (!desclength) return false; /* * If the sum of the length of the description, the claimed filepath * length and the original header are greater than the length of the * variable, it's malformed */ if ((desclength + filepathlength + 6) > len) return false; /* * And, finally, check the filepath */ return validate_device_path(var, match, buffer + desclength + 6, filepathlength); }
Why these checks and validation were not performed in the efibootmgr utility rather than in the kernel module is a mystery since that would have been the logical place to do this type of operation rather than in the efivars kernel module. By the way efivars is nowadays (since 2009?) built into the kernel and is no longer a standalone kernel module.
If the efivars mechanism is retired, kernel developers would also have to modify the efi_pstore_* functions to use efivarfs. These routines, which I have written about in a previous post, enable generic access to platform level persistent storage, i.e. UEFI NVRAM. The routines are used to create EFI variables of the form “dump-type
Another item made available through efivars is /sys/firmware/efi/systab
# cat systab MPS=0xfc8d0 ACPI20=0xda7b1000 ACPI=0xda7b1000 SMBIOS=0xf0480
This comes from the following function in efivars.c:
static ssize_t systab_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char *str = buf; if (!kobj || !buf) return -EINVAL; if (efi.mps != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "MPS=0x%lx\n", efi.mps); if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20); if (efi.acpi != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "ACPI=0x%lx\n", efi.acpi); if (efi.smbios != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios); if (efi.hcdp != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp); if (efi.boot_info != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info); if (efi.uga != EFI_INVALID_TABLE_ADDR) str += sprintf(str, "UGA=0x%lx\n", efi.uga); return str - buf; }
I am unaware of any utility or application which is using this file to access such information.
Well, that is all for this post. I think I have provided you with sufficient information to understand how to use both the new efivarfs filesystem and older efivars mechanism to create, read, write and delete (U)EFI variables.
Merry Christmas and a Happy New Year to all my readers!
Nice post. Do you have any patches for efibootmgr that makes it work with efivarfs (and prefer /sys/firmware/efi/efivars over /sys/firmware/efi/vars if possible)?
Thank you. Yes, I have a working prototype. However, I want to run it past Matt Domsch before I release it as I want to also revamp all the command line options to make the utility more intuitive to use.
I would love to test it in my Thinkpad Edge E430. Can you upload your modified efibootmgr source to some git site (maybe your github page)? BTW the current upstream maintainer of efibootmgr is Jordan Hargrave, not Matt Domsch.
What is the status of your efibootmgr and uefivars support for efivarfs?
Can you also make efibootmgr automatically detect the file path of the loader file in efisys like the way gummiboot’s setup utility does, like (with unix-style path separator so that it is easy to use in bash scripts)
efibootmgr -c -l /boot/efi/EFI/tools/shellx64.efi -L Shell
instead of
efibootmgr -c -d /dev/sda -p 1 -l \EFI\tools\shellx64.efi -L Shell
Any update on your efibootmgr fork? Please see https://github.com/fpmurphy/Various/issues/1 for my comments.