xref: /linux/drivers/char/tpm/eventlog/efi.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
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 	if (!log_size) {
45 		pr_warn("UEFI TPM log area empty\n");
46 		return -EIO;
47 	}
48 
49 	log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
50 			   MEMREMAP_WB);
51 	if (!log_tbl) {
52 		pr_err("Could not map UEFI TPM log table payload!\n");
53 		return -ENOMEM;
54 	}
55 
56 	/* malloc EventLog space */
57 	log->bios_event_log = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
58 	if (!log->bios_event_log) {
59 		ret = -ENOMEM;
60 		goto out;
61 	}
62 
63 	log->bios_event_log_end = log->bios_event_log + log_size;
64 	tpm_log_version = log_tbl->version;
65 
66 	ret = tpm_log_version;
67 
68 	if (efi.tpm_final_log == EFI_INVALID_TABLE_ADDR ||
69 	    efi_tpm_final_log_size == 0 ||
70 	    tpm_log_version != EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
71 		goto out;
72 
73 	final_tbl = memremap(efi.tpm_final_log,
74 			     sizeof(*final_tbl) + efi_tpm_final_log_size,
75 			     MEMREMAP_WB);
76 	if (!final_tbl) {
77 		pr_err("Could not map UEFI TPM final log\n");
78 		kfree(log->bios_event_log);
79 		ret = -ENOMEM;
80 		goto out;
81 	}
82 
83 	efi_tpm_final_log_size -= log_tbl->final_events_preboot_size;
84 
85 	tmp = krealloc(log->bios_event_log,
86 		       log_size + efi_tpm_final_log_size,
87 		       GFP_KERNEL);
88 	if (!tmp) {
89 		kfree(log->bios_event_log);
90 		ret = -ENOMEM;
91 		goto out;
92 	}
93 
94 	log->bios_event_log = tmp;
95 
96 	/*
97 	 * Copy any of the final events log that didn't also end up in the
98 	 * main log. Events can be logged in both if events are generated
99 	 * between GetEventLog() and ExitBootServices().
100 	 */
101 	memcpy((void *)log->bios_event_log + log_size,
102 	       final_tbl->events + log_tbl->final_events_preboot_size,
103 	       efi_tpm_final_log_size);
104 	log->bios_event_log_end = log->bios_event_log +
105 		log_size + efi_tpm_final_log_size;
106 
107 out:
108 	memunmap(final_tbl);
109 	memunmap(log_tbl);
110 	return ret;
111 }
112