feat(measured-boot): add measured boot drivers
Introduces core measured boot support, including TPM event log handling,
hashing infrastructure, and event formatting per TCG spec. The driver is
imported from the existing implementation in TF-A.
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
Change-Id: Ib2e6a88c86f110f9a6907c3e6dbb0dc736486de9
diff --git a/lib/event_log/event_handoff.c b/lib/event_log/event_handoff.c
new file mode 100644
index 0000000..238ea27
--- /dev/null
+++ b/lib/event_log/event_handoff.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+
+#include <common/debug.h>
+#include <drivers/measured_boot/event_log/event_handoff.h>
+
+#include <platform_def.h>
+
+static uint8_t *get_log_ptr(struct transfer_list_entry *te, size_t offset)
+{
+ uint8_t *base_ptr = transfer_list_entry_data(te);
+
+ if (base_ptr == NULL) {
+ return NULL;
+ }
+
+ return base_ptr + offset;
+}
+
+uint8_t *transfer_list_event_log_extend(struct transfer_list_header *tl,
+ size_t req_size, size_t *free)
+{
+ struct transfer_list_entry *existing_entry;
+ struct transfer_list_entry *new_entry;
+ uint8_t *old_data;
+ size_t existing_offset;
+ size_t old_size;
+
+ if (tl == NULL || free == NULL || req_size == 0) {
+ ERROR("Invalid arguments to event log extend.\n");
+ return NULL;
+ }
+
+ existing_entry = transfer_list_find(tl, TL_TAG_TPM_EVLOG);
+ existing_offset = EVENT_LOG_RESERVED_BYTES;
+
+ if (existing_entry != NULL) {
+ existing_offset = existing_entry->data_size;
+
+ if (transfer_list_set_data_size(tl, existing_entry,
+ req_size + existing_offset)) {
+ VERBOSE("TPM event log entry resized: new space %zu bytes at offset %zu\n",
+ req_size, existing_offset);
+
+ *free = existing_entry->data_size - existing_offset;
+
+ return get_log_ptr(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;
+ }
+
+ VERBOSE("New TPM event log entry added at %p\n",
+ transfer_list_entry_data(new_entry));
+
+ if (existing_entry != NULL) {
+ old_data = transfer_list_entry_data(existing_entry);
+ old_size = existing_offset;
+
+ VERBOSE("Copying existing event log (%zu bytes) to new entry at %p\n",
+ old_size, transfer_list_entry_data(new_entry));
+
+ memmove(transfer_list_entry_data(new_entry), old_data,
+ old_size);
+
+ transfer_list_rem(tl, existing_entry);
+ }
+
+ *free = new_entry->data_size - existing_offset;
+
+ return get_log_ptr(new_entry, 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);
+
+ VERBOSE("TPM event log finalized: trimmed to %zu bytes",
+ final_log_size - EVENT_LOG_RESERVED_BYTES);
+
+ /* Ensure changes are visible to the next stage. */
+ flush_dcache_range((uintptr_t)tl, tl->size);
+
+ return get_log_ptr(entry, EVENT_LOG_RESERVED_BYTES);
+}
diff --git a/lib/event_log/event_log.c b/lib/event_log/event_log.c
new file mode 100644
index 0000000..761ff29
--- /dev/null
+++ b/lib/event_log/event_log.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "crypto_mod.h"
+#include "event_log.h"
+
+#if TPM_ALG_ID == TPM_ALG_SHA512
+#define CRYPTO_MD_ID CRYPTO_MD_SHA512
+#elif TPM_ALG_ID == TPM_ALG_SHA384
+#define CRYPTO_MD_ID CRYPTO_MD_SHA384
+#elif TPM_ALG_ID == TPM_ALG_SHA256
+#define CRYPTO_MD_ID CRYPTO_MD_SHA256
+#else
+# error Invalid TPM algorithm.
+#endif /* TPM_ALG_ID */
+
+/* Running Event Log Pointer */
+static uint8_t *log_ptr;
+
+/* Pointer to the first byte past end of the Event Log buffer */
+static uintptr_t log_end;
+
+/* TCG_EfiSpecIdEvent */
+static const id_event_headers_t id_event_header = {
+ .header = {
+ .pcr_index = PCR_0,
+ .event_type = EV_NO_ACTION,
+ .digest = {0},
+ .event_size = (uint32_t)(sizeof(id_event_struct_t) +
+ (sizeof(id_event_algorithm_size_t) *
+ HASH_ALG_COUNT))
+ },
+
+ .struct_header = {
+ .signature = TCG_ID_EVENT_SIGNATURE_03,
+ .platform_class = PLATFORM_CLASS_CLIENT,
+ .spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
+ .spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
+ .spec_errata = TCG_SPEC_ERRATA_TPM2,
+ .uintn_size = (uint8_t)(sizeof(unsigned int) /
+ sizeof(uint32_t)),
+ .number_of_algorithms = HASH_ALG_COUNT
+ }
+};
+
+static const event2_header_t locality_event_header = {
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
+ */
+ .pcr_index = PCR_0,
+
+ /*
+ * All EV_NO_ACTION events SHALL set
+ * TCG_PCR_EVENT2.eventType = 03h
+ */
+ .event_type = EV_NO_ACTION,
+
+ /*
+ * All EV_NO_ACTION events SHALL set TCG_PCR_EVENT2.digests to all
+ * 0x00's for each allocated Hash algorithm
+ */
+ .digests = {
+ .count = HASH_ALG_COUNT
+ }
+};
+
+int event_log_record(const uint8_t *hash, uint32_t event_type,
+ const event_log_metadata_t *metadata_ptr)
+{
+ void *ptr = log_ptr;
+ uint32_t name_len = 0U;
+
+ /* event_log_buf_init() must have been called prior to this. */
+ if (hash == NULL || metadata_ptr == NULL || log_ptr == NULL) {
+ return -EINVAL;
+ }
+
+ if (metadata_ptr->name != NULL) {
+ name_len = (uint32_t)strlen(metadata_ptr->name) + 1U;
+ }
+
+ /* Check for space in Event Log buffer */
+ if (((uintptr_t)ptr + (uint32_t)EVENT2_HDR_SIZE + name_len) > log_end) {
+ return -ENOMEM;
+ }
+
+ /*
+ * As per TCG specifications, firmware components that are measured
+ * into PCR[0] must be logged in the event log using the event type
+ * EV_POST_CODE.
+ */
+ /* TCG_PCR_EVENT2.PCRIndex */
+ ((event2_header_t *)ptr)->pcr_index = metadata_ptr->pcr;
+
+ /* TCG_PCR_EVENT2.EventType */
+ ((event2_header_t *)ptr)->event_type = event_type;
+
+ /* TCG_PCR_EVENT2.Digests.Count */
+ ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
+ ((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
+
+ /* TCG_PCR_EVENT2.Digests[] */
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpml_digest_values, digests));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+
+ /* Copy digest */
+ (void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
+ ((event2_data_t *)ptr)->event_size = name_len;
+
+ /* Copy event data to TCG_PCR_EVENT2.Event */
+ if (metadata_ptr->name != NULL) {
+ (void)memcpy((void *)(((event2_data_t *)ptr)->event),
+ (const void *)metadata_ptr->name, name_len);
+ }
+
+ /* End of event data */
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(event2_data_t, event) + name_len);
+
+ return 0;
+}
+
+int event_log_buf_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ if (event_log_start == NULL || event_log_finish == NULL ||
+ event_log_start > event_log_finish) {
+ return -EINVAL;
+ }
+
+ log_ptr = event_log_start;
+ log_end = (uintptr_t)event_log_finish;
+
+ return 0;
+}
+
+int event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+ return event_log_buf_init(event_log_start, event_log_finish);
+}
+
+int event_log_write_specid_event(void)
+{
+ void *ptr;
+
+ /* event_log_buf_init() must have been called prior to this. */
+ if (log_ptr == NULL) {
+ return -EFAULT;
+ }
+
+ if (((uintptr_t)log_ptr + ID_EVENT_SIZE) > log_end) {
+ return -ENOMEM;
+ }
+
+ ptr = log_ptr;
+
+ /*
+ * Add Specification ID Event first
+ *
+ * Copy TCG_EfiSpecIDEventStruct structure header
+ */
+ (void)memcpy(ptr, (const void *)&id_event_header,
+ sizeof(id_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
+
+ /* TCG_EfiSpecIdEventAlgorithmSize structure */
+ ((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
+ ((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
+
+ /*
+ * TCG_EfiSpecIDEventStruct.vendorInfoSize
+ * No vendor data
+ */
+ ((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
+ log_ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(id_event_struct_data_t, vendor_info));
+
+ return 0;
+}
+
+int event_log_write_header(void)
+{
+ const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
+ void *ptr;
+ int rc;
+
+ rc = event_log_write_specid_event();
+ if (rc < 0) {
+ return rc;
+ }
+
+ if (((uintptr_t)log_ptr + LOC_EVENT_SIZE) > log_end) {
+ return -ENOMEM;
+ }
+
+ ptr = log_ptr;
+
+ /*
+ * The Startup Locality event should be placed in the log before
+ * any event which extends PCR[0].
+ *
+ * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
+ */
+
+ /* Copy Startup Locality Event Header */
+ (void)memcpy(ptr, (const void *)&locality_event_header,
+ sizeof(locality_event_header));
+ ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
+
+ /* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+ ((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+ /* TCG_PCR_EVENT2.Digests[].Digest[] */
+ (void)memset(&((tpmt_ha *)ptr)->digest, 0, TCG_DIGEST_SIZE);
+ ptr = (uint8_t *)((uintptr_t)ptr +
+ offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
+
+ /* TCG_PCR_EVENT2.EventSize */
+ ((event2_data_t *)ptr)->event_size =
+ (uint32_t)sizeof(startup_locality_event_t);
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+ /* TCG_EfiStartupLocalityEvent.Signature */
+ (void)memcpy(ptr, (const void *)locality_signature,
+ sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
+
+ /*
+ * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
+ * the platform's boot firmware
+ */
+ ((startup_locality_event_t *)ptr)->startup_locality = 0U;
+ log_ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
+
+ return 0;
+}
+
+int event_log_measure(uintptr_t data_base, uint32_t data_size,
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE])
+{
+ /* Calculate hash */
+ return crypto_mod_calc_hash(CRYPTO_MD_ID,
+ (void *)data_base, data_size, hash_data);
+}
+
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+ uint32_t data_id,
+ const event_log_metadata_t *metadata_ptr)
+{
+ unsigned char hash_data[CRYPTO_MD_MAX_SIZE];
+ int rc;
+
+ if (metadata_ptr == NULL) {
+ return -EINVAL;
+ }
+
+ /* Get the metadata associated with this image. */
+ while (metadata_ptr->id != data_id) {
+ if (metadata_ptr->id == EVLOG_INVALID_ID) {
+ return -EINVAL;
+ }
+
+ metadata_ptr++;
+ }
+
+ /* Measure the payload with algorithm selected by EventLog driver */
+ rc = event_log_measure(data_base, data_size, hash_data);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = event_log_record(hash_data, EV_POST_CODE, metadata_ptr);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+size_t event_log_get_cur_size(uint8_t *event_log_start)
+{
+ assert(event_log_start != NULL);
+ assert(log_ptr >= event_log_start);
+
+ return (size_t)((uintptr_t)log_ptr - (uintptr_t)event_log_start);
+}
diff --git a/lib/event_log/event_log.mk b/lib/event_log/event_log.mk
new file mode 100644
index 0000000..df55c62
--- /dev/null
+++ b/lib/event_log/event_log.mk
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2020-2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# Path to library sources
+EVENT_LOG_SRC_DIR := lib/event_log/
+
+# Default log level to dump the event log (LOG_LEVEL_INFO)
+EVENT_LOG_LEVEL ?= 40
+
+EVENT_LOG_SOURCES := ${EVENT_LOG_SRC_DIR}event_print.c
+
+INCLUDES += -Iinclude/lib/event_log \
+ -Iinclude/drivers/auth
+
+ifdef CRYPTO_SUPPORT
+# Measured Boot hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
+ifdef TPM_HASH_ALG
+ $(warning "TPM_HASH_ALG is deprecated. Please use MBOOT_EL_HASH_ALG instead.")
+ MBOOT_EL_HASH_ALG := ${TPM_HASH_ALG}
+else
+ MBOOT_EL_HASH_ALG := sha256
+endif
+
+ifeq (${MBOOT_EL_HASH_ALG}, sha512)
+ TPM_ALG_ID := TPM_ALG_SHA512
+ TCG_DIGEST_SIZE := 64U
+else ifeq (${MBOOT_EL_HASH_ALG}, sha384)
+ TPM_ALG_ID := TPM_ALG_SHA384
+ TCG_DIGEST_SIZE := 48U
+else
+ TPM_ALG_ID := TPM_ALG_SHA256
+ TCG_DIGEST_SIZE := 32U
+endif #MBOOT_EL_HASH_ALG
+
+# Set definitions for event log library.
+$(eval $(call add_define,TFTF_DEFINES,TPM_ALG_ID))
+$(eval $(call add_define,TFTF_DEFINES,EVENT_LOG_LEVEL))
+$(eval $(call add_define,TFTF_DEFINES,TCG_DIGEST_SIZE))
+
+EVENT_LOG_SOURCES := ${EVENT_LOG_SRC_DIR}event_log.c
+
+INCLUDES += -Iinclude/lib/event_log \
+ -Iinclude/drivers/auth
+
+ifeq (${TRANSFER_LIST}, 1)
+EVENT_LOG_SOURCES += ${EVENT_LOG_SRC_DIR}/event_handoff.c
+INCLUDES += -Iinclude/lib
+endif
+
+endif
diff --git a/lib/event_log/event_print.c b/lib/event_log/event_print.c
new file mode 100644
index 0000000..234a694
--- /dev/null
+++ b/lib/event_log/event_print.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include "event_log.h"
+
+/**
+ * Print a TCG_EfiSpecIDEventStruct entry from the event log.
+ *
+ * This function extracts and prints a TCG_EfiSpecIDEventStruct
+ * entry from the event log for debugging or auditing purposes.
+ *
+ * @param[in,out] log_addr Pointer to the current position in the Event Log.
+ * Updated to the next entry after processing.
+ * @param[in,out] log_size Pointer to the remaining Event Log size.
+ * Updated to reflect the remaining bytes.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+static int event_log_print_id_event(uint8_t **log_addr, size_t *log_size)
+{
+ unsigned int i;
+ uint8_t info_size, *info_size_ptr;
+ void *ptr = *log_addr;
+ id_event_headers_t *event = (id_event_headers_t *)ptr;
+ id_event_algorithm_size_t *alg_ptr;
+ uint32_t event_size, number_of_algorithms;
+ size_t digest_len;
+ const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
+
+ if (*log_size < sizeof(id_event_headers_t)) {
+ return -EINVAL;
+ }
+
+ /* The fields of the event log header are defined to be PCRIndex of 0,
+ * EventType of EV_NO_ACTION, Digest of 20 bytes of 0, and
+ * Event content defined as TCG_EfiSpecIDEventStruct.
+ */
+ LOG_EVENT("TCG_EfiSpecIDEvent:\n");
+ LOG_EVENT(" PCRIndex : %u\n", event->header.pcr_index);
+ if (event->header.pcr_index != (uint32_t)PCR_0) {
+ return -EINVAL;
+ }
+
+ LOG_EVENT(" EventType : %u\n", event->header.event_type);
+ if (event->header.event_type != EV_NO_ACTION) {
+ return -EINVAL;
+ }
+
+ LOG_EVENT(" Digest :");
+ for (i = 0U; i < sizeof(event->header.digest); ++i) {
+ uint8_t val = event->header.digest[i];
+
+ (void)printf(" %02x", val);
+ if ((i & U(0xF)) == 0U) {
+ (void)printf("\n");
+ LOG_EVENT("\t\t :");
+ }
+ }
+
+ if ((i & U(0xF)) != 0U) {
+ (void)printf("\n");
+ }
+
+ /* EventSize */
+ event_size = event->header.event_size;
+ LOG_EVENT(" EventSize : %u\n", event_size);
+
+ LOG_EVENT(" Signature : %s\n",
+ event->struct_header.signature);
+ LOG_EVENT(" PlatformClass : %u\n",
+ event->struct_header.platform_class);
+ LOG_EVENT(" SpecVersion : %u.%u.%u\n",
+ event->struct_header.spec_version_major,
+ event->struct_header.spec_version_minor,
+ event->struct_header.spec_errata);
+ LOG_EVENT(" UintnSize : %u\n",
+ event->struct_header.uintn_size);
+
+ /* NumberOfAlgorithms */
+ number_of_algorithms = event->struct_header.number_of_algorithms;
+ LOG_EVENT(" NumberOfAlgorithms : %u\n", number_of_algorithms);
+
+ /* Address of DigestSizes[] */
+ alg_ptr = event->struct_header.digest_size;
+
+ /* Size of DigestSizes[] */
+ digest_len = number_of_algorithms * sizeof(id_event_algorithm_size_t);
+ if (digest_len > (uintptr_t)end_ptr - (uintptr_t)alg_ptr) {
+ return -EFAULT;
+ }
+
+ LOG_EVENT(" DigestSizes :\n");
+ for (i = 0U; i < number_of_algorithms; ++i) {
+ LOG_EVENT(" #%u AlgorithmId : SHA", i);
+ uint16_t algorithm_id = alg_ptr[i].algorithm_id;
+
+ switch (algorithm_id) {
+ case TPM_ALG_SHA256:
+ (void)printf("256\n");
+ break;
+ case TPM_ALG_SHA384:
+ (void)printf("384\n");
+ break;
+ case TPM_ALG_SHA512:
+ (void)printf("512\n");
+ break;
+ default:
+ (void)printf("?\n");
+ ERROR("Algorithm 0x%x not found\n", algorithm_id);
+ return -ENOENT;
+ }
+
+ LOG_EVENT(" DigestSize : %u\n",
+ alg_ptr[i].digest_size);
+ }
+
+ /* Address of VendorInfoSize */
+ info_size_ptr = (uint8_t *)((uintptr_t)alg_ptr + digest_len);
+ if ((uintptr_t)info_size_ptr > (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ info_size = *info_size_ptr++;
+ LOG_EVENT(" VendorInfoSize : %u\n", info_size);
+
+ /* Check VendorInfo end address */
+ if (((uintptr_t)info_size_ptr + info_size) > (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ /* Check EventSize */
+ if (event_size !=
+ (sizeof(id_event_struct_t) + digest_len + info_size)) {
+ return -EFAULT;
+ }
+
+ if (info_size != 0U) {
+ LOG_EVENT(" VendorInfo :");
+ for (i = 0U; i < info_size; ++i) {
+ (void)printf(" %02x", *info_size_ptr++);
+ }
+ (void)printf("\n");
+ }
+
+ *log_size -= (uintptr_t)info_size_ptr - (uintptr_t)*log_addr;
+ *log_addr = info_size_ptr;
+
+ return 0;
+}
+
+/**
+ * Print a TCG_PCR_EVENT2 entry from the event log.
+ *
+ * This function extracts and prints a TCG_PCR_EVENT2 structure
+ * from the event log for debugging or auditing purposes.
+ *
+ * @param[in,out] log_addr Pointer to the current position in the Event Log.
+ * Updated to the next entry after processing.
+ * @param[in,out] log_size Pointer to the remaining Event Log size.
+ * Updated to reflect the remaining bytes.
+ *
+ * @return 0 on success, or a negative error code on failure.
+ */
+static int event_log_print_pcr_event2(uint8_t **log_addr, size_t *log_size)
+{
+ uint32_t event_size, count;
+ size_t sha_size, digests_size = 0U;
+ void *ptr = *log_addr;
+ const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
+
+ if (*log_size < sizeof(event2_header_t)) {
+ return -EINVAL;
+ }
+
+ LOG_EVENT("PCR_Event2:\n");
+ LOG_EVENT(" PCRIndex : %u\n",
+ ((event2_header_t *)ptr)->pcr_index);
+ LOG_EVENT(" EventType : %u\n",
+ ((event2_header_t *)ptr)->event_type);
+
+ count = ((event2_header_t *)ptr)->digests.count;
+ if (count < 1U) {
+ LOG_EVENT("Invalid Digests Count : %u\n", count);
+ return -EINVAL;
+ }
+
+ LOG_EVENT(" Digests Count : %u\n", count);
+
+ /* Address of TCG_PCR_EVENT2.Digests[] */
+ ptr = (uint8_t *)ptr + sizeof(event2_header_t);
+ if ((uintptr_t)ptr > (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ for (unsigned int i = 0U; i < count; ++i) {
+ /* Check AlgorithmId address */
+ if (((uintptr_t)ptr + offsetof(tpmt_ha, digest)) >
+ (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ LOG_EVENT(" #%u AlgorithmId : SHA", i);
+ switch (((tpmt_ha *)ptr)->algorithm_id) {
+ case TPM_ALG_SHA256:
+ sha_size = SHA256_DIGEST_SIZE;
+ (void)printf("256\n");
+ break;
+ case TPM_ALG_SHA384:
+ sha_size = SHA384_DIGEST_SIZE;
+ (void)printf("384\n");
+ break;
+ case TPM_ALG_SHA512:
+ sha_size = SHA512_DIGEST_SIZE;
+ (void)printf("512\n");
+ break;
+ default:
+ (void)printf("?\n");
+ printf("Algorithm 0x%x not found\n",
+ ((tpmt_ha *)ptr)->algorithm_id);
+ return -ENOENT;
+ }
+
+ /* End of Digest[] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+ if (((uintptr_t)ptr + sha_size) > (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ /* Total size of all digests */
+ digests_size += sha_size;
+
+ LOG_EVENT(" Digest :");
+ for (unsigned int j = 0U; j < sha_size; ++j) {
+ (void)printf(" %02x", *(uint8_t *)ptr++);
+ if ((j & U(0xF)) == U(0xF)) {
+ (void)printf("\n");
+ if (j < (sha_size - 1U)) {
+ LOG_EVENT("\t\t :");
+ }
+ }
+ }
+ }
+
+ /* TCG_PCR_EVENT2.EventSize */
+ if (((uintptr_t)ptr + offsetof(event2_data_t, event)) >
+ (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ event_size = ((event2_data_t *)ptr)->event_size;
+ LOG_EVENT(" EventSize : %u\n", event_size);
+
+ /* Address of TCG_PCR_EVENT2.Event[EventSize] */
+ ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+ /* End of TCG_PCR_EVENT2.Event[EventSize] */
+ if (((uintptr_t)ptr + event_size) > (uintptr_t)end_ptr) {
+ return -EFAULT;
+ }
+
+ if ((event_size == sizeof(startup_locality_event_t)) &&
+ (strcmp((const char *)ptr, TCG_STARTUP_LOCALITY_SIGNATURE) == 0)) {
+ LOG_EVENT(" Signature : %s\n",
+ ((startup_locality_event_t *)ptr)->signature);
+ LOG_EVENT(" StartupLocality : %u\n",
+ ((startup_locality_event_t *)ptr)->startup_locality);
+ } else {
+ LOG_EVENT(" Event : %s\n", (uint8_t *)ptr);
+ }
+
+ *log_size -= (uintptr_t)ptr + event_size - (uintptr_t)*log_addr;
+ *log_addr = (uint8_t *)ptr + event_size;
+
+ return 0;
+}
+
+int event_log_dump(uint8_t *log_addr, size_t log_size)
+{
+ int rc;
+
+ if (log_addr == NULL) {
+ return -EINVAL;
+ }
+
+ /* Print TCG_EfiSpecIDEvent */
+ rc = event_log_print_id_event(&log_addr, &log_size);
+
+ if (rc < 0) {
+ return rc;
+ }
+
+ while (log_size != 0U) {
+ rc = event_log_print_pcr_event2(&log_addr, &log_size);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+ return 0;
+}