Pull request efi-2024-07-rc1-3

Documentation:
 
 * sort env sub-commands alphabetically
 * update list of aliases for the env command
 
 UEFI:
 
 * allow enabling SetVariable at runtime
   for future OS supported writing to ubootefi.var
 * use event callback for initrd deregistration
 
 Others:
 
 * correct alignment of x86 firmware tables
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEK7wKXt3/btL6/yA+hO4vgnE3U0sFAmYjhhUACgkQhO4vgnE3
 U0txexAAyA7uYklnrlTWp+gmLvdcKIRMlN74CiESHfmGBZHjtQlk2mfmnl5sy0R4
 2U1ulT0VwQPiltHH2X+0BY7/QgU92iAWNC++IWUjxHLsPhGnGBPkl3phFHRd1bLm
 fk6h5KEIvsXZnWbIOGlXCzgvarja4nHE8Y2rzUW6yJf+gfNVMdPodn+1g8p8t84r
 SDr+r1Fb2L4RZAsfOgXe/1Sa7bBkoRjiTcEOEh+o0BOIZLh4TMvSyY9PZ3TUTHeL
 ua/YmxsevWl3pCI+XW06ePIpkKAMuwU2bnV0RBd1L+SZR1FXffjkRti4dEQZBJ0U
 BAEVf3WjjnWC9FnwZOSMSFjDDwlqqi0Y77vqOXEJWbY27muW4mF1q1npv/Zamqa7
 O+T+4bl7Kd5VeZafY9CAZXdtaImvsY5CWnop7W2rLE+NgUrShz5cvOj7BT00L4+i
 q2ExSeQxW+fVQqkFKzp6Kcm5SDTVnJfYtknEEYseiFvAp2wz229fV24bWfh5Gidn
 03iU3YW4Oc+m1rSeSEmyJ/Yr57lmLdP6PF42hIRpiT/a/FHjXX1oOwvpjxBGr4gl
 S4LgfO69GuY5uO6ABacldlJ79SHTF9yuhqmwTRXj34+yY7I6Lb+pMqToXIJ9iZMx
 YaptdlEJlE9iYDAWM5TwoKp3ATZH9EYOQcJxlp/bFHHVrPBZeGc=
 =7YWW
 -----END PGP SIGNATURE-----

Merge tag 'efi-2024-07-rc1-3' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request efi-2024-07-rc1-3

Documentation:

* sort env sub-commands alphabetically
* update list of aliases for the env command

UEFI:

* allow enabling SetVariable at runtime
  for future OS supported writing to ubootefi.var
* use event callback for initrd deregistration

Others:

* correct alignment of x86 firmware tables
This commit is contained in:
Tom Rini 2024-04-20 08:19:20 -06:00
commit b064bb66a1
15 changed files with 591 additions and 139 deletions

View File

@ -98,6 +98,8 @@ int write_tables(void)
int size = table->size ? : CONFIG_ROM_TABLE_SIZE;
u32 rom_table_end;
rom_addr = ALIGN(rom_addr, 16);
if (!strcmp("smbios", table->name))
gd->arch.smbios_start = rom_addr;

View File

@ -1419,7 +1419,7 @@ static efi_status_t eficonfig_edit_boot_option(u16 *varname, struct eficonfig_bo
}
bo->initrd_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
if (!bo->file_info.current_path) {
if (!bo->initrd_info.current_path) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}

View File

