diff options
| author | Michal Simek <[email protected]> | 2026-03-13 12:20:37 +0100 |
|---|---|---|
| committer | Heinrich Schuchardt <[email protected]> | 2026-03-14 08:14:20 +0100 |
| commit | 94c5c0835bccdb0763c25af7fdf72cdd2b9f7e5a (patch) | |
| tree | ae8bc9a07158b520291cc76dd5b536f15b5127ef /include | |
| parent | a9080e600c214bbff331f95136aa26e7cfbe3375 (diff) | |
efi_loader: avoid superfluous variable store writes on unchanged data
Every SetVariable() call triggers efi_var_mem_ins() followed by
efi_var_to_storage(), even when the variable value is not actually
changing. This is unfriendly to flash-backed stores that suffer
wear from unnecessary erase/write cycles.
Add a change-detection path to efi_var_mem_ins(): when size2 == 0
(i.e. not an append) and the caller passes a non-NULL changep flag,
look up the existing variable and compare attributes, length, time
and data byte-by-byte. If everything matches, set *changep = false
and return EFI_SUCCESS without touching the variable buffer.
Both efi_set_variable_int() and efi_set_variable_runtime() now
check the flag and skip efi_var_mem_del() / efi_var_to_storage()
when nothing changed.
Introduce efi_memcmp_runtime() - a runtime-safe byte-by-byte memory
comparison helper, following the same pattern as the existing
efi_memcpy_runtime(). The standard memcmp() is not available after
ExitBootServices() and calling it from Linux will crash.
Tested-by: Heinrich Schuchardt <[email protected]>
Reviewed-by: Heinrich Schuchardt <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
Reviewed-by: Ilias Apalodimas <[email protected]>
Diffstat (limited to 'include')
| -rw-r--r-- | include/efi_loader.h | 3 | ||||
| -rw-r--r-- | include/efi_variable.h | 8 |
2 files changed, 10 insertions, 1 deletions
diff --git a/include/efi_loader.h b/include/efi_loader.h index 0ebc80e0af0..3a4d502631c 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -1148,6 +1148,9 @@ struct pkcs7_message *efi_parse_pkcs7_header(const void *buf, /* runtime implementation of memcpy() */ void efi_memcpy_runtime(void *dest, const void *src, size_t n); +/* runtime implementation of memcmp() */ +int efi_memcmp_runtime(const void *s1, const void *s2, size_t n); + /* commonly used helper functions */ u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name, unsigned int index); diff --git a/include/efi_variable.h b/include/efi_variable.h index fc1184e5ca1..c3229c717d8 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -216,6 +216,11 @@ void efi_var_mem_del(struct efi_var_entry *var); * The variable is appended without checking if a variable of the same name * already exists. The two data buffers are concatenated. * + * When @changep is non-NULL and @size2 is 0, the function compares the new + * value against an existing variable with the same name and vendor. If + * attributes and data are identical the insertion is skipped and *@changep + * is set to false, avoiding superfluous writes. + * * @variable_name: variable name * @vendor: GUID * @attributes: variable attributes @@ -224,13 +229,14 @@ void efi_var_mem_del(struct efi_var_entry *var); * @size2: size of the second data field * @data2: second data buffer * @time: time of authentication (as seconds since start of epoch) + * @changep: pointer to change flag (may be NULL) * Result: status code */ efi_status_t efi_var_mem_ins(const u16 *variable_name, const efi_guid_t *vendor, u32 attributes, const efi_uintn_t size1, const void *data1, const efi_uintn_t size2, const void *data2, - const u64 time); + const u64 time, bool *changep); /** * efi_var_mem_free() - determine free memory for variables |
