feat: add logging infra w/ backend support

Add functions to support logging. This enables a user specifying their
own logging format for all functions. TF-A's logging format is supported
out of the box by specifying the `DEBUG_BACKEND_HEADER` as
`log_backed_tf.h`.

Implement digest helpers that avoid heap/libc as some end projects don't
have access to this.

Change-Id: I55410ab963ea4d0c1956ba41f94b67eced8621d5
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/src/digest.c b/src/digest.c
new file mode 100644
index 0000000..346679d
--- /dev/null
+++ b/src/digest.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "event_log.h"
+
+const struct event_log_algorithm algorithms[] = {
+	{ TPM_ALG_SHA256, "SHA256", SHA256_DIGEST_SIZE },
+	{ TPM_ALG_SHA384, "SHA384", SHA384_DIGEST_SIZE },
+	{ TPM_ALG_SHA512, "SHA512", SHA512_DIGEST_SIZE },
+};
+
+const struct event_log_algorithm *
+event_log_algorithm_lookup(uint16_t algorithm_id)
+{
+	for (size_t i = 0; i < sizeof(algorithms) / sizeof(algorithms[0]);
+	     i++) {
+		if (algorithms[i].id == algorithm_id) {
+			return &algorithms[i];
+		}
+	}
+
+	return NULL;
+}
+
+size_t event_log_append_str(char *dst, size_t cap, size_t *pos, const char *s)
+{
+	size_t n = strlen(s);
+	size_t room = (*pos < cap) ? (cap - *pos) : 0;
+
+	if (room) {
+		/* copy as much as fits, leave NUL handled by caller if needed */
+		size_t to_copy = (n < room) ? n : (room - 1);
+		memcpy(dst + *pos, s, to_copy);
+		dst[*pos + to_copy] = '\0';
+	}
+	*pos += n;
+	return n;
+}
+
+size_t event_log_write_hex_spaced(char *dst, size_t dst_len, size_t nbytes,
+				  const uint8_t *digest)
+{
+	static const char HEX[] = "0123456789abcdef";
+	size_t pos = 0;
+
+	if (nbytes > dst_len / 3) {
+		nbytes = dst_len / 3;
+	}
+
+	for (size_t i = 0; i < nbytes; i++) {
+		dst[pos++] = HEX[digest[i] >> 4];
+		dst[pos++] = HEX[digest[i] & 0x0F];
+		dst[pos++] = ' ';
+	}
+
+	if (dst_len > 0) {
+		if (pos >= dst_len) {
+			dst[dst_len - 1] = '\0';
+		} else {
+			dst[pos] = '\0';
+		}
+	}
+
+	return pos; /* count that WOULD have been written */
+}
diff --git a/src/event_print.c b/src/event_print.c
index 72a1c7c..6029548 100644
--- a/src/event_print.c
+++ b/src/event_print.c
@@ -6,11 +6,60 @@
 
 #include <errno.h>
 #include <stdbool.h>
-#include <stdio.h>
 #include <string.h>
 
+#include "debug.h"
+#include "digest.h"
 #include "event_log.h"
 
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * @brief Pretty-print a digest as 16-byte spaced hex rows with a
+ * header/continuation prefix.
+ *
+ * Emits one or more lines through the NOTICE() logging macro.
+ * Each line renders up to 16 bytes as "aa bb …".
+ *
+ * @param[in] buf         Byte array to print.
+ * @param[in] buf_len     Number of bytes in @p digest.
+ * @param[in] prefix      Prefix to append to the byte array (e.g. 'VendorInfo      :').
+ *
+ */
+static void event_log_print_spaced_hex(const uint8_t *buf, size_t buf_len,
+				       const char *prefix)
+{
+	char output_buf[256];
+	const size_t cap = sizeof(output_buf);
+	size_t pos = 0U;
+	size_t chunk;
+
+	/* Start from just after the prefix */
+	event_log_append_str(output_buf, cap, &pos, prefix);
+
+	for (size_t off = 0; off < buf_len; off += 16U) {
+		chunk = (buf_len - off >= 16U) ? 16U : (buf_len - off);
+
+		/* write the 16-byte (or tail) chunk */
+		pos += event_log_write_hex_spaced(output_buf + pos,
+						  (pos < cap) ? (cap - pos) : 0,
+						  chunk, buf + off);
+
+		NOTICE("  %s\n", output_buf);
+
+		/* prepare next line: reset to prefix only */
+		pos = 0;
+		output_buf[0] = '\0';
+		event_log_append_str(output_buf, cap, &pos, "\t\t      : ");
+	}
+}
+
+static void event_log_print_digest(const uint8_t *digest, size_t digest_len)
+{
+	event_log_print_spaced_hex(digest, digest_len, "Digest             : ");
+}
+
 /**
  * Print a TCG_EfiSpecIDEventStruct entry from the event log.
  *
@@ -34,6 +83,7 @@
 	uint32_t event_size, number_of_algorithms;
 	size_t digest_len;
 	const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
+	const struct event_log_algorithm *algo_info;
 
 	if (*log_size < sizeof(id_event_headers_t)) {
 		return -EINVAL;
@@ -43,48 +93,36 @@
 	 * EventType of EV_NO_ACTION, Digest of 20 bytes of 0, and
 	 * Event content defined as TCG_EfiSpecIDEventStruct.
 	 */
