1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2017 Google |
4 | * |
5 | * Authors: |
6 | * Thiebaud Weksteen <tweek@google.com> |
7 | */ |
8 | |
9 | #include <linux/device.h> |
10 | #include <linux/efi.h> |
11 | #include <linux/tpm_eventlog.h> |
12 | |
13 | #include "../tpm.h" |
14 | #include "common.h" |
15 | |
16 | /* read binary bios log from EFI configuration table */ |
17 | int tpm_read_log_efi(struct tpm_chip *chip) |
18 | { |
19 | |
20 | struct efi_tcg2_final_events_table *final_tbl = NULL; |
21 | int final_events_log_size = efi_tpm_final_log_size; |
22 | struct linux_efi_tpm_eventlog *log_tbl; |
23 | struct tpm_bios_log *log; |
24 | u32 log_size; |
25 | u8 tpm_log_version; |
26 | void *tmp; |
27 | int ret; |
28 | |
29 | if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) |
30 | return -ENODEV; |
31 | |
32 | if (efi.tpm_log == EFI_INVALID_TABLE_ADDR) |
33 | return -ENODEV; |
34 | |
35 | log = &chip->log; |
36 | |
37 | log_tbl = memremap(offset: efi.tpm_log, size: sizeof(*log_tbl), flags: MEMREMAP_WB); |
38 | if (!log_tbl) { |
39 | pr_err("Could not map UEFI TPM log table !\n" ); |
40 | return -ENOMEM; |
41 | } |
42 | |
43 | log_size = log_tbl->size; |
44 | memunmap(addr: log_tbl); |
45 | |
46 | if (!log_size) { |
47 | pr_warn("UEFI TPM log area empty\n" ); |
48 | return -EIO; |
49 | } |
50 | |
51 | log_tbl = memremap(offset: efi.tpm_log, size: sizeof(*log_tbl) + log_size, |
52 | flags: MEMREMAP_WB); |
53 | if (!log_tbl) { |
54 | pr_err("Could not map UEFI TPM log table payload!\n" ); |
55 | return -ENOMEM; |
56 | } |
57 | |
58 | /* malloc EventLog space */ |
59 | log->bios_event_log = devm_kmemdup(dev: &chip->dev, src: log_tbl->log, len: log_size, GFP_KERNEL); |
60 | if (!log->bios_event_log) { |
61 | ret = -ENOMEM; |
62 | goto out; |
63 | } |
64 | |
65 | log->bios_event_log_end = log->bios_event_log + log_size; |
66 | tpm_log_version = log_tbl->version; |
67 | |
68 | ret = tpm_log_version; |
69 | |
70 | if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR || |
71 | final_events_log_size == 0 || |
72 | tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) |
73 | goto out; |
74 | |
75 | final_tbl = memremap(offset: efi.tpm_final_log, |
76 | size: sizeof(*final_tbl) + final_events_log_size, |
77 | flags: MEMREMAP_WB); |
78 | if (!final_tbl) { |
79 | pr_err("Could not map UEFI TPM final log\n" ); |
80 | devm_kfree(dev: &chip->dev, p: log->bios_event_log); |
81 | ret = -ENOMEM; |
82 | goto out; |
83 | } |
84 | |
85 | /* |
86 | * The 'final events log' size excludes the 'final events preboot log' |
87 | * at its beginning. |
88 | */ |
89 | final_events_log_size -= log_tbl->final_events_preboot_size; |
90 | |
91 | /* |
92 | * Allocate memory for the 'combined log' where we will append the |
93 | * 'final events log' to. |
94 | */ |
95 | tmp = devm_krealloc(dev: &chip->dev, ptr: log->bios_event_log, |
96 | size: log_size + final_events_log_size, |
97 | GFP_KERNEL); |
98 | if (!tmp) { |
99 | devm_kfree(dev: &chip->dev, p: log->bios_event_log); |
100 | ret = -ENOMEM; |
101 | goto out; |
102 | } |
103 | |
104 | log->bios_event_log = tmp; |
105 | |
106 | /* |
107 | * Append any of the 'final events log' that didn't also end up in the |
108 | * 'main log'. Events can be logged in both if events are generated |
109 | * between GetEventLog() and ExitBootServices(). |
110 | */ |
111 | memcpy((void *)log->bios_event_log + log_size, |
112 | final_tbl->events + log_tbl->final_events_preboot_size, |
113 | final_events_log_size); |
114 | /* |
115 | * The size of the 'combined log' is the size of the 'main log' plus |
116 | * the size of the 'final events log'. |
117 | */ |
118 | log->bios_event_log_end = log->bios_event_log + |
119 | log_size + final_events_log_size; |
120 | |
121 | out: |
122 | memunmap(addr: final_tbl); |
123 | memunmap(addr: log_tbl); |
124 | return ret; |
125 | } |
126 | |