@ -16,18 +16,18 @@ Synopsis
env default [-f] (-a | var [...])
env delete [-f] var [...]
env edit name
env erase
env exists name
env export [-t | -b | -c] [-s size] addr [var ...]
env flags
env grep [-e] [-n | -v | -b] string [...]
env import [-d] [-t [-r] | -b | -c] addr [size] [var ...]
env info [-d] [-p] [-q]
env load
env print [-a | name ...]
env print -e [-guid guid] [-n] [name ...]
env run var [...]
env save
env erase
env load
env select [target]
env set [-f] name [value]
env set -e [-nv][-bs][-rt][-at][-a][-i addr:size][-v] name [value]
@ -40,11 +40,12 @@ the UEFI variables.
The next commands are kept as alias and for compatibility:
+ :doc:`askenv <askenv>` = *env ask*
+ *editenv* = *env edit*
+ *grepenv* = *env grep*
+ *setenv* = *env set*
+ *askenv* = *env ask*
+ :doc:`printenv <printenv>` = *env print*
+ *run* = *env run*
+ *setenv* = *env set*
Ask
~~~
@ -103,6 +104,11 @@ The *env edit* command edits an environment variable.
name
name of the variable.
Erase
~~~~~
The *env erase* command erases the U-Boot environment.
Exists
~~~~~~
@ -204,6 +210,11 @@ environment information.
quiet output, use only for command result, by example with
'test' command.
Load
~~~~
The *env load* command loads the U-Boot environment from persistent storage.
Print
~~~~~
@ -235,16 +246,6 @@ Save
The *env save* command saves the U-Boot environment in persistent storage.
Erase
~~~~~
The *env erase* command erases the U-Boot environment.
Load
~~~~
The *env load* command loads the U-Boot environment from persistent storage.
Select
~~~~~~
@ -350,15 +351,15 @@ edit
exists
CONFIG_CMD_ENV_EXISTS
flags
CONFIG_CMD_ENV_FLAGS
erase
CONFIG_CMD_ERASEENV
export
CONFIG_CMD_EXPORTENV
flags
CONFIG_CMD_ENV_FLAGS
grep
CONFIG_CMD_GREPENV, CONFIG_REGEX for '-e' option

View File

@ -159,6 +159,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr,
#define EFICONFIG_AUTO_GENERATED_ENTRY_GUID \
EFI_GUID(0x8108ac4e, 0x9f11, 0x4d59, \
0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2)
#define U_BOOT_EFI_RT_VAR_FILE_GUID \
EFI_GUID(0xb2ac5fc9, 0x92b7, 0x4acd, \
0xae, 0xac, 0x11, 0xe8, 0x18, 0xc3, 0x13, 0x0c)
/* Use internal device tree when starting UEFI application */
#define EFI_FDT_USE_INTERNAL NULL

View File

@ -271,13 +271,16 @@ const efi_guid_t *efi_auth_var_get_guid(const u16 *name);
*
* @variable_name_size: size of variable_name buffer in bytes
* @variable_name: name of uefi variable's name in u16
* @mask: bitmask with required attributes of variables to be collected.
* variables are only collected if all of the required
* attributes match. Use 0 to skip matching
* @vendor: vendor's guid
*
* Return: status code
*/
efi_status_t __efi_runtime
efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name,
efi_guid_t *vendor);
efi_guid_t *vendor, u32 mask);
/**
* efi_get_variable_mem() - Runtime common code across efi variable
* implementations for GetVariable() from
@ -289,12 +292,15 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_na
* @data_size: size of the buffer to which the variable value is copied
* @data: buffer to which the variable value is copied
* @timep: authentication time (seconds since start of epoch)
* @mask: bitmask with required attributes of variables to be collected.
* variables are only collected if all of the required
* attributes match. Use 0 to skip matching
* Return: status code
*/
efi_status_t __efi_runtime
efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep);
u64 *timep, u32 mask);
/**
* efi_get_variable_runtime() - runtime implementation of GetVariable()
@ -334,4 +340,10 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
*/
void efi_var_buf_update(struct efi_var_file *var_buf);
efi_status_t __efi_runtime efi_var_collect_mem(struct efi_var_file *buf,
efi_uintn_t *lenp,
u32 check_attr_mask);
u32 efi_var_entry_len(struct efi_var_entry *var);
#endif

View File