-	printf("TCG_EfiSpecIDEvent:\n");
-	printf("  PCRIndex           : %u\n", event->header.pcr_index);
+	NOTICE("TCG_EfiSpecIDEvent:\n");
+	NOTICE("  PCRIndex           : %u\n", event->header.pcr_index);
 	if (event->header.pcr_index != (uint32_t)PCR_0) {
 		return -EINVAL;
 	}
 
-	printf("  EventType          : %u\n", event->header.event_type);
+	NOTICE("  EventType          : %u\n", event->header.event_type);
 	if (event->header.event_type != EV_NO_ACTION) {
 		return -EINVAL;
 	}
 
-	printf("  Digest             :");
-	for (i = 0U; i < sizeof(event->header.digest); ++i) {
-		uint8_t val = event->header.digest[i];
-
-		(void)printf(" %02x", val);
-		if ((i & 0xFU) == 0U) {
-			(void)printf("\n");
-			printf("\t\t      :");
-		}
-	}
-
-	if ((i & 0xFU) != 0U) {
-		(void)printf("\n");
-	}
+	event_log_print_digest(event->header.digest,
+			       sizeof(event->header.digest));
 
 	/* EventSize */
 	event_size = event->header.event_size;
-	printf("  EventSize          : %u\n", event_size);
+	NOTICE("  EventSize          : %u\n", event_size);
 
-	printf("  Signature          : %s\n", event->struct_header.signature);
-	printf("  PlatformClass      : %u\n",
+	NOTICE("  Signature          : %s\n", event->struct_header.signature);
+	NOTICE("  PlatformClass      : %u\n",
 	       event->struct_header.platform_class);
-	printf("  SpecVersion        : %u.%u.%u\n",
+	NOTICE("  SpecVersion        : %u.%u.%u\n",
 	       event->struct_header.spec_version_major,
 	       event->struct_header.spec_version_minor,
 	       event->struct_header.spec_errata);
-	printf("  UintnSize          : %u\n", event->struct_header.uintn_size);
+	NOTICE("  UintnSize          : %u\n", event->struct_header.uintn_size);
 
 	/* NumberOfAlgorithms */
 	number_of_algorithms = event->struct_header.number_of_algorithms;
-	printf("  NumberOfAlgorithms : %u\n", number_of_algorithms);
+	NOTICE("  NumberOfAlgorithms : %u\n", number_of_algorithms);
 
 	/* Address of DigestSizes[] */
 	alg_ptr = event->struct_header.digest_size;
@@ -95,29 +133,20 @@
 		return -EFAULT;
 	}
 
-	printf("  DigestSizes        :\n");
-	for (i = 0U; i < number_of_algorithms; ++i) {
-		printf("    #%u AlgorithmId   : SHA", i);
-		uint16_t algorithm_id = alg_ptr[i].algorithm_id;
+	NOTICE("  DigestSizes        :\n");
 
-		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);
-			printf("Algorithm 0x%x not found\n", algorithm_id);
+	for (i = 0U; i < number_of_algorithms; ++i) {
+		uint16_t algorithm_id = alg_ptr[i].algorithm_id;
+		algo_info = event_log_algorithm_lookup(algorithm_id);
+
+		if (algo_info == NULL) {
+			ERROR("    #%u AlgorithmId   : %d (unknown)\n", i,
+			      algorithm_id);
 			return -ENOENT;
 		}
 
-		printf("       DigestSize    : %u\n", alg_ptr[i].digest_size);
+		NOTICE("    #%u AlgorithmId   : %s\n", i, algo_info->name);
+		NOTICE("       DigestSize    : %u\n", alg_ptr[i].digest_size);
 	}
 
 	/* Address of VendorInfoSize */
@@ -127,7 +156,7 @@
 	}
 
 	info_size = *info_size_ptr++;
