Make sure the protocol is usable: the counter must advance at roughly the reported frequency, otherwise applications get wrong time measurements.
Signed-off-by: Felix Moessbauer <[email protected]> --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_timestamp.c | 99 +++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_timestamp.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 9882d9f2748..552eeb071a7 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_selftest_rng.o obj-$(CONFIG_EFI_GET_TIME) += efi_selftest_rtc.o obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_selftest_tcg2.o +obj-$(CONFIG_EFI_TIMESTAMP_PROTOCOL) += efi_selftest_timestamp.o ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) obj-y += efi_selftest_fdt.o diff --git a/lib/efi_selftest/efi_selftest_timestamp.c b/lib/efi_selftest/efi_selftest_timestamp.c new file mode 100644 index 00000000000..39583f0df3b --- /dev/null +++ b/lib/efi_selftest/efi_selftest_timestamp.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_timestamp + * + * Copyright (c) 2026, Siemens AG + * + * Test the efi timestamp service. + */ + +#include <efi_selftest.h> +#include <efi_timestamp.h> + +static struct efi_boot_services *boottime; +static efi_guid_t efi_timestamp_guid = EFI_TIMESTAMP_PROTOCOL_GUID; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Check the properties of the timestamp counter and verify that it + * advances at roughly the advertised frequency across a 10 ms stall. + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_timestamp_protocol *ts; + struct efi_timestamp_properties props; + efi_status_t ret; + u64 t0, t1, expected; + + ret = boottime->locate_protocol(&efi_timestamp_guid, NULL, + (void **)&ts); + if (ret != EFI_SUCCESS) { + efi_st_error("Timestamp protocol not available\n"); + return EFI_ST_FAILURE; + } + + ret = ts->get_properties(NULL); + if (ret != EFI_INVALID_PARAMETER) { + efi_st_error("GetProperties(NULL) did not fail\n"); + return EFI_ST_FAILURE; + } + + ret = ts->get_properties(&props); + if (ret != EFI_SUCCESS) { + efi_st_error("GetProperties failed\n"); + return EFI_ST_FAILURE; + } + if (!props.frequency) { + efi_st_error("Frequency is zero\n"); + return EFI_ST_FAILURE; + } + if (props.end_value != ~0ULL) { + efi_st_error("Unexpected end value\n"); + return EFI_ST_FAILURE; + } + + t0 = ts->get_timestamp(); + ret = boottime->stall(10000); + if (ret != EFI_SUCCESS) { + efi_st_error("Stall failed\n"); + return EFI_ST_FAILURE; + } + t1 = ts->get_timestamp(); + + if (t1 <= t0) { + efi_st_error("Timestamp did not advance\n"); + return EFI_ST_FAILURE; + } + /* 10 ms correspond to frequency / 100 ticks, allow 50 % slack */ + expected = props.frequency / 100; + if (t1 - t0 < expected / 2) { + efi_st_error("Timestamp advanced too slowly\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(timestamp) = { + .name = "timestamp", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; -- 2.55.0