@ -387,7 +387,7 @@ int u16_strcasecmp(const u16 *s1, const u16 *s2)
* > 0 if the first different u16 in s1 is greater than the
* corresponding u16 in s2
*/
int u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
int __efi_runtime u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
{
int ret = 0;

View File

@ -62,6 +62,22 @@ config EFI_VARIABLE_FILE_STORE
Select this option if you want non-volatile UEFI variables to be
stored as file /ubootefi.var on the EFI system partition.
config EFI_RT_VOLATILE_STORE
bool "Allow variable runtime services in volatile storage (e.g RAM)"
depends on EFI_VARIABLE_FILE_STORE
help
When EFI variables are stored on file we don't allow SetVariableRT,
since the OS doesn't know how to write that file. At he same time
we copy runtime variables in DRAM and support GetVariableRT
Enable this option to allow SetVariableRT on the RAM backend of
the EFI variable storage. The OS will be responsible for syncing
the RAM contents to the file, otherwise any changes made during
runtime won't persist reboots.
Authenticated variables are not supported. Note that this will
violate the EFI spec since writing auth variables will return
EFI_INVALID_PARAMETER
config EFI_MM_COMM_TEE
bool "UEFI variables storage service via the trusted world"
depends on OPTEE

View File

@ -549,11 +549,6 @@ efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
out:
free(load_options);
if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
if (efi_initrd_deregister() != EFI_SUCCESS)
log_err("Failed to remove loadfile2 for initrd\n");
}
/* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
list_for_each_entry(evt, &efi_events, link) {
if (evt->group &&

View File

@ -183,41 +183,6 @@ out:
return ret;
}
/**
* efi_initrd_register() - create handle for loading initial RAM disk
*
* This function creates a new handle and installs a Linux specific vendor
* device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path
* to identify the handle and then calls the LoadFile service of the
* EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk.
*
* Return: status code
*/
efi_status_t efi_initrd_register(void)
{
efi_status_t ret;
/*
* Allow the user to continue if Boot#### file path is not set for
* an initrd
*/
ret = check_initrd();
if (ret == EFI_INVALID_PARAMETER)
return EFI_SUCCESS;
if (ret != EFI_SUCCESS)
return ret;
ret = efi_install_multiple_protocol_interfaces(&efi_initrd_handle,
/* initramfs */
&efi_guid_device_path, &dp_lf2_handle,
/* LOAD_FILE2 */
&efi_guid_load_file2_protocol,
&efi_lf2_protocol,
NULL);
return ret;
}
/**
* efi_initrd_deregister() - delete the handle for loading initial RAM disk
*
@ -245,3 +210,66 @@ efi_status_t efi_initrd_deregister(void)
return ret;
}
/**
* efi_initrd_return_notify() - return to efibootmgr callback
*
* @event: the event for which this notification function is registered
* @context: event context
*/
static void EFIAPI efi_initrd_return_notify(struct efi_event *event,
void *context)
{
efi_status_t ret;
EFI_ENTRY("%p, %p", event, context);
ret = efi_initrd_deregister();
EFI_EXIT(ret);
}
/**
* efi_initrd_register() - create handle for loading initial RAM disk
*
* This function creates a new handle and installs a Linux specific vendor
* device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path
* to identify the handle and then calls the LoadFile service of the
* EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk.
*
* Return: status code
*/
efi_status_t efi_initrd_register(void)
{
efi_status_t ret;
struct efi_event *event;
/*
* Allow the user to continue if Boot#### file path is not set for
* an initrd
*/
ret = check_initrd();
if (ret == EFI_INVALID_PARAMETER)
return EFI_SUCCESS;
if (ret != EFI_SUCCESS)
return ret;
ret = efi_install_multiple_protocol_interfaces(&efi_initrd_handle,
/* initramfs */
&efi_guid_device_path, &dp_lf2_handle,
/* LOAD_FILE2 */
&efi_guid_load_file2_protocol,
&efi_lf2_protocol,
NULL);
if (ret != EFI_SUCCESS) {
log_err("installing EFI_LOAD_FILE2_PROTOCOL failed\n");
return ret;
}
ret = efi_create_event(EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
efi_initrd_return_notify, NULL,
&efi_guid_event_group_return_to_efibootmgr,
&event);
if (ret != EFI_SUCCESS)
log_err("Creating event failed\n");
return ret;
}