-	printf("  VendorInfoSize     : %u\n", info_size);
+	NOTICE("  VendorInfoSize     : %u\n", info_size);
 
 	/* Check VendorInfo end address */
 	if (((uintptr_t)info_size_ptr + info_size) > (uintptr_t)end_ptr) {
@@ -140,13 +169,8 @@
 		return -EFAULT;
 	}
 
-	if (info_size != 0U) {
-		printf("  VendorInfo         :");
-		for (i = 0U; i < info_size; ++i) {
-			(void)printf(" %02x", *info_size_ptr++);
-		}
-		(void)printf("\n");
-	}
+	event_log_print_spaced_hex(info_size_ptr, info_size,
+				   "  VendorInfo         : ");
 
 	*log_size -= (uintptr_t)info_size_ptr - (uintptr_t)*log_addr;
 	*log_addr = info_size_ptr;
@@ -170,27 +194,27 @@
 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 struct event_log_algorithm *algo_info;
 	const uint8_t *end_ptr = (uint8_t *)((uintptr_t)*log_addr + *log_size);
 
 	if (*log_size < sizeof(event2_header_t)) {
 		return -EINVAL;
 	}
 
-	printf("PCR_Event2:\n");
-	printf("  PCRIndex           : %u\n",
+	NOTICE("PCR_Event2:\n");
+	NOTICE("  PCRIndex           : %u\n",
 	       ((event2_header_t *)ptr)->pcr_index);
-	printf("  EventType          : %u\n",
+	NOTICE("  EventType          : %u\n",
 	       ((event2_header_t *)ptr)->event_type);
 
 	count = ((event2_header_t *)ptr)->digests.count;
 	if (count < 1U) {
-		printf("Invalid Digests Count      : %u\n", count);
+		NOTICE("Invalid Digests Count      : %u\n", count);
 		return -EINVAL;
 	}
 
-	printf("  Digests Count      : %u\n", count);
+	NOTICE("  Digests Count      : %u\n", count);
 
 	/* Address of TCG_PCR_EVENT2.Digests[] */
 	ptr = (uint8_t *)ptr + sizeof(event2_header_t);
@@ -205,46 +229,25 @@
 			return -EFAULT;
 		}
 
-		printf("    #%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);
+		algo_info = event_log_algorithm_lookup(
+			((tpmt_ha *)ptr)->algorithm_id);
+
+		if (algo_info == NULL) {
+			ERROR("    #%u AlgorithmId   : %d (unknown)\n", i,
+			      ((tpmt_ha *)ptr)->algorithm_id);
 			return -ENOENT;
 		}
 
+		NOTICE("    #%u AlgorithmId   : %s\n", i, algo_info->name);
+
 		/* End of Digest[] */
 		ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
-		if (((uintptr_t)ptr + sha_size) > (uintptr_t)end_ptr) {
+		if (((uintptr_t)ptr + algo_info->size) > (uintptr_t)end_ptr) {
 			return -EFAULT;
 		}
 
-		/* Total size of all digests */
-		digests_size += sha_size;
-
-		printf("       Digest        :");
-		for (unsigned int j = 0U; j < sha_size; ++j) {
-			(void)printf(" %02x", *(uint8_t *)ptr++);
-			if ((j & 0xFU) == 0xFU) {
-				(void)printf("\n");
-				if (j < (sha_size - 1U)) {
-					printf("\t\t      :");
-				}
-			}
-		}
+		event_log_print_digest(ptr, algo_info->size);
+		ptr += algo_info->size;
 	}
 
 	/* TCG_PCR_EVENT2.EventSize */
@@ -254,7 +257,7 @@
 	}
 
 	event_size = ((event2_data_t *)ptr)->event_size;
-	printf("  EventSize          : %u\n", event_size);
+	NOTICE("  EventSize          : %u\n", event_size);
 
 	/* Address of TCG_PCR_EVENT2.Event[EventSize] */
 	ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
@@ -266,12 +269,12 @@
 
 	if ((event_size == sizeof(startup_locality_event_t)) &&
 	    (strcmp((const char *)ptr, TCG_STARTUP_LOCALITY_SIGNATURE) == 0)) {
-		printf("  Signature          : %s\n",
+		NOTICE("  Signature          : %s\n",
 		       ((startup_locality_event_t *)ptr)->signature);
-		printf("  StartupLocality    : %u\n",
+		NOTICE("  StartupLocality    : %u\n",
 		       ((startup_locality_event_t *)ptr)->startup_locality);
 	} else {
-		printf("  Event              : %s\n", (uint8_t *)ptr);
+		NOTICE("  Event              : %s\n", (uint8_t *)ptr);
 	}
 
 	*log_size -= (uintptr_t)ptr + event_size - (uintptr_t)*log_addr;