feat(libtl): add TPM event log management helpers
Introduce `tpm_event_log.c` and `tpm_event_log.h` to simplify managing
the TPM event log within a Transfer List. These helpers allow:
- Extending an existing event log entry in-place if possible
- Adding a new event log TE if needed, while preserving old data
- Finalizing and resizing the TE after log writing is complete
This isolates common event log handling logic used during measured boot,
making integration simpler across different firmware stages.
Change-Id: I5506b4a7111ae690e1c9032bb245618a16fb1fff
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a1bd03f..d5a9f12 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,6 +23,7 @@
add_library(tl
STATIC
${PROJECT_SOURCE_DIR}/src/generic/transfer_list.c
+ ${PROJECT_SOURCE_DIR}/src/generic/tpm_event_log.c
${PROJECT_SOURCE_DIR}/src/generic/logging.c
)
diff --git a/include/tpm_event_log.h b/include/tpm_event_log.h
new file mode 100644
index 0000000..d0a9455
--- /dev/null
+++ b/include/tpm_event_log.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TPM_EVENT_LOG_H
+#define TPM_EVENT_LOG_H
+
+#include <stdint.h>
+
+#include <transfer_list.h>
+
+/**
+ * Initializes or extends the TPM event log in the transfer list.
+ *
+ * If an event log entry exists, attempts to resize it. Otherwise, adds a new entry.
+ * Copies old data if needed. Updates free to reflect available space.
+ *
+ * @param tl Pointer to the transfer list header.
+ * @param req_size Requested size (bytes)
+ * @return Pointer to start of free space in the log, or NULL.
+ */
+uint8_t *transfer_list_event_log_extend(struct transfer_list_header *tl,
+ size_t req_size);
+
+/**
+ * Finalizes the event log after writing is complete.
+ *
+ * Resizes the event log to match actual data written, updates checksum,
+ * and flushes cache for the next stage.
+ *
+ * @param tl Pointer to the transfer list header.
+ * @param cursor End offset of written log data.
+ * @return Pointer to start of log (past reserved bytes), or NULL.
+ */
+uint8_t *transfer_list_event_log_finish(struct transfer_list_header *tl,
+ uintptr_t cursor);
+
+#define EVENT_LOG_RESERVED_BYTES 4U
+
+#endif /* TPM_EVENT_LOG_H */
diff --git a/src/generic/tpm_event_log.c b/src/generic/tpm_event_log.c
new file mode 100644
index 0000000..6dcf6fe
--- /dev/null
+++ b/src/generic/tpm_event_log.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include <logging.h>
+#include <tpm_event_log.h>
+
+uint8_t *transfer_list_event_log_extend(struct transfer_list_header *tl,
+ size_t req_size)
+{
+ size_t existing_offset = EVENT_LOG_RESERVED_BYTES;
+ struct transfer_list_entry *existing_entry, *new_entry;
+ uint8_t *new_data_ptr;
+
+ if (tl == NULL || req_size == 0U) {
+ error("Invalid arguments to event log extend.\n");
+ return NULL;
+ }
+
+ existing_entry = transfer_list_find(tl, TL_TAG_TPM_EVLOG);
+ if (existing_entry != NULL) {
+ existing_offset = existing_entry->data_size;
+
+ if (transfer_list_set_data_size(tl, existing_entry,
+ req_size + existing_offset)) {
+ info("TPM event log entry resized: new space %zu bytes at offset %zu\n",
+ req_size, existing_offset);
+
+ return transfer_list_entry_data(existing_entry) +
+ existing_offset;
+ }
+ }
+
+ /* Add new entry (resize failed or no existing entry) */
+ new_entry = transfer_list_add(tl, TL_TAG_TPM_EVLOG,
+ req_size + existing_offset, NULL);
+
+ if (new_entry == NULL) {
+ error("Failed to add TPM event log entry to transfer list.\n");
+ return NULL;
+ }
+
+ new_data_ptr = transfer_list_entry_data(new_entry);
+
+ if (existing_entry != NULL) {
+ info("Copying existing event log (%zu bytes) to new entry at %p\n",
+ existing_offset, new_data_ptr);
+
+ memmove(new_data_ptr, transfer_list_entry_data(existing_entry),
+ existing_offset);
+
+ transfer_list_rem(tl, existing_entry);
+ }
+
+ return new_data_ptr + existing_offset;
+}
+
+uint8_t *transfer_list_event_log_finish(struct transfer_list_header *tl,
+ uintptr_t cursor)
+{
+ uintptr_t entry_data_base;
+ size_t final_log_size;
+ struct transfer_list_entry *entry;
+
+ entry = transfer_list_find(tl, TL_TAG_TPM_EVLOG);
+ entry_data_base = (uintptr_t)transfer_list_entry_data(entry);
+
+ if (cursor < entry_data_base ||
+ cursor >= entry_data_base + entry->data_size) {
+ error("Invalid cursor: outside event log bounds.\n");
+ return NULL;
+ }
+
+ final_log_size = cursor - entry_data_base;
+
+ if (!transfer_list_set_data_size(tl, entry, final_log_size)) {
+ error("Unable to resize event log TE.\n");
+ return NULL;
+ }
+
+ transfer_list_update_checksum(tl);
+
+ info("TPM event log finalized: trimmed to %zu bytes",
+ final_log_size - EVENT_LOG_RESERVED_BYTES);
+
+ return (uint8_t *)(entry_data_base + EVENT_LOG_RESERVED_BYTES);
+}