View File

@ -10,6 +10,7 @@
#include <dm.h>
#include <elf.h>
#include <efi_loader.h>
#include <efi_variable.h>
#include <log.h>
#include <malloc.h>
#include <rtc.h>
@ -110,6 +111,7 @@ static __efi_runtime_data efi_uintn_t efi_descriptor_size;
*/
efi_status_t efi_init_runtime_supported(void)
{
const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID;
efi_status_t ret;
struct efi_rt_properties_table *rt_table;
@ -127,6 +129,46 @@ efi_status_t efi_init_runtime_supported(void)
EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP |
EFI_RT_SUPPORTED_CONVERT_POINTER;
if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
u8 s = 0;
ret = efi_set_variable_int(u"RTStorageVolatile",
&efi_guid_efi_rt_var_file,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_READ_ONLY,
sizeof(EFI_VAR_FILE_NAME),
EFI_VAR_FILE_NAME, false);
if (ret != EFI_SUCCESS) {
log_err("Failed to set RTStorageVolatile\n");
return ret;
}
/*
* This variable needs to be visible so users can read it,
* but the real contents are going to be filled during
* GetVariable
*/
ret = efi_set_variable_int(u"VarToFile",
&efi_guid_efi_rt_var_file,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_READ_ONLY,
sizeof(s),
&s, false);
if (ret != EFI_SUCCESS) {
log_err("Failed to set VarToFile\n");
efi_set_variable_int(u"RTStorageVolatile",
&efi_guid_efi_rt_var_file,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_READ_ONLY,
0, NULL, false);
return ret;
}
rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE;
}
/*
* This value must be synced with efi_runtime_detach_list
* as well as efi_runtime_services.

View File

@ -182,7 +182,8 @@ efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
{
efi_status_t ret;
ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL);
ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
/* Remove EFI_VARIABLE_READ_ONLY flag */
if (attributes)
@ -195,7 +196,8 @@ efi_status_t __efi_runtime EFIAPI
efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
u16 *variable_name, efi_guid_t *guid)
{
return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid);
return efi_get_next_variable_name_mem(variable_name_size, variable_name,
guid, EFI_VARIABLE_RUNTIME_ACCESS);
}
/**
@ -419,7 +421,7 @@ void *efi_get_var(const u16 *name, const efi_guid_t *vendor, efi_uintn_t *size)
}
/**
* efi_var_collect() - Copy EFI variables mstching attributes mask
* efi_var_collect() - Copy EFI variables matching attributes mask
*
* @bufp: buffer containing variable collection
* @lenp: buffer length

View File

@ -61,6 +61,23 @@ efi_var_mem_compare(struct efi_var_entry *var, const efi_guid_t *guid,
return match;
}
/**
* efi_var_entry_len() - Get the entry len including headers & name
*
* @var: pointer to variable start
*
* Return: 8-byte aligned variable entry length
*/
u32 __efi_runtime efi_var_entry_len(struct efi_var_entry *var)
{
if (!var)
return 0;
return ALIGN((sizeof(u16) * (u16_strlen(var->name) + 1)) +
var->length + sizeof(*var), 8);
}
struct efi_var_entry __efi_runtime
*efi_var_mem_find(const efi_guid_t *guid, const u16 *name,
struct efi_var_entry **next)
@ -184,53 +201,6 @@ u64 __efi_runtime efi_var_mem_free(void)
sizeof(struct efi_var_entry);
}
/**
* efi_var_mem_bs_del() - delete boot service only variables
*/
static void efi_var_mem_bs_del(void)
{
struct efi_var_entry *var = efi_var_buf->var;
for (;;) {
struct efi_var_entry *last;
last = (struct efi_var_entry *)
((uintptr_t)efi_var_buf + efi_var_buf->length);
if (var >= last)
break;
if (var->attr & EFI_VARIABLE_RUNTIME_ACCESS) {
u16 *data;
/* skip variable */
for (data = var->name; *data; ++data)
;
++data;
var = (struct efi_var_entry *)
ALIGN((uintptr_t)data + var->length, 8);
} else {
/* delete variable */
efi_var_mem_del(var);
}
}
}
/**
* efi_var_mem_notify_exit_boot_services() - ExitBootService callback
*
* @event: callback event
* @context: callback context
*/
static void EFIAPI
efi_var_mem_notify_exit_boot_services(struct efi_event *event, void *context)
{
EFI_ENTRY("%p, %p", event, context);
/* Delete boot service only variables */
efi_var_mem_bs_del();
EFI_EXIT(EFI_SUCCESS);
}
/**
* efi_var_mem_notify_exit_boot_services() - SetVirtualMemoryMap callback
*
@ -261,11 +231,7 @@ efi_status_t efi_var_mem_init(void)
efi_var_buf->magic = EFI_VAR_FILE_MAGIC;
efi_var_buf->length = (uintptr_t)efi_var_buf->var -
(uintptr_t)efi_var_buf;
/* crc32 for 0 bytes = 0 */
ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
efi_var_mem_notify_exit_boot_services, NULL,
NULL, &event);
if (ret != EFI_SUCCESS)
return ret;
ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_CALLBACK,
@ -276,10 +242,71 @@ efi_status_t efi_var_mem_init(void)
return ret;
}
/**
* efi_var_collect_mem() - Copy EFI variables matching attributes mask from
* efi_var_buf
*
* @buf: buffer containing variable collection
* @lenp: buffer length
* @mask: mask of matched attributes
*
* Return: Status code
*/
efi_status_t __efi_runtime
efi_var_collect_mem(struct efi_var_file *buf, efi_uintn_t *lenp, u32 mask)
{
static struct efi_var_file __efi_runtime_data hdr = {
.magic = EFI_VAR_FILE_MAGIC,
};
struct efi_var_entry *last, *var, *var_to;
hdr.length = sizeof(struct efi_var_file);
var = efi_var_buf->var;
last = (struct efi_var_entry *)
((uintptr_t)efi_var_buf + efi_var_buf->length);
if (buf)
var_to = buf->var;
while (var < last) {
u32 len = efi_var_entry_len(var);
if ((var->attr & mask) != mask) {
var = (void *)((uintptr_t)var + len);
continue;
}
hdr.length += len;
if (buf && hdr.length <= *lenp) {
efi_memcpy_runtime(var_to, var, len);
var_to = (void *)var_to + len;
}
var = (void *)var + len;
}
if (!buf && hdr.length <= *lenp) {
*lenp = hdr.length;
return EFI_INVALID_PARAMETER;
}
if (!buf || hdr.length > *lenp) {
*lenp = hdr.length;
return EFI_BUFFER_TOO_SMALL;
}
hdr.crc32 = crc32(0, (u8 *)buf->var,
hdr.length - sizeof(struct efi_var_file));
efi_memcpy_runtime(buf, &hdr, sizeof(hdr));
*lenp = hdr.length;
return EFI_SUCCESS;
}
efi_status_t __efi_runtime
efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep)
u64 *timep, u32 mask)
{
efi_uintn_t old_size;
struct efi_var_entry *var;
@ -291,11 +318,22 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
if (!var)
return EFI_NOT_FOUND;
/*
* This function is used at runtime to dump EFI variables.
* The memory backend we keep around has BS-only variables as
* well. At runtime we filter them here
*/
if (mask && !((var->attr & mask) == mask))
return EFI_NOT_FOUND;
if (attributes)
*attributes = var->attr;
if (timep)
*timep = var->time;
if (!u16_strcmp(variable_name, u"VarToFile"))
return efi_var_collect_mem(data, data_size, EFI_VARIABLE_NON_VOLATILE);
old_size = *data_size;
*data_size = var->length;
if (old_size < var->length)
@ -315,7 +353,8 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor,
efi_status_t __efi_runtime
efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
u16 *variable_name, efi_guid_t *vendor)
u16 *variable_name, efi_guid_t *vendor,
u32 mask)
{
struct efi_var_entry *var;
efi_uintn_t len, old_size;
@ -324,6 +363,7 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
if (!variable_name_size || !variable_name || !vendor)
return EFI_INVALID_PARAMETER;
skip:
len = *variable_name_size >> 1;
if (u16_strnlen(variable_name, len) == len)
return EFI_INVALID_PARAMETER;
@ -347,6 +387,11 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size,
efi_memcpy_runtime(variable_name, var->name, *variable_name_size);
efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t));
if (mask && !((var->attr & mask) == mask)) {
*variable_name_size = old_size;
goto skip;
}
return EFI_SUCCESS;
}

