EFI applications such as boot loaders (e.g systemd-boot, efibootguard)
measure the time spent inside the bootloader prior to loading the next
stage. These values are then forwarded via efi variables to systemd,
which exposes them via systemd-analyze. This helps to identify where in
the boot chain delays are happening.

Without having the protocol, bootloaders have to fall back to direct
reads of the time counters, which are architecture specific. To unify
this, we implement the EFI_TIMESTAMP_PROTOCOL inside the efi provider,
resulting in an architecture independent interface.

As the implementation of the protocol is tiny, we default enable it. If
this is not desired, set EFI_TIMESTAMP_PROTOCOL=n.

Signed-off-by: Felix Moessbauer <[email protected]>
---
 include/efi_api.h              |  4 ++
 include/efi_loader.h           |  4 ++
 include/efi_timestamp.h        | 35 +++++++++++++++
 lib/efi_loader/Kconfig         |  8 ++++
 lib/efi_loader/Makefile        |  1 +
 lib/efi_loader/efi_setup.c     |  7 +++
 lib/efi_loader/efi_timestamp.c | 79 ++++++++++++++++++++++++++++++++++
 lib/uuid.c                     |  4 ++
 8 files changed, 142 insertions(+)
 create mode 100644 include/efi_timestamp.h
 create mode 100644 lib/efi_loader/efi_timestamp.c

diff --git a/include/efi_api.h b/include/efi_api.h
index d4fdd50c49e..9789237b025 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -475,6 +475,10 @@ struct efi_runtime_services {
        EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, \
                 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44)
 
+#define EFI_TIMESTAMP_PROTOCOL_GUID \
+       EFI_GUID(0xafbfde41, 0x2e6e, 0x4262, 0xba, 0x65, \
+                0x62, 0xb9, 0x23, 0x6e, 0x54, 0x95)
+
 #define EFI_DT_FIXUP_PROTOCOL_GUID \
        EFI_GUID(0xe617d64c, 0xfe08, 0x46da, 0xf4, 0xdc, \
                 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 7b865fe900a..dd91c953776 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -384,6 +384,8 @@ extern const efi_guid_t efi_guid_cert_type_pkcs7;
 
 /* GUID of RNG protocol */
 extern const efi_guid_t efi_guid_rng_protocol;
+/* GUID of timestamp protocol */
+extern const efi_guid_t efi_guid_timestamp_protocol;
 /* GUID of capsule update result */
 extern const efi_guid_t efi_guid_capsule_report;
 /* GUID of firmware management protocol */
@@ -674,6 +676,8 @@ efi_status_t efi_console_register(void);
 efi_status_t efi_disks_register(void);
 /* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
 efi_status_t efi_rng_register(void);
+/* Called by efi_init_obj_list() to install EFI_TIMESTAMP_PROTOCOL */
+efi_status_t efi_timestamp_register(void);
 /* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
 efi_status_t efi_tcg2_register(void);
 /* Called by efi_init_obj_list() to install RISCV_EFI_BOOT_PROTOCOL */
diff --git a/include/efi_timestamp.h b/include/efi_timestamp.h
new file mode 100644
index 00000000000..0fe0c41b62d
--- /dev/null
+++ b/include/efi_timestamp.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2026, Siemens AG
+ */
+
+#if !defined _EFI_TIMESTAMP_H_
+#define _EFI_TIMESTAMP_H_
+
+#include <efi.h>
+#include <efi_api.h>
+
+/**
+ * struct efi_timestamp_properties - properties of the timestamp counter
+ *
+ * @frequency: frequency of the timestamp counter in Hz
+ * @end_value: value at which the counter rolls over to zero
+ */
+struct efi_timestamp_properties {
+       u64 frequency;
+       u64 end_value;
+};
+
+/**
+ * struct efi_timestamp_protocol - EFI_TIMESTAMP_PROTOCOL
+ *
+ * @get_timestamp:     retrieve the current value of the timestamp counter
+ * @get_properties:    retrieve the properties of the timestamp counter
+ */
+struct efi_timestamp_protocol {
+       u64 (EFIAPI *get_timestamp)(void);
+       efi_status_t (EFIAPI *get_properties)
+               (struct efi_timestamp_properties *properties);
+};
+
+#endif /* _EFI_TIMESTAMP_H_ */
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index c4b0c2137b8..25e2c4b1144 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -469,6 +469,14 @@ config EFI_RNG_PROTOCOL
          Provide a EFI_RNG_PROTOCOL implementation using the hardware random
          number generator of the platform.
 
+config EFI_TIMESTAMP_PROTOCOL
+       bool "EFI_TIMESTAMP_PROTOCOL support"
+       default y
+       help
+         Provide an EFI_TIMESTAMP_PROTOCOL implementation giving EFI
+         applications access to a monotonic 64-bit timestamp counter and
+         its frequency.
+
 config EFI_TCG2_PROTOCOL
        bool "EFI_TCG2_PROTOCOL support"
        default y
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 567db518a8f..8ff5468ae9a 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_http.o
 obj-$(CONFIG_ACPI) += efi_acpi.o
 obj-$(CONFIG_SMBIOS) += efi_smbios.o
 obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
+obj-$(CONFIG_EFI_TIMESTAMP_PROTOCOL) += efi_timestamp.o
 obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
 obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o
 obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index f302bb62ab9..f0b3e59c3e7 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -325,6 +325,13 @@ efi_status_t efi_init_obj_list(void)
                        goto out;
        }
 
