Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / char / tpm / eventlog / efi.c
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/efi.h>
10 #include <linux/tpm_eventlog.h>
11
12 #include "../tpm.h"
13 #include "common.h"
14
15 /* read binary bios log from EFI configuration table */
16 int tpm_read_log_efi(struct tpm_chip *chip)
17 {
18
19         struct efi_tcg2_final_events_table *final_tbl = NULL;
20         struct linux_efi_tpm_eventlog *log_tbl;
21         struct tpm_bios_log *log;
22         u32 log_size;
23         u8 tpm_log_version;
24         void *tmp;
25         int ret;
26
27         if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
28                 return -ENODEV;
29
30         if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
31                 return -ENODEV;
32
33         log = &chip->log;
34
35         log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB);
36         if (!log_tbl) {
37                 pr_err("Could not map UEFI TPM log table !\n");
38                 return -ENOMEM;
39         }
40
41         log_size = log_tbl->size;
42         memunmap(log_tbl);
43
44         log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
45                            MEMREMAP_WB);
46         if (!log_tbl) {
47                 pr_err("Could not map UEFI TPM log table payload!\n");
48                 return -ENOMEM;
49         }
50
51         /* malloc EventLog space */
52         log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
53         if (!log->bios_event_log) {
54                 ret = -ENOMEM;
55                 goto out;
56         }
57
58         log->bios_event_log_end = log->bios_event_log + log_size;
59         tpm_log_version = log_tbl->version;
60
61         ret = tpm_log_version;
62
63         if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
64             efi_tpm_final_log_size == 0 ||
65             tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
66                 goto out;
67
68         final_tbl = memremap(efi.tpm_final_log,
69                              sizeof(*final_tbl) + efi_tpm_final_log_size,
70                              MEMREMAP_WB);
71         if (!final_tbl) {
72                 pr_err("Could not map UEFI TPM final log\n");
73                 kfree(log->bios_event_log);
74                 ret = -ENOMEM;
75                 goto out;
76         }
77
78         efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
79
80         tmp = krealloc(log->bios_event_log,
81                        log_size + efi_tpm_final_log_size,
82                        GFP_KERNEL);
83         if (!tmp) {
84                 kfree(log->bios_event_log);
85                 ret = -ENOMEM;
86                 goto out;
87         }
88
89         log->bios_event_log = tmp;
90
91         /*
92          * Copy any of the final events log that didn't also end up in the
93          * main log. Events can be logged in both if events are generated
94          * between GetEventLog() and ExitBootServices().
95          */
96         memcpy((void *)log->bios_event_log + log_size,
97                final_tbl->events + log_tbl->final_events_preboot_size,
98                efi_tpm_final_log_size);
99         log->bios_event_log_end = log->bios_event_log +
100                 log_size + efi_tpm_final_log_size;
101
102 out:
103         memunmap(final_tbl);
104         memunmap(log_tbl);
105         return ret;
106 }