xref: /openbmc/linux/drivers/char/tpm/eventlog/efi.c (revision e7bae9bb)
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 }
107