:: limine / common / protos / linux.c 3.7 KB raw

1
#if defined (UEFI)
2
3
#include <stdint.h>
4
#include <stddef.h>
5
#include <stdbool.h>
6
#include <efi.h>
7
#include <efi/protocol/efitcg2.h>
8
#include <protos/linux.h>
9
#include <lib/misc.h>
10
#include <lib/tpm.h>
11
#include <lib/print.h>
12
#include <lib/libc.h>
13
14
#define LINUX_EFI_TPM_EVENT_LOG_GUID \
15
    { 0xb7799cb0, 0xeca2, 0x4943, { 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa } }
16
17
struct linux_efi_tpm_eventlog {
18
    uint32_t size;
19
    uint32_t final_events_preboot_size;
20
    uint8_t  version;
21
    uint8_t  log[];
22
} __attribute__((packed));
23
24
// Wrap the captured TCG event log in Linux's linux_efi_tpm_eventlog framing
25
// and publish it as the LINUX_EFI_TPM_EVENT_LOG configuration table for the
26
// kernel's TPM driver. Limine bypasses the EFI stub that would normally do
27
// this, and the ACPI TPM2 fallback path the kernel uses otherwise is
28
// unreliable on common firmware.
29
void linux_install_efi_tpm_event_log(void) {
30
    uint32_t format;
31
    void *log_addr;
32
    size_t log_size;
33
    if (!tpm_get_event_log(&format, &log_addr, &log_size)) {
34
        return;
35
    }
36
37
    // Walk the firmware's final-events table so the kernel can deduplicate
38
    // any pre-boot events firmware migrated there. The table is selected
39
    // by the active measurement protocol (TCG2 vs CC).
40
    uint32_t final_events_preboot_size = 0;
41
    if (format > EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) {
42
        EFI_TCG2_FINAL_EVENTS_TABLE *final_events = tpm_get_final_events_table();
43
        if (final_events != NULL && final_events->NumberOfEvents > 0) {
44
            const uint8_t *base = final_events->Events;
45
            uint64_t remaining = final_events->NumberOfEvents;
46
            while (remaining > 0) {
47
                const void *header = base + final_events_preboot_size;
48
                uint32_t ev_size = tpm_calc_event_size(header, log_addr);
49
                if (ev_size == 0) {
50
                    // Malformed entry: a partial sum would skip an arbitrary
51
                    // prefix and leave the rest looking post-boot, which is
52
                    // worse than disabling dedup. Hand the kernel 0 so it
53
                    // processes every final-events entry; the worst case is
54
                    // duplicate events in its log, not silent loss.
55
                    printv("linux: malformed entry in TCG final events table; "
56
                           "disabling preboot dedup\n");
57
                    final_events_preboot_size = 0;
58
                    break;
59
                }
60
                final_events_preboot_size += ev_size;
61
                remaining--;
62
            }
63
        }
64
    }
65
66
    UINTN total_size = sizeof(struct linux_efi_tpm_eventlog) + log_size;
67
    struct linux_efi_tpm_eventlog *log_tbl = NULL;
68
    EFI_STATUS status = gBS->AllocatePool(EfiACPIReclaimMemory, total_size,
69
                                          (void **)&log_tbl);
70
    if (status != EFI_SUCCESS) {
71
        printv("linux: failed to allocate event log table: %X\n", (uint64_t)status);
72
        return;
73
    }
74
75
    memset(log_tbl, 0, total_size);
76
    log_tbl->size = (uint32_t)log_size;
77
    log_tbl->final_events_preboot_size = final_events_preboot_size;
78
    log_tbl->version = (uint8_t)format;
79
    if (log_size > 0) {
80
        memcpy(log_tbl->log, log_addr, log_size);
81
    }
82
83
    EFI_GUID linux_log_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
84
    status = gBS->InstallConfigurationTable(&linux_log_guid, log_tbl);
85
    if (status != EFI_SUCCESS) {
86
        printv("linux: failed to install event log table: %X\n", (uint64_t)status);
87
        gBS->FreePool(log_tbl);
88
        return;
89
    }
90
91
    tpm_release_event_log();
92
93
    printv("linux: installed event log (%u bytes, format TCG_%s) as configuration table\n",
94
           log_tbl->size,
95
           format == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ? "2" : "1.2");
96
}
97
98
#endif
tab: 248 wrap: offon