summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2026-03-16 08:23:18 -0600
committerTom Rini <[email protected]>2026-03-16 08:23:18 -0600
commitfa3a11fcf01a27f038789f4ef36d0414fe78b493 (patch)
tree416a413625c79ac468a679a5f6cb0c1610a70280
parent071e914b4aa139c9c411efda3fe1ffaebda5c76e (diff)
parent8f83a4596677fe6a3f3b587b76d460644205a922 (diff)
Merge tag 'efi-2026-03-14' of https://source.denx.de/u-boot/custodians/u-boot-efi into next
Pull request efi-2026-03-14 CI: https://source.denx.de/u-boot/custodians/u-boot-efi/-/pipelines/29512 UEFI: * Require at least 128 KiB of stack space to use EFI sub-system. * Avoid buffer overrun in efi_var_restore(). * Avoid superfluous variable store writes on unchanged data * Implement SPI Flash store for EFI variables. * Add an efidebug ecpt sub-command to display the ECPT table and a unit test for the command. Others: * Add missing include string.h to make exception command build again. * lib: uuid: add EBBR 2.1 conformance profile GUID
-rw-r--r--Kconfig8
-rw-r--r--cmd/efidebug.c49
-rw-r--r--include/efi_loader.h7
-rw-r--r--include/efi_variable.h8
-rw-r--r--include/exception.h1
-rw-r--r--lib/efi_loader/Kconfig35
-rw-r--r--lib/efi_loader/Makefile1
-rw-r--r--lib/efi_loader/efi_conformance.c2
-rw-r--r--lib/efi_loader/efi_runtime.c24
-rw-r--r--lib/efi_loader/efi_var_common.c4
-rw-r--r--lib/efi_loader/efi_var_mem.c29
-rw-r--r--lib/efi_loader/efi_var_sf.c111
-rw-r--r--lib/efi_loader/efi_variable.c27
-rw-r--r--lib/uuid.c6
-rw-r--r--test/py/tests/test_efi_ecpt.py42
15 files changed, 338 insertions, 16 deletions
diff --git a/Kconfig b/Kconfig
index a50b4c8c68a..b52331d6ff2 100644
--- a/Kconfig
+++ b/Kconfig
@@ -615,9 +615,11 @@ config STACK_SIZE
default 0x4000 if ARCH_STM32
default 0x1000000
help
- Define Max stack size that can be used by U-Boot. This value is used
- by the UEFI sub-system. On some boards initrd_high is calculated as
- base stack pointer minus this stack size.
+ Define Max stack size that can be used by U-Boot. The UEFI sub-system
+ considers this value when setting up the memory map. The UEFI
+ specification requires 128 KiB or more of available stack space. On
+ some boards initrd_high is calculated as base stack pointer minus this
+ stack size.
config SYS_MEM_TOP_HIDE
hex "Exclude some memory from U-Boot / OS information"
diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index 109496d9e95..7b733119c82 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -533,6 +533,47 @@ static int do_efi_show_defaults(struct cmd_tbl *cmdtp, int flag,
return CMD_RET_SUCCESS;
}
+#if CONFIG_IS_ENABLED(EFI_ECPT)
+/**
+ * do_efi_show_ecpt() - show UEFI conformance profiles in ECPT
+ *
+ * @cmdtp: Command table
+ * @flag: Command flag
+ * @argc: Number of arguments
+ * @argv: Argument array
+ * Return: CMD_RET_SUCCESS on success,
+ * CMD_RET_USAGE or CMD_RET_FAILURE on failure
+ *
+ * Implement efidebug "ecpt" sub-command.
+ * Show all the UEFI Conformance Profiles listed in the EFI Conformance Profiles
+ * Table (ECPT).
+ */
+static int do_efi_show_ecpt(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ const struct efi_conformance_profiles_table *ecpt;
+ u16 n;
+
+ if (argc != 1)
+ return CMD_RET_USAGE;
+
+ ecpt = efi_get_configuration_table(&efi_ecpt_guid);
+ if (!ecpt) {
+ log_err("ECPT table missing\n");
+ return CMD_RET_FAILURE;
+ }
+
+ for (n = 0; n < ecpt->number_of_profiles; n++) {
+ const efi_guid_t *guid = &ecpt->conformance_profiles[n];
+
+ printf("%pUl %s\n", guid->b,
+ uuid_guid_get_str(guid->b) ?: "(unknown)");
+ }
+
+ return CMD_RET_SUCCESS;
+}
+#endif /* CONFIG_IS_ENABLED(EFI_ECPT) */
+
static const char * const efi_mem_type_string[] = {
[EFI_RESERVED_MEMORY_TYPE] = "RESERVED",
[EFI_LOADER_CODE] = "LOADER CODE",
@@ -1586,6 +1627,10 @@ static struct cmd_tbl cmd_efidebug_sub[] = {
"", ""),
U_BOOT_CMD_MKENT(defaults, CONFIG_SYS_MAXARGS, 1, do_efi_show_defaults,
"", ""),
+#if CONFIG_IS_ENABLED(EFI_ECPT)
+ U_BOOT_CMD_MKENT(ecpt, CONFIG_SYS_MAXARGS, 1, do_efi_show_ecpt,
+ "", ""),
+#endif
U_BOOT_CMD_MKENT(images, CONFIG_SYS_MAXARGS, 1, do_efi_show_images,
"", ""),
U_BOOT_CMD_MKENT(memmap, CONFIG_SYS_MAXARGS, 1, do_efi_show_memmap,
@@ -1680,6 +1725,10 @@ U_BOOT_LONGHELP(efidebug,
" - show UEFI handles\n"
"efidebug defaults\n"
" - show default EFI filename and PXE architecture\n"
+#if CONFIG_IS_ENABLED(EFI_ECPT)
+ "efidebug ecpt\n"
+ " - show conformance profiles in the ECPT\n"
+#endif
"efidebug images\n"
" - show loaded images\n"
"efidebug memmap\n"
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3e70ac07055..3a4d502631c 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -387,6 +387,10 @@ extern const efi_guid_t efi_guid_capsule_report;
extern const efi_guid_t efi_guid_firmware_management_protocol;
/* GUID for the ESRT */
extern const efi_guid_t efi_esrt_guid;
+/* GUID for the ECPT */
+#if CONFIG_IS_ENABLED(EFI_ECPT)
+extern const efi_guid_t efi_ecpt_guid;
+#endif
/* GUID of the SMBIOS table */
extern const efi_guid_t smbios_guid;
extern const efi_guid_t smbios3_guid;
@@ -1144,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
diff --git a/include/exception.h b/include/exception.h
index a7f21e73d75..0d4dff49954 100644
--- a/include/exception.h
+++ b/include/exception.h
@@ -6,6 +6,7 @@
*/
#include <command.h>
+#include <string.h>
static int do_exception(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 579eed65880..b5f81e0ff53 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -15,6 +15,8 @@ config EFI_LOADER
# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT
depends on !EFI_APP
+ # The EFI specification requires 128 KiB or more of stack space
+ depends on STACK_SIZE >= 0x20000
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
select EFI
select CHARSET
@@ -124,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
@@ -194,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_conformance.c b/lib/efi_loader/efi_conformance.c
index 2d31800ccb8..470141af483 100644
--- a/lib/efi_loader/efi_conformance.c
+++ b/lib/efi_loader/efi_conformance.c
@@ -12,7 +12,7 @@
#include <efi_api.h>
#include <malloc.h>
-static const efi_guid_t efi_ecpt_guid = EFI_CONFORMANCE_PROFILES_TABLE_GUID;
+const efi_guid_t efi_ecpt_guid = EFI_CONFORMANCE_PROFILES_TABLE_GUID;
/**
* efi_ecpt_register() - Install the ECPT system table.
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 35eb6a77766..73d4097464c 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -210,6 +210,30 @@ void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n)
}
/**
+ * efi_memcmp_runtime() - compare memory areas
+ *
+ * At runtime memcmp() is not available.
+ *
+ * @s1: first memory area
+ * @s2: second memory area
+ * @n: number of bytes to compare
+ * Return: 0 if equal, negative if s1 < s2, positive if s1 > s2
+ */
+int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
+{
+ const u8 *pos1 = s1;
+ const u8 *pos2 = s2;
+
+ for (; n; --n) {
+ if (*pos1 != *pos2)
+ return *pos1 - *pos2;
+ ++pos1;
+ ++pos2;
+ }
+ return 0;
+}
+
+/**
* efi_update_table_header_crc32() - Update crc32 in table header
*
* @table: EFI table
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index 5ea1688dca3..d63c2d1b1cd 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -497,6 +497,8 @@ efi_status_t efi_var_restore(struct efi_var_file *buf, bool safe)
efi_status_t ret;
if (buf->reserved || buf->magic != EFI_VAR_FILE_MAGIC ||
+ buf->length > EFI_VAR_BUF_SIZE ||
+ buf->length < sizeof(struct efi_var_file) ||
buf->crc32 != crc32(0, (u8 *)buf->var,
buf->length - sizeof(struct efi_var_file))) {
log_err("Invalid EFI variables file\n");
@@ -524,7 +526,7 @@ efi_status_t efi_var_restore(struct efi_var_file *buf, bool safe)
continue;
ret = efi_var_mem_ins(var->name, &var->guid, var->attr,
var->length, data, 0, NULL,
- var->time);
+ var->time, NULL);
if (ret != EFI_SUCCESS)
log_err("Failed to set EFI variable %ls\n", var->name);
}
diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c
index 31180df9e3a..8d5f99f4870 100644
--- a/lib/efi_loader/efi_var_mem.c
+++ b/lib/efi_loader/efi_var_mem.c
@@ -159,12 +159,39 @@ efi_status_t __efi_runtime efi_var_mem_ins(
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)
{
u16 *data;
struct efi_var_entry *var;
u32 var_name_len;
+ if (changep)
+ *changep = true;
+
+ /*
+ * If this is not an append (size2 == 0), check whether the variable
+ * already exists with identical attributes and data. When nothing
+ * changed we can skip the write and avoid superfluous erases.
+ */
+ if (!size2 && changep) {
+ struct efi_var_entry *old;
+
+ old = efi_var_mem_find(vendor, variable_name, NULL);
+ if (old && old->attr == attributes &&
+ old->length == size1 && old->time == time) {
+ u16 *old_data;
+
+ for (old_data = old->name; *old_data; ++old_data)
+ ;
+ ++old_data;
+
+ if (!efi_memcmp_runtime(old_data, data1, size1)) {
+ *changep = false;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
var = (struct efi_var_entry *)
((uintptr_t)efi_var_buf + efi_var_buf->length);
var_name_len = u16_strlen(variable_name) + 1;
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 <efi_loader.h>
+#include <efi_variable.h>
+#include <spi_flash.h>
+#include <dm.h>
+
+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;
+}
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 8512bc20f11..9923936c1b5 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -277,6 +277,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
struct efi_var_entry *var;
efi_uintn_t ret;
bool append, delete;
+ bool changed = false;
u64 time = 0;
enum efi_auth_var_type var_type;
@@ -366,6 +367,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
if (delete) {
/* EFI_NOT_FOUND has been handled before */
attributes = var->attr;
+ changed = true;
ret = EFI_SUCCESS;
} else if (append && var) {
/*
@@ -380,15 +382,19 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
ret = efi_var_mem_ins(variable_name, vendor,
attributes & ~EFI_VARIABLE_APPEND_WRITE,
var->length, old_data, data_size, data,
- time);
+ time, &changed);
} else {
ret = efi_var_mem_ins(variable_name, vendor, attributes,
- data_size, data, 0, NULL, time);
+ data_size, data, 0, NULL, time,
+ &changed);
}
if (ret != EFI_SUCCESS)
return ret;
+ if (!changed)
+ return EFI_SUCCESS;
+
efi_var_mem_del(var);
if (var_type == EFI_AUTH_VAR_PK)
@@ -396,10 +402,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
else
ret = EFI_SUCCESS;
- /*
- * Write non-volatile EFI variables
- * TODO: check if a value change has occured to avoid superfluous writes
- */
+ /* Write non-volatile EFI variables to storage */
if (attributes & EFI_VARIABLE_NON_VOLATILE) {
if (IS_ENABLED(CONFIG_EFI_VARIABLE_NO_STORE))
return EFI_SUCCESS;
@@ -498,6 +501,7 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
struct efi_var_entry *var;
efi_uintn_t ret;
bool append, delete;
+ bool changed = false;
u64 time = 0;
if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE))
@@ -549,6 +553,7 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
if (delete) {
/* EFI_NOT_FOUND has been handled before */
attributes = var->attr;
+ changed = true;
ret = EFI_SUCCESS;
} else if (append && var) {
u16 *old_data = (void *)((uintptr_t)var->name +
@@ -556,15 +561,19 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
ret = efi_var_mem_ins(variable_name, vendor, attributes,
var->length, old_data, data_size, data,
- time);
+ time, &changed);
} else {
ret = efi_var_mem_ins(variable_name, vendor, attributes,
- data_size, data, 0, NULL, time);
+ data_size, data, 0, NULL, time,
+ &changed);
}
if (ret != EFI_SUCCESS)
return ret;
- /* We are always inserting new variables, get rid of the old copy */
+
+ if (!changed)
+ return EFI_SUCCESS;
+
efi_var_mem_del(var);
return EFI_SUCCESS;
diff --git a/lib/uuid.c b/lib/uuid.c
index 0a166320e07..3a666d0430d 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -254,6 +254,12 @@ static const struct {
NULL, "EFI Conformance Profiles Table",
EFI_CONFORMANCE_PROFILES_TABLE_GUID,
},
+#if CONFIG_IS_ENABLED(EFI_ECPT)
+ {
+ NULL, "EFI EBBR 2.1 Conformance Profile",
+ EFI_CONFORMANCE_PROFILE_EBBR_2_1_GUID,
+ },
+#endif
#ifdef CONFIG_EFI_RISCV_BOOT_PROTOCOL
{
NULL, "RISC-V Boot",
diff --git a/test/py/tests/test_efi_ecpt.py b/test/py/tests/test_efi_ecpt.py
new file mode 100644
index 00000000000..632a6b90bad
--- /dev/null
+++ b/test/py/tests/test_efi_ecpt.py
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+""" Unit test for the EFI Conformance Profiles Table (ECPT)
+"""
+
+import pytest
+
+
[email protected]('cmd_efidebug')
[email protected]('efi_ecpt')
+def test_efi_ecpt(ubman) -> None:
+ """ Unit test for the ECPT
+ This test assumes nothing about the ECPT contents, it just checks that the
+ ECPT table is there and that the efidebug ecpt command does not fail.
+
+ Args:
+ ubman -- U-Boot console
+ """
+ response = ubman.run_command('efidebug tables')
+ assert ('36122546-f7e7-4c8f-bd9b-eb8525b50c0b '
+ 'EFI Conformance Profiles Table') in response
+
+ response = ubman.run_command('efidebug ecpt')
+ assert 'Unknown command' not in response
+ assert 'Configure UEFI environment' not in response
+ assert 'Usage:' not in response
+ assert 'table missing' not in response
+
+
[email protected]('cmd_efidebug')
[email protected]('efi_ecpt')
[email protected]('efi_ebbr_2_1_conformance')
+def test_efi_ecpt_ebbr_2_1(ubman) -> None:
+ """ Unit test for the ECPT, with EBBR 2.1 profile
+ This test uses the efidebug ecpt command to dump the ECPT and check that
+ the EBBR 2.1 conformance profile is there.
+
+ Args:
+ ubman -- U-Boot console
+ """
+ response = ubman.run_command('efidebug ecpt')
+ assert ('cce33c35-74ac-4087-bce7-8b29b02eeb27 '
+ 'EFI EBBR 2.1 Conformance Profile') in response