View File

@ -209,27 +209,32 @@ efi_get_variable_int(const u16 *variable_name, const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size, void *data,
u64 *timep)
{
return efi_get_variable_mem(variable_name, vendor, attributes, data_size, data, timep);
return efi_get_variable_mem(variable_name, vendor, attributes, data_size,
data, timep, 0);
}
efi_status_t __efi_runtime
efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
u16 *variable_name, efi_guid_t *vendor)
{
return efi_get_next_variable_name_mem(variable_name_size, variable_name, vendor);
return efi_get_next_variable_name_mem(variable_name_size, variable_name,
vendor, 0);
}
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data, bool ro_check)
/**
* setvariable_allowed() - checks defined by the UEFI spec for setvariable
*
* @variable_name: name of the variable
* @vendor: vendor GUID
* @attributes: attributes of the variable
* @data_size: size of the buffer with the variable value
* @data: buffer with the variable value
* Return: status code
*/
static efi_status_t __efi_runtime
setvariable_allowed(const u16 *variable_name, const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size, const void *data)
{
struct efi_var_entry *var;
efi_uintn_t ret;
bool append, delete;
u64 time = 0;
enum efi_auth_var_type var_type;
if (!variable_name || !*variable_name || !vendor)
return EFI_INVALID_PARAMETER;
@ -261,6 +266,25 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
!(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)))
return EFI_INVALID_PARAMETER;
return EFI_SUCCESS;
}
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data, bool ro_check)
{
struct efi_var_entry *var;
efi_uintn_t ret;
bool append, delete;
u64 time = 0;
enum efi_auth_var_type var_type;
ret = setvariable_allowed(variable_name, vendor, attributes, data_size,
data);
if (ret != EFI_SUCCESS)
return ret;
/* check if a variable exists */
var = efi_var_mem_find(vendor, variable_name, NULL);
append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
@ -454,7 +478,79 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
u32 attributes, efi_uintn_t data_size,
const void *data)
{
return EFI_UNSUPPORTED;
struct efi_var_entry *var;
efi_uintn_t ret;
bool append, delete;
u64 time = 0;
if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE))
return EFI_UNSUPPORTED;
/*
* Authenticated variables are not supported. The EFI spec
* in §32.3.6 requires keys to be stored in non-volatile storage which
* is tamper and delete resistant.
* The rest of the checks are in setvariable_allowed()
*/
if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
return EFI_INVALID_PARAMETER;
ret = setvariable_allowed(variable_name, vendor, attributes, data_size,
data);
if (ret != EFI_SUCCESS)
return ret;
/* check if a variable exists */
var = efi_var_mem_find(vendor, variable_name, NULL);
append = !!(attributes & EFI_VARIABLE_APPEND_WRITE);
attributes &= ~EFI_VARIABLE_APPEND_WRITE;
delete = !append && (!data_size || !attributes);
/* BS only variables are hidden deny writing them */
if (!delete && !(attributes & EFI_VARIABLE_RUNTIME_ACCESS))
return EFI_INVALID_PARAMETER;
if (var) {
if (var->attr & EFI_VARIABLE_READ_ONLY ||
!(var->attr & EFI_VARIABLE_NON_VOLATILE))
return EFI_WRITE_PROTECTED;
/* attributes won't be changed */
if (!delete && (((var->attr & ~EFI_VARIABLE_READ_ONLY) !=
(attributes & ~EFI_VARIABLE_READ_ONLY))))
return EFI_INVALID_PARAMETER;
time = var->time;
} else {
if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
return EFI_INVALID_PARAMETER;
if (append && !data_size)
return EFI_SUCCESS;
if (delete)
return EFI_NOT_FOUND;
}
if (delete) {
/* EFI_NOT_FOUND has been handled before */
attributes = var->attr;
ret = EFI_SUCCESS;
} else if (append && var) {
u16 *old_data = (void *)((uintptr_t)var->name +
sizeof(u16) * (u16_strlen(var->name) + 1));
ret = efi_var_mem_ins(variable_name, vendor, attributes,
var->length, old_data, data_size, data,
time);
} else {
ret = efi_var_mem_ins(variable_name, vendor, attributes,
data_size, data, 0, NULL, time);
}
if (ret != EFI_SUCCESS)
return ret;
/* We are always inserting new variables, get rid of the old copy */
efi_var_mem_del(var);
return EFI_SUCCESS;
}
/**

View File

@ -959,11 +959,6 @@ void efi_variables_boot_exit_notify(void)
log_err("Unable to notify the MM partition for ExitBootServices\n");
free(comm_buf);
/*
* Populate the list for runtime variables.
* asking EFI_VARIABLE_RUNTIME_ACCESS is redundant, since
* efi_var_mem_notify_exit_boot_services will clean those, but that's fine
*/
ret = efi_var_collect(&var_buf, &len, EFI_VARIABLE_RUNTIME_ACCESS);
if (ret != EFI_SUCCESS)
log_err("Can't populate EFI variables. No runtime variables will be available\n");

