protos/linux: Publish TPM event log as LINUX_EFI_TPM_EVENT_LOG configuration table
diff --git a/common/protos/linux.c b/common/protos/linux.c
new file mode 100644
index 00000000..ae1346fe
--- /dev/null
+++ b/common/protos/linux.c
@@ -0,0 +1,97 @@
+#if defined (UEFI)
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <efi.h>
+#include <efi/protocol/efitcg2.h>
+#include <protos/linux.h>
+#include <lib/misc.h>
+#include <lib/tpm.h>
+#include <lib/print.h>
+#include <lib/libc.h>
+
+#define LINUX_EFI_TPM_EVENT_LOG_GUID \
+ { 0xb7799cb0, 0xeca2, 0x4943, { 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa } }
+
+struct linux_efi_tpm_eventlog {
+ uint32_t size;
+ uint32_t final_events_preboot_size;
+ uint8_t version;
+ uint8_t log[];
+} __attribute__((packed));
+
+// Wrap the captured TCG event log in Linux's linux_efi_tpm_eventlog framing
+// and publish it as the LINUX_EFI_TPM_EVENT_LOG configuration table for the
+// kernel's TPM driver. Limine bypasses the EFI stub that would normally do
+// this, and the ACPI TPM2 fallback path the kernel uses otherwise is
+// unreliable on common firmware.
+void linux_install_efi_tpm_event_log(void) {
+ uint32_t format;
+ void *log_addr;
+ size_t log_size;
+ if (!tpm_get_event_log(&format, &log_addr, &log_size)) {
+ return;
+ }
+
+ // Walk the firmware's EFI_TCG2_FINAL_EVENTS_TABLE so the kernel can
+ // deduplicate any pre-boot events firmware migrated there.
+ uint32_t final_events_preboot_size = 0;
+ if (format > EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) {
+ EFI_TCG2_FINAL_EVENTS_TABLE *final_events = NULL;
+ EFI_GUID final_events_guid = EFI_TCG2_FINAL_EVENTS_TABLE_GUID;
+ for (UINTN i = 0; i < gST->NumberOfTableEntries; i++) {
+ if (memcmp(&gST->ConfigurationTable[i].VendorGuid,
+ &final_events_guid, sizeof(EFI_GUID)) == 0) {
+ final_events = gST->ConfigurationTable[i].VendorTable;
+ break;
+ }
+ }
+ if (final_events != NULL && final_events->NumberOfEvents > 0) {
+ const uint8_t *base = final_events->Events;
+ uint64_t remaining = final_events->NumberOfEvents;
+ while (remaining > 0) {
+ const void *header = base + final_events_preboot_size;
+ uint32_t ev_size = tpm_calc_event_size(header, log_addr);
+ if (ev_size == 0) {
+ break;
+ }
+ final_events_preboot_size += ev_size;
+ remaining--;
+ }
+ }
+ }
+
+ UINTN total_size = sizeof(struct linux_efi_tpm_eventlog) + log_size;
+ struct linux_efi_tpm_eventlog *log_tbl = NULL;
+ EFI_STATUS status = gBS->AllocatePool(EfiACPIReclaimMemory, total_size,
+ (void **)&log_tbl);
+ if (status != EFI_SUCCESS) {
+ printv("linux: failed to allocate event log table: %X\n", (uint64_t)status);
+ return;
+ }
+
+ memset(log_tbl, 0, total_size);
+ log_tbl->size = (uint32_t)log_size;
+ log_tbl->final_events_preboot_size = final_events_preboot_size;
+ log_tbl->version = (uint8_t)format;
+ if (log_size > 0) {
+ memcpy(log_tbl->log, log_addr, log_size);
+ }
+
+ EFI_GUID linux_log_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
+ status = gBS->InstallConfigurationTable(&linux_log_guid, log_tbl);
+ if (status != EFI_SUCCESS) {
+ printv("linux: failed to install event log table: %X\n", (uint64_t)status);
+ gBS->FreePool(log_tbl);
+ return;
+ }
+
+ tpm_release_event_log();
+
+ printv("linux: installed event log (%u bytes, format TCG_%s) as configuration table\n",
+ log_tbl->size,
+ format == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ? "2" : "1.2");
+}
+
+#endif
diff --git a/common/protos/linux.h b/common/protos/linux.h
index f214c25d..3b2f6c09 100644
--- a/common/protos/linux.h
+++ b/common/protos/linux.h
@@ -70,4 +70,8 @@ struct screen_info {
noreturn void linux_load(char *config, char *cmdline);
+#if defined (UEFI)
+void linux_install_efi_tpm_event_log(void);
+#endif
+
#endif
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index c1f7a30d..bdb8f07e 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -345,6 +345,7 @@ static void prepare_efi_tables(struct boot_param *p, char *config) {
}
}
+ linux_install_efi_tpm_event_log();
efi_exit_boot_services();
}
diff --git a/common/protos/linux_x86.c b/common/protos/linux_x86.c
index 2bc5c0ea..b506c823 100644
--- a/common/protos/linux_x86.c
+++ b/common/protos/linux_x86.c
@@ -625,6 +625,7 @@ no_fb:;
// UEFI
///////////////////////////////////////
#if defined (UEFI)
+ linux_install_efi_tpm_event_log();
efi_exit_boot_services();
#if defined (__x86_64__)
