diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 2d8581b57bb..b5f81e0ff53 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -126,6 +126,24 @@ 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_VARIABLE_SF_STORE + bool "Store non-volatile UEFI variables in SPI Flash" + depends on SPI_FLASH + help + Select this option if you want non-volatile UEFI variables to be + stored in SPI Flash. + + Define CONFIG_EFI_VARIABLE_SF_OFFSET as offset in SPI Flash to use as + the storage for variables. CONFIG_EFI_VAR_BUF_SIZE defines the space + needed. + + Note that SPI Flash devices have a limited number of program/erase + cycles. Frequent updates to UEFI variables may cause excessive wear + and can permanently damage the flash device, particularly on SPI NAND + or low-end SPI NOR parts without wear leveling. This option should be + used with care on such systems, and is not recommended for platforms + where UEFI variables are updated frequently. + config EFI_MM_COMM_TEE bool "UEFI variables storage service via the trusted world" depends on OPTEE @@ -196,6 +214,21 @@ config FFA_SHARED_MM_BUF_ADDR the MM SP in secure world. It is assumed that the MM SP knows the address of the shared MM communication buffer. +config EFI_VARIABLE_SF_OFFSET + hex "EFI variables in SPI flash offset" + depends on EFI_VARIABLE_SF_STORE + help + Offset from the start of the SPI Flash where EFI variables will be stored. + This should be aligned to the sector size of SPI Flash. + +config EFI_VARIABLE_SF_DEVICE_INDEX + int "Device Index for target SPI Flash" + depends on EFI_VARIABLE_SF_STORE + default 0 + help + The index of SPI Flash device used for storing EFI variables. This would be + needed if there are more than 1 SPI Flash devices available to use. + config EFI_VARIABLES_PRESEED bool "Initial values for UEFI variables" depends on !COMPILE_TEST diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index ca1775eb03b..d73ad43951b 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -54,6 +54,7 @@ obj-y += efi_variable_tee.o else obj-y += efi_variable.o obj-$(CONFIG_EFI_VARIABLE_FILE_STORE) += efi_var_file.o +obj-$(CONFIG_EFI_VARIABLE_SF_STORE) += efi_var_sf.o obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o endif obj-y += efi_watchdog.o diff --git a/lib/efi_loader/efi_var_sf.c b/lib/efi_loader/efi_var_sf.c new file mode 100644 index 00000000000..6eae8d46464 --- /dev/null +++ b/lib/efi_loader/efi_var_sf.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SPI Flash interface for UEFI variables + * + * Copyright (c) 2023, Shantur Rathore + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#define LOG_CATEGORY LOGC_EFI + +#include +#include +#include +#include + +efi_status_t efi_var_to_storage(void) +{ + struct efi_var_file *buf; + struct spi_flash *flash; + struct udevice *sfdev; + efi_status_t ret; + size_t erase_len; + loff_t len; + int r; + + ret = efi_var_collect(&buf, &len, EFI_VARIABLE_NON_VOLATILE); + if (ret != EFI_SUCCESS) + goto error; + + if (len > EFI_VAR_BUF_SIZE) { + log_debug("EFI var buffer length more than target SPI Flash size\n"); + ret = EFI_OUT_OF_RESOURCES; + goto error; + } + + log_debug("Got buffer to write buf->len: %d\n", buf->length); + + r = uclass_get_device(UCLASS_SPI_FLASH, + CONFIG_EFI_VARIABLE_SF_DEVICE_INDEX, &sfdev); + if (r) { + ret = EFI_DEVICE_ERROR; + goto error; + } + + flash = dev_get_uclass_priv(sfdev); + if (!flash) { + log_debug("Failed to get SPI Flash priv data\n"); + ret = EFI_DEVICE_ERROR; + goto error; + } + erase_len = ALIGN(len, flash->sector_size); + + r = spi_flash_erase_dm(sfdev, CONFIG_EFI_VARIABLE_SF_OFFSET, + erase_len); + if (r) { + log_debug("Failed to erase SPI Flash\n"); + ret = EFI_DEVICE_ERROR; + goto error; + } + + r = spi_flash_write_dm(sfdev, CONFIG_EFI_VARIABLE_SF_OFFSET, len, buf); + if (r) { + log_debug("Failed to write to SPI Flash: %d\n", r); + ret = EFI_DEVICE_ERROR; + } + +error: + free(buf); + return ret; +} + +efi_status_t efi_var_from_storage(void) +{ + struct efi_var_file *buf; + struct udevice *sfdev; + efi_status_t ret; + int r; + + buf = calloc(1, EFI_VAR_BUF_SIZE); + if (!buf) { + log_err("Unable to allocate buffer\n"); + return EFI_OUT_OF_RESOURCES; + } + + r = uclass_get_device(UCLASS_SPI_FLASH, + CONFIG_EFI_VARIABLE_SF_DEVICE_INDEX, &sfdev); + if (r) { + log_err("Failed to get SPI Flash device: %d\n", r); + ret = EFI_DEVICE_ERROR; + goto error; + } + + r = spi_flash_read_dm(sfdev, CONFIG_EFI_VARIABLE_SF_OFFSET, + EFI_VAR_BUF_SIZE, buf); + if (r) { + log_err("Failed to read from SPI Flash: %d\n", r); + ret = EFI_DEVICE_ERROR; + goto error; + } + + if (efi_var_restore(buf, false) != EFI_SUCCESS) { + log_err("No valid EFI variables in SPI Flash\n"); + ret = EFI_DEVICE_ERROR; + goto error; + } + + ret = EFI_SUCCESS; +error: + free(buf); + return ret; +}