+       /* Install EFI_TIMESTAMP_PROTOCOL */
+       if (IS_ENABLED(CONFIG_EFI_TIMESTAMP_PROTOCOL)) {
+               ret = efi_timestamp_register();
+               if (ret != EFI_SUCCESS)
+                       goto out;
+       }
+
        if (IS_ENABLED(CONFIG_EFI_RISCV_BOOT_PROTOCOL)) {
                ret = efi_riscv_register();
                if (ret != EFI_SUCCESS)
diff --git a/lib/efi_loader/efi_timestamp.c b/lib/efi_loader/efi_timestamp.c
new file mode 100644
index 00000000000..78cefd7a8c1
--- /dev/null
+++ b/lib/efi_loader/efi_timestamp.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2026, Siemens AG
+ *
+ * Provides access to a monotonic 64-bit timestamp counter.
+ */
+
+#define LOG_CATEGORY LOGC_EFI
+
+#include <efi_loader.h>
+#include <efi_timestamp.h>
+#include <log.h>
+#include <time.h>
+#include <linux/kernel.h>
+
+const efi_guid_t efi_guid_timestamp_protocol = EFI_TIMESTAMP_PROTOCOL_GUID;
+
+/**
+ * get_timestamp() - retrieve the current value of the timestamp counter
+ *
+ * This function implements the GetTimestamp() service of the
+ * EFI_TIMESTAMP_PROTOCOL.
+ *
+ * Return:     current value of the timestamp counter
+ */
+static u64 EFIAPI get_timestamp(void)
+{
+       EFI_ENTRY("");
+
+       return EFI_EXIT(get_ticks());
+}
+
+/**
+ * get_properties() - retrieve the properties of the timestamp counter
+ *
+ * This function implements the GetProperties() service of the
+ * EFI_TIMESTAMP_PROTOCOL.
+ *
+ * @properties:        buffer receiving the properties
+ * Return:     status code
+ */
+static efi_status_t EFIAPI
+get_properties(struct efi_timestamp_properties *properties)
+{
+       EFI_ENTRY("%p", properties);
+
+       if (!properties)
+               return EFI_EXIT(EFI_INVALID_PARAMETER);
+
+       properties->frequency = get_tbclk();
+       /* get_ticks() extends narrower hardware counters to 64 bits */
+       properties->end_value = U64_MAX;
+
+       return EFI_EXIT(EFI_SUCCESS);
+}
+
+static const struct efi_timestamp_protocol efi_timestamp_protocol = {
+       .get_timestamp = get_timestamp,
+       .get_properties = get_properties,
+};
+
+/**
+ * efi_timestamp_register() - install the EFI_TIMESTAMP_PROTOCOL
+ *
+ * The protocol is installed on the root node.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_timestamp_register(void)
+{
+       efi_status_t ret;
+
+       ret = efi_add_protocol(efi_root, &efi_guid_timestamp_protocol,
+                              (void *)&efi_timestamp_protocol);
+       if (ret != EFI_SUCCESS)
+               log_err("Cannot install EFI_TIMESTAMP_PROTOCOL\n");
+
+       return ret;
+}
diff --git a/lib/uuid.c b/lib/uuid.c
index 16ca8f37751..d7022519f0e 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -189,6 +189,10 @@ static const struct {
                NULL, "Random Number Generator",
                EFI_RNG_PROTOCOL_GUID,
        },
+       {
+               NULL, "Timestamp",
+               EFI_TIMESTAMP_PROTOCOL_GUID,
+       },
        {
                NULL, "Simple Network",
                EFI_SIMPLE_NETWORK_PROTOCOL_GUID,
-- 
2.55.0

Reply via email to