View File

@ -10,6 +10,8 @@
*/
#include <efi_selftest.h>
#include <efi_variable.h>
#include <u-boot/crc.h>
#define EFI_ST_MAX_DATA_SIZE 16
#define EFI_ST_MAX_VARNAME_SIZE 40
@ -17,6 +19,8 @@
static struct efi_boot_services *boottime;
static struct efi_runtime_services *runtime;
static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID;
static const efi_guid_t __efi_runtime_data efi_rt_var_guid =
U_BOOT_EFI_RT_VAR_FILE_GUID;
/*
* Setup unit test.
@ -41,15 +45,18 @@ static int setup(const efi_handle_t img_handle,
static int execute(void)
{
efi_status_t ret;
efi_uintn_t len;
efi_uintn_t len, avail, append_len = 17;
u32 attr;
u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
u8 v2[CONFIG_EFI_VAR_BUF_SIZE];
u8 data[EFI_ST_MAX_DATA_SIZE];
u8 data2[CONFIG_EFI_VAR_BUF_SIZE];
u16 varname[EFI_ST_MAX_VARNAME_SIZE];
efi_guid_t guid;
u64 max_storage, rem_storage, max_size;
memset(v2, 0x1, sizeof(v2));
ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS,
&max_storage, &rem_storage,
&max_size);
@ -62,9 +69,216 @@ static int execute(void)
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
3, v + 4);
if (ret != EFI_UNSUPPORTED) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
efi_uintn_t prev_len, delta;
struct efi_var_entry *var;
struct efi_var_file *hdr;
/* At runtime only non-volatile variables may be set. */
if (ret != EFI_INVALID_PARAMETER) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* runtime atttribute must be set */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
3, v + 4);
if (ret != EFI_INVALID_PARAMETER) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
len = sizeof(data);
ret = runtime->get_variable(u"RTStorageVolatile",
&efi_rt_var_guid,
&attr, &len, data);
if (ret != EFI_SUCCESS) {
efi_st_error("GetVariable failed\n");
return EFI_ST_FAILURE;
}
if (len != sizeof(EFI_VAR_FILE_NAME) ||
memcmp(data, EFI_VAR_FILE_NAME, sizeof(EFI_VAR_FILE_NAME))) {
data[len - 1] = 0;
efi_st_error("RTStorageVolatile = %s\n", data);
return EFI_ST_FAILURE;
}
len = sizeof(data2);
ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
&attr, &len, data2);
if (ret != EFI_SUCCESS) {
efi_st_error("GetVariable failed\n");
return EFI_ST_FAILURE;
}
/*
* VarToFile size must change once a variable is inserted
* Store it now, we'll use it later
*/
prev_len = len;
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
sizeof(v2),
v2);
/*
* This will try to update VarToFile as well and must fail,
* without changing or deleting VarToFile
*/
if (ret != EFI_OUT_OF_RESOURCES) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
len = sizeof(data2);
ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
&attr, &len, data2);
if (ret != EFI_SUCCESS || prev_len != len) {
efi_st_error("Get/SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* Add an 8byte aligned variable */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
sizeof(v), v);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* Delete it by setting the attrs to 0 */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
0, sizeof(v), v);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* Add it back */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
sizeof(v), v);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* Delete it again by setting the size to 0 */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
0, NULL);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/* Delete it again and make sure it's not there */
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
0, NULL);
if (ret != EFI_NOT_FOUND) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
/*
* Add a non-aligned variable
* VarToFile updates must include efi_st_var0
*/
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
9, v + 4);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
var = efi_var_mem_find(&guid_vendor0, u"efi_st_var0", NULL);
if (!var) {
efi_st_error("GetVariable failed\n");
return EFI_ST_FAILURE;
}
delta = efi_var_entry_len(var);
len = sizeof(data2);
ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
&attr, &len, data2);
if (ret != EFI_SUCCESS || prev_len + delta != len) {
efi_st_error("Get/SetVariable failed\n");
return EFI_ST_FAILURE;
}
/*
* Append on an existing variable must update VarToFile
* Our variable entries are 8-byte aligned.
* Adding a single byte will fit on the existing space
*/
prev_len = len;
avail = efi_var_entry_len(var) -
(sizeof(u16) * (u16_strlen(var->name) + 1) + sizeof(*var)) -
var->length;
if (avail >= append_len)
delta = 0;
else
delta = ALIGN(append_len - avail, 8);
ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_APPEND_WRITE |
EFI_VARIABLE_NON_VOLATILE,
append_len, v2);
if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
len = sizeof(data2);
ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
&attr, &len, data2);
if (ret != EFI_SUCCESS) {
efi_st_error("GetVariable failed\n");
return EFI_ST_FAILURE;
}
if (prev_len + delta != len) {
efi_st_error("Unexpected VarToFile size");
return EFI_ST_FAILURE;
}
/* Make sure that variable contains a valid file */
hdr = (struct efi_var_file *)data2;
if (hdr->magic != EFI_VAR_FILE_MAGIC ||
len != hdr->length ||
hdr->crc32 != crc32(0, (u8 *)((uintptr_t)data2 + sizeof(struct efi_var_file)),
len - sizeof(struct efi_var_file))) {
efi_st_error("VarToFile invalid header\n");
return EFI_ST_FAILURE;
}
/* Variables that are BS, RT and volatile are RO after EBS */
ret = runtime->set_variable(u"VarToFile", &efi_rt_var_guid,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS |
EFI_VARIABLE_NON_VOLATILE,
sizeof(v), v);
if (ret != EFI_WRITE_PROTECTED) {
efi_st_error("Get/SetVariable failed\n");
return EFI_ST_FAILURE;
}
} else {
if (ret != EFI_UNSUPPORTED) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
}
len = EFI_ST_MAX_DATA_SIZE;
ret = runtime->get_variable(u"PlatformLangCodes", &guid_vendor0,