blob: ceeb5fbdcb48c58427d4762b0d7311dce3a2a0bb [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
Stefan Berger2aff1c12015-05-26 15:48:33 -04002// described in specs found at
3// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
Stefan Bergerb310dfa2015-03-23 14:22:16 -04004//
Stefan Berger2aff1c12015-05-26 15:48:33 -04005// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
Stefan Bergerb310dfa2015-03-23 14:22:16 -04006//
7// Authors:
8// Stefan Berger <stefanb@linux.vnet.ibm.com>
9//
10// This file may be distributed under the terms of the GNU LGPLv3 license.
11
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050012#include "bregs.h" // struct bregs
Stefan Bergerb310dfa2015-03-23 14:22:16 -040013#include "byteorder.h" // cpu_to_*
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050014#include "config.h" // CONFIG_TCGBIOS
Stefan Bergerb310dfa2015-03-23 14:22:16 -040015#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050016#include "fw/paravirt.h" // runningOnXen
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "output.h" // dprintf
19#include "sha1.h" // sha1
20#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
21#include "std/smbios.h" // struct smbios_entry_point
22#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
Stefan Bergerb310dfa2015-03-23 14:22:16 -040023#include "string.h" // checksum
24#include "tcgbios.h"// tpm_*, prototypes
25#include "util.h" // printf, get_keystroke
Stefan Berger320df852015-11-30 11:14:19 -050026#include "stacks.h" // wait_threads, reset
Stefan Bergerb310dfa2015-03-23 14:22:16 -040027
Stefan Berger0d289b52015-06-09 19:56:29 -040028static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
29static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040030
Stefan Berger0d289b52015-06-09 19:56:29 -040031static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
32static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
33static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
34static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040035
36static const u8 CommandFlag_FALSE[1] = { 0x00 };
37static const u8 CommandFlag_TRUE[1] = { 0x01 };
38
Kevin O'Connor27065322015-11-28 14:25:41 -050039typedef u8 tpm_ppi_code;
40
Stefan Bergerb310dfa2015-03-23 14:22:16 -040041
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050042/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050043 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050044 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040045
Kevin O'Connor27065322015-11-28 14:25:41 -050046struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050047 /* length of the TCPA log buffer */
48 u32 log_area_minimum_length;
49
50 /* start address of TCPA log buffer */
51 u8 * log_area_start_address;
52
53 /* number of log entries written */
54 u32 entry_count;
55
56 /* address to write next log entry to */
57 u8 * log_area_next_entry;
58
59 /* address of last entry written (need for TCG_StatusCheck) */
60 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050061} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050062
Stefan Berger115d0082016-01-07 12:02:49 -050063static int TPM_has_physical_presence;
64
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050065static struct tcpa_descriptor_rev2 *
66find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
67{
Kevin O'Connor27065322015-11-28 14:25:41 -050068 if (!rsdp) {
69 dprintf(DEBUG_tcg,
70 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
71 return NULL;
72 }
73 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050074 if (!rsdt)
75 return NULL;
76
Kevin O'Connor27065322015-11-28 14:25:41 -050077 u32 length = rsdt->length;
78 u16 off = offsetof(struct rsdt_descriptor, entry);
79 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050080 while ((off + sizeof(rsdt->entry[0])) <= length) {
81 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -050082 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050083
84 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -050085 if (tcpa->signature == TCPA_SIGNATURE
86 && checksum(tcpa, tcpa->length) == 0)
87 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050088
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050089 off += sizeof(rsdt->entry[0]);
90 ctr++;
91 }
92
Kevin O'Connor27065322015-11-28 14:25:41 -050093 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
94 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050095}
96
Kevin O'Connor27065322015-11-28 14:25:41 -050097static int
98tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050099{
Kevin O'Connor27065322015-11-28 14:25:41 -0500100 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
101 if (!tcpa)
102 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500103
Kevin O'Connor27065322015-11-28 14:25:41 -0500104 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
105 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
106 if (!log_area_start_address || !log_area_minimum_length)
107 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500108
Kevin O'Connor27065322015-11-28 14:25:41 -0500109 memset(log_area_start_address, 0, log_area_minimum_length);
110 tpm_state.log_area_start_address = log_area_start_address;
111 tpm_state.log_area_minimum_length = log_area_minimum_length;
112 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500113 tpm_state.log_area_last_entry = NULL;
114 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500115 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500116}
117
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500118/*
119 * Extend the ACPI log with the given entry by copying the
120 * entry data into the log.
121 * Input
122 * pcpes : Pointer to the event 'header' to be copied into the log
123 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500124 *
125 * Output:
126 * Returns an error code in case of faiure, 0 in case of success
127 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500128static int
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500129tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500130{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500131 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
132 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
133
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500134 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500135 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500136
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500137 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500138
139 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
140 tpm_state.log_area_minimum_length) {
141 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500142 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500143 }
144
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500145 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
146 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500147 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500148
149 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
150 tpm_state.log_area_next_entry += size;
151 tpm_state.entry_count++;
152
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500153 return 0;
154}
155
156
157/****************************************************************
158 * Helper functions
159 ****************************************************************/
160
Kevin O'Connord559a232015-11-28 08:35:26 -0500161u8 TPM_working VARLOW;
162
Stefan Berger115d0082016-01-07 12:02:49 -0500163static int
Kevin O'Connord559a232015-11-28 08:35:26 -0500164tpm_is_working(void)
165{
166 return CONFIG_TCGBIOS && TPM_working;
167}
168
Stefan Berger115d0082016-01-07 12:02:49 -0500169int
170tpm_can_show_menu(void)
171{
172 return tpm_is_working() && TPM_has_physical_presence;
173}
174
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400175/*
176 * Send a TPM command with the given ordinal. Append the given buffer
177 * containing all data in network byte order to the command (this is
178 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400179 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500180static int
Stefan Berger47b9df52015-11-21 14:54:40 -0500181build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500182 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400183{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500184 struct {
185 struct tpm_req_header trqh;
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500186 u8 cmd[2];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500187 } PACKED req = {
188 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500189 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500190 .trqh.ordinal = cpu_to_be32(ordinal),
191 };
Stefan Bergerece25612015-11-12 10:14:46 -0500192 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400193 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400194 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400195 memset(obuffer, 0x0, sizeof(obuffer));
196
Kevin O'Connor71479612015-12-29 14:32:19 -0500197 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500198 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500199 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500200 }
201 if (append_size)
202 memcpy(req.cmd, append, append_size);
203
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500204 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
205 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500206 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
207 ordinal, req.cmd[0], req.cmd[1], ret);
208 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400209}
210
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500211static void
212tpm_set_failure(void)
213{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500214 /* we will try to deactivate the TPM now - ignoring all errors */
215 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
216 PhysicalPresence_CMD_ENABLE,
217 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500218 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500219
220 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
221 PhysicalPresence_PRESENT,
222 sizeof(PhysicalPresence_PRESENT),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500223 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500224
225 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500226 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500227
Kevin O'Connord559a232015-11-28 08:35:26 -0500228 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500229}
230
Kevin O'Connorca606362015-12-29 14:21:29 -0500231static int
232tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
233{
234 struct tpm_req_getcap trgc = {
235 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
236 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
237 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
238 .capArea = cpu_to_be32(cap),
239 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
240 .subCap = cpu_to_be32(subcap)
241 };
242 u32 resp_size = rsize;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500243 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
244 TPM_DURATION_TYPE_SHORT);
245 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
Kevin O'Connorca606362015-12-29 14:21:29 -0500246 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
247 " = %x\n", cap, subcap, ret);
248 if (ret) {
249 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
250 tpm_set_failure();
251 }
252 return ret;
253}
254
255static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400256determine_timeouts(void)
257{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400258 struct tpm_res_getcap_timeouts timeouts;
Kevin O'Connorca606362015-12-29 14:21:29 -0500259 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
260 , &timeouts.hdr, sizeof(timeouts));
261 if (ret)
262 return ret;
263
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400264 struct tpm_res_getcap_durations durations;
Kevin O'Connorca606362015-12-29 14:21:29 -0500265 ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
266 , &durations.hdr, sizeof(durations));
267 if (ret)
268 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400269
Kevin O'Connorca606362015-12-29 14:21:29 -0500270 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400271 for (i = 0; i < 3; i++)
272 durations.durations[i] = be32_to_cpu(durations.durations[i]);
273
274 for (i = 0; i < 4; i++)
275 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
276
277 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
278 timeouts.timeouts[0],
279 timeouts.timeouts[1],
280 timeouts.timeouts[2],
281 timeouts.timeouts[3]);
282
283 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
284 durations.durations[0],
285 durations.durations[1],
286 durations.durations[2]);
287
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500288 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400289
290 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400291}
292
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500293static int
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500294tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500295{
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500296 if (pcpes->pcrindex >= 24)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500297 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500298
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500299 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500300 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
301 .hdr.totlen = cpu_to_be32(sizeof(tre)),
302 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
303 .pcrindex = cpu_to_be32(pcpes->pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500304 };
305 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
306
307 struct tpm_rsp_extend rsp;
308 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500309 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
310 TPM_DURATION_TYPE_SHORT);
311 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500312 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500313
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500314 return tpm_log_event(pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500315}
316
Kevin O'Connor92244402015-11-22 16:54:18 -0500317static void
318tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
319{
320 if (hashdata)
321 sha1(hashdata, hashdata_length, pcpes->digest);
322}
323
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500324/*
325 * Add a measurement to the log; the data at data_seg:data/length are
326 * appended to the TCG_PCClientPCREventStruct
327 *
328 * Input parameters:
329 * pcrindex : which PCR to extend
330 * event_type : type of event; specs section on 'Event Types'
331 * event : pointer to info (e.g., string) to be added to log as-is
332 * event_length: length of the event
333 * hashdata : pointer to the data to be hashed
334 * hashdata_length: length of the data to be hashed
335 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500336static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500337tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
338 const char *event, u32 event_length,
339 const u8 *hashdata, u32 hashdata_length)
340{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500341 if (!tpm_is_working())
342 return;
343
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500344 struct pcpes pcpes = {
345 .pcrindex = pcrindex,
346 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500347 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500348 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500349 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500350 int ret = tpm_log_extend_event(&pcpes, event);
351 if (ret)
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500352 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500353}
354
355
356/****************************************************************
357 * Setup and Measurements
358 ****************************************************************/
359
Kevin O'Connora6175422015-11-22 11:28:14 -0500360// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500361static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500362tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500363{
Kevin O'Connora6175422015-11-22 11:28:14 -0500364 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500365 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
366 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500367}
368
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500369/*
370 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
371 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500372static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500373tpm_add_event_separators(void)
374{
Kevin O'Connora6175422015-11-22 11:28:14 -0500375 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500376 u32 pcrIndex;
377 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
378 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
379 NULL, 0,
380 evt_separator,
381 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500382}
383
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500384static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500385tpm_smbios_measure(void)
386{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500387 struct pcctes pcctes = {
388 .eventid = 1,
389 .eventdatasize = SHA1_BUFSIZE,
390 };
391 struct smbios_entry_point *sep = SMBiosAddr;
392
393 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
394
395 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500396 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500397
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500398 sha1((const u8 *)sep->structure_table_address,
399 sep->structure_table_length, pcctes.digest);
400 tpm_add_measurement_to_log(1,
401 EV_EVENT_TAG,
402 (const char *)&pcctes, sizeof(pcctes),
403 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500404}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400405
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500406static int
Stefan Bergere55e37f2016-01-07 12:02:47 -0500407read_permanent_flags(char *buf, int buf_len)
408{
409 memset(buf, 0, buf_len);
410
411 struct tpm_res_getcap_perm_flags pf;
412 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
413 , &pf.hdr, sizeof(pf));
414 if (ret)
415 return -1;
416
417 memcpy(buf, &pf.perm_flags, buf_len);
418
419 return 0;
420}
421
422static int
Stefan Bergera2206d32016-01-07 12:02:48 -0500423assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500424{
Stefan Bergera2206d32016-01-07 12:02:48 -0500425 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
426 PhysicalPresence_PRESENT,
427 sizeof(PhysicalPresence_PRESENT),
428 TPM_DURATION_TYPE_SHORT);
429 if (!ret)
430 return 0;
431
432 struct tpm_permanent_flags pf;
433 ret = read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500434 if (ret)
435 return -1;
436
Stefan Bergera2206d32016-01-07 12:02:48 -0500437 /* check if hardware physical presence is supported */
438 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
439 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -0500440 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -0500441 }
442
Stefan Bergera2206d32016-01-07 12:02:48 -0500443 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
444 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
445 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
446 PhysicalPresence_CMD_ENABLE,
447 sizeof(PhysicalPresence_CMD_ENABLE),
448 TPM_DURATION_TYPE_SHORT);
449
450 return build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
451 PhysicalPresence_PRESENT,
452 sizeof(PhysicalPresence_PRESENT),
453 TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -0500454 }
Stefan Bergere55e37f2016-01-07 12:02:47 -0500455 return -1;
456}
457
458static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400459tpm_startup(void)
460{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400461 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500462 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
463 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
464 TPM_DURATION_TYPE_SHORT);
465 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400466 /* with other firmware on the system the TPM may already have been
467 * initialized
468 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500469 ret = 0;
470 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400471 goto err_exit;
472
Stefan Berger115d0082016-01-07 12:02:49 -0500473 /* assertion of physical presence is only possible after startup */
474 ret = assert_physical_presence();
475 if (!ret)
476 TPM_has_physical_presence = 1;
477
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500478 ret = determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500479 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500480 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500481
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500482 ret = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
483 TPM_DURATION_TYPE_LONG);
484 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400485 goto err_exit;
486
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500487 ret = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
488 TPM_DURATION_TYPE_SHORT);
489 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400490 goto err_exit;
491
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400492 return 0;
493
494err_exit:
495 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
496
Stefan Berger7fce1d92015-11-12 10:14:45 -0500497 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500498 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400499}
500
Kevin O'Connord6aca442015-06-10 11:00:17 -0400501void
502tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400503{
504 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400505 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400506
Kevin O'Connor27065322015-11-28 14:25:41 -0500507 int ret = tpmhw_probe();
508 if (ret)
509 return;
510
511 ret = tpm_tcpa_probe();
512 if (ret)
513 return;
514
515 TPM_working = 1;
516
Quan Xu67643952015-04-30 19:43:04 -0400517 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400518 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400519
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500520 ret = tpm_startup();
521 if (ret)
522 return;
523
524 tpm_smbios_measure();
525 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400526}
527
Kevin O'Connord6aca442015-06-10 11:00:17 -0400528void
529tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400530{
Kevin O'Connord559a232015-11-28 08:35:26 -0500531 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400532 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400533
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500534 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
535 PhysicalPresence_CMD_ENABLE,
536 sizeof(PhysicalPresence_CMD_ENABLE),
537 TPM_DURATION_TYPE_SHORT);
538 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400539 goto err_exit;
540
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500541 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
542 PhysicalPresence_NOT_PRESENT_LOCK,
543 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
544 TPM_DURATION_TYPE_SHORT);
545 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400546 goto err_exit;
547
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500548 tpm_add_action(4, "Calling INT 19h");
549 tpm_add_event_separators();
Stefan Berger2aff1c12015-05-26 15:48:33 -0400550
Kevin O'Connord6aca442015-06-10 11:00:17 -0400551 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400552
553err_exit:
554 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
555
Stefan Berger7fce1d92015-11-12 10:14:45 -0500556 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400557}
558
Stefan Berger5aa2a752015-03-23 14:22:17 -0400559/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500560 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400561 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500562void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500563tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400564{
Kevin O'Connord559a232015-11-28 08:35:26 -0500565 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500566 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500567
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500568 struct pcctes_romex pcctes = {
569 .eventid = 7,
570 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400571 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500572 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500573 tpm_add_measurement_to_log(2,
574 EV_EVENT_TAG,
575 (const char *)&pcctes, sizeof(pcctes),
576 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500577}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400578
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500579void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400580tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
581{
Kevin O'Connord559a232015-11-28 08:35:26 -0500582 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500583 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400584
Stefan Berger4cdbc412015-11-30 11:14:18 -0500585 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500586 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500587
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500588 const char *string = "Booting BCV device 00h (Floppy)";
589 if (bootdrv == 0x80)
590 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500591 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400592
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500593 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
594 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500595 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500596 tpm_add_measurement_to_log(4, EV_IPL,
597 string, strlen(string),
598 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500599
600 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
601 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500602 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
603 string, strlen(string),
604 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400605}
606
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500607void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400608tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
609{
Kevin O'Connord559a232015-11-28 08:35:26 -0500610 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500611 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400612
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500613 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400614
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500615 /* specs: see section 'El Torito' */
616 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500617 tpm_add_measurement_to_log(4, EV_IPL,
618 string, strlen(string),
619 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400620}
621
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500622void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400623tpm_add_cdrom_catalog(const u8 *addr, u32 length)
624{
Kevin O'Connord559a232015-11-28 08:35:26 -0500625 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500626 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400627
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500628 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400629
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500630 /* specs: see section 'El Torito' */
631 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500632 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
633 string, strlen(string),
634 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400635}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400636
Kevin O'Connord6aca442015-06-10 11:00:17 -0400637void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400638tpm_s3_resume(void)
639{
Kevin O'Connord559a232015-11-28 08:35:26 -0500640 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400641 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400642
643 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
644
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500645 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
646 Startup_ST_STATE, sizeof(Startup_ST_STATE),
647 TPM_DURATION_TYPE_SHORT);
648 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400649 goto err_exit;
650
Kevin O'Connord6aca442015-06-10 11:00:17 -0400651 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400652
653err_exit:
654 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
655
Stefan Berger7fce1d92015-11-12 10:14:45 -0500656 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400657}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500658
659
660/****************************************************************
661 * BIOS interface
662 ****************************************************************/
663
Kevin O'Connor59076132015-11-28 13:55:09 -0500664u8 TPM_interface_shutdown VARLOW;
665
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500666static inline void *input_buf32(struct bregs *regs)
667{
668 return MAKE_FLATPTR(regs->es, regs->di);
669}
670
671static inline void *output_buf32(struct bregs *regs)
672{
673 return MAKE_FLATPTR(regs->ds, regs->si);
674}
675
676static u32
677hash_log_extend_event_int(const struct hleei_short *hleei_s,
678 struct hleeo *hleeo)
679{
680 u32 rc = 0;
681 struct hleo hleo;
682 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
683 const void *logdataptr;
684 u32 logdatalen;
685 struct pcpes *pcpes;
686 u32 pcrindex;
687
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500688 /* short or long version? */
689 switch (hleei_s->ipblength) {
690 case sizeof(struct hleei_short):
691 /* short */
692 logdataptr = hleei_s->logdataptr;
693 logdatalen = hleei_s->logdatalen;
694 pcrindex = hleei_s->pcrindex;
695 break;
696
697 case sizeof(struct hleei_long):
698 /* long */
699 logdataptr = hleei_l->logdataptr;
700 logdatalen = hleei_l->logdatalen;
701 pcrindex = hleei_l->pcrindex;
702 break;
703
704 default:
705 /* bad input block */
706 rc = TCG_INVALID_INPUT_PARA;
707 goto err_exit;
708 }
709
710 pcpes = (struct pcpes *)logdataptr;
711
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500712 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
713 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500714 rc = TCG_INVALID_INPUT_PARA;
715 goto err_exit;
716 }
717
Kevin O'Connor92244402015-11-22 16:54:18 -0500718 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500719 int ret = tpm_log_extend_event(pcpes, pcpes->event);
720 if (ret) {
721 rc = TCG_TCG_COMMAND_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500722 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500723 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500724
725 hleeo->opblength = sizeof(struct hleeo);
726 hleeo->reserved = 0;
727 hleeo->eventnumber = hleo.eventnumber;
Stefan Berger2b237502016-01-07 12:02:46 -0500728 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500729
730err_exit:
731 if (rc != 0) {
732 hleeo->opblength = 4;
733 hleeo->reserved = 0;
734 }
735
736 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500737}
738
739static u32
740pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
741{
742 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500743 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500744
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500745 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
746 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
747 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500748 rc = TCG_INVALID_INPUT_PARA;
749 goto err_exit;
750 }
751
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500752 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500753 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
754 TPM_DURATION_TYPE_LONG /* worst case */);
755 if (ret) {
756 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500757 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500758 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500759
760 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
761 pttto->reserved = 0;
762
763err_exit:
764 if (rc != 0) {
765 pttto->opblength = 4;
766 pttto->reserved = 0;
767 }
768
769 return rc;
770}
771
772static u32
773shutdown_preboot_interface(void)
774{
Kevin O'Connor59076132015-11-28 13:55:09 -0500775 TPM_interface_shutdown = 1;
776 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500777}
778
779static u32
780hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
781{
782 u32 rc = 0;
783 u16 size;
784 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500785
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500786 size = hlei->ipblength;
787 if (size != sizeof(*hlei)) {
788 rc = TCG_INVALID_INPUT_PARA;
789 goto err_exit;
790 }
791
792 pcpes = (struct pcpes *)hlei->logdataptr;
793
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500794 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
795 || pcpes->eventtype != hlei->logeventtype
796 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500797 rc = TCG_INVALID_INPUT_PARA;
798 goto err_exit;
799 }
800
Kevin O'Connor92244402015-11-22 16:54:18 -0500801 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500802 int ret = tpm_log_event(pcpes, pcpes->event);
803 if (ret) {
804 rc = TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500805 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500806 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500807
808 /* updating the log was fine */
809 hleo->opblength = sizeof(struct hleo);
810 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500811 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500812
813err_exit:
814 if (rc != 0) {
815 hleo->opblength = 2;
816 hleo->reserved = 0;
817 }
818
819 return rc;
820}
821
822static u32
823hash_all_int(const struct hai *hai, u8 *hash)
824{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500825 if (hai->ipblength != sizeof(struct hai) ||
826 hai->hashdataptr == 0 ||
827 hai->hashdatalen == 0 ||
828 hai->algorithmid != TPM_ALG_SHA)
829 return TCG_INVALID_INPUT_PARA;
830
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500831 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
832 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500833}
834
835static u32
836tss_int(struct ti *ti, struct to *to)
837{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500838 to->opblength = sizeof(struct to);
839 to->reserved = 0;
840
Kevin O'Connor59076132015-11-28 13:55:09 -0500841 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500842}
843
844static u32
845compact_hash_log_extend_event_int(u8 *buffer,
846 u32 info,
847 u32 length,
848 u32 pcrindex,
849 u32 *edx_ptr)
850{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500851 struct pcpes pcpes = {
852 .pcrindex = pcrindex,
853 .eventtype = EV_COMPACT_HASH,
854 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500855 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500856
Kevin O'Connor92244402015-11-22 16:54:18 -0500857 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500858 int ret = tpm_log_extend_event(&pcpes, &info);
859 if (ret)
860 return TCG_TCG_COMMAND_ERROR;
861 *edx_ptr = tpm_state.entry_count;
862 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500863}
864
865void VISIBLE32FLAT
866tpm_interrupt_handler32(struct bregs *regs)
867{
868 if (!CONFIG_TCGBIOS)
869 return;
870
871 set_cf(regs, 0);
872
Kevin O'Connor59076132015-11-28 13:55:09 -0500873 if (TPM_interface_shutdown && regs->al) {
874 regs->eax = TCG_INTERFACE_SHUTDOWN;
875 return;
876 }
877
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500878 switch ((enum irq_ids)regs->al) {
879 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -0500880 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500881 /* no TPM available */
882 regs->eax = TCG_PC_TPM_NOT_PRESENT;
883 } else {
884 regs->eax = 0;
885 regs->ebx = TCG_MAGIC;
886 regs->ch = TCG_VERSION_MAJOR;
887 regs->cl = TCG_VERSION_MINOR;
888 regs->edx = 0x0;
889 regs->esi = (u32)tpm_state.log_area_start_address;
890 regs->edi = (u32)tpm_state.log_area_last_entry;
891 }
892 break;
893
894 case TCG_HashLogExtendEvent:
895 regs->eax =
896 hash_log_extend_event_int(
897 (struct hleei_short *)input_buf32(regs),
898 (struct hleeo *)output_buf32(regs));
899 break;
900
901 case TCG_PassThroughToTPM:
902 regs->eax =
903 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
904 (struct pttto *)output_buf32(regs));
905 break;
906
907 case TCG_ShutdownPreBootInterface:
908 regs->eax = shutdown_preboot_interface();
909 break;
910
911 case TCG_HashLogEvent:
912 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
913 (struct hleo*)output_buf32(regs));
914 break;
915
916 case TCG_HashAll:
917 regs->eax =
918 hash_all_int((struct hai*)input_buf32(regs),
919 (u8 *)output_buf32(regs));
920 break;
921
922 case TCG_TSS:
923 regs->eax = tss_int((struct ti*)input_buf32(regs),
924 (struct to*)output_buf32(regs));
925 break;
926
927 case TCG_CompactHashLogExtendEvent:
928 regs->eax =
929 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
930 regs->esi,
931 regs->ecx,
932 regs->edx,
933 &regs->edx);
934 break;
935
936 default:
937 set_cf(regs, 1);
938 }
939
940 return;
941}
Stefan Berger320df852015-11-30 11:14:19 -0500942
Kevin O'Connor26e36172015-12-29 12:20:23 -0500943
944/****************************************************************
945 * TPM Configuration Menu
946 ****************************************************************/
947
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500948static int
Stefan Berger320df852015-11-30 11:14:19 -0500949read_has_owner(int *has_owner)
950{
Stefan Berger320df852015-11-30 11:14:19 -0500951 struct tpm_res_getcap_ownerauth oauth;
Kevin O'Connorca606362015-12-29 14:21:29 -0500952 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
953 , &oauth.hdr, sizeof(oauth));
954 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500955 return -1;
Stefan Berger320df852015-11-30 11:14:19 -0500956
957 *has_owner = oauth.flag;
958
959 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500960}
961
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500962static int
963enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -0500964{
Stefan Berger320df852015-11-30 11:14:19 -0500965 struct tpm_permanent_flags pf;
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500966 int ret = read_permanent_flags((char *)&pf, sizeof(pf));
967 if (ret)
968 return -1;
Stefan Berger320df852015-11-30 11:14:19 -0500969
970 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
971 return 0;
972
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500973 ret = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
974 : TPM_ORD_PhysicalDisable,
975 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500976 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -0500977 goto err_exit;
978
979 return 0;
980
981err_exit:
982 if (enable)
983 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
984 else
985 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
986
987 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
988
989 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500990 return ret;
Stefan Berger320df852015-11-30 11:14:19 -0500991}
992
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500993static int
994activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -0500995{
Stefan Berger320df852015-11-30 11:14:19 -0500996 struct tpm_permanent_flags pf;
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500997 int ret = read_permanent_flags((char *)&pf, sizeof(pf));
998 if (ret)
999 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001000
1001 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1002 return 0;
1003
1004 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1005 return 0;
1006
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001007 ret = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1008 activate ? CommandFlag_FALSE
1009 : CommandFlag_TRUE,
1010 activate ? sizeof(CommandFlag_FALSE)
1011 : sizeof(CommandFlag_TRUE),
1012 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001013 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001014 goto err_exit;
1015
1016 if (activate && allow_reset) {
1017 if (verbose) {
1018 printf("Requiring a reboot to activate the TPM.\n");
1019
1020 msleep(2000);
1021 }
1022 reset();
1023 }
1024
1025 return 0;
1026
1027err_exit:
1028 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1029
1030 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001031 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001032}
1033
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001034static int
1035enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001036{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001037 int ret = enable_tpm(1, verbose);
1038 if (ret)
1039 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001040
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001041 return activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001042}
1043
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001044static int
1045force_clear(int enable_activate_before, int enable_activate_after, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001046{
Stefan Berger320df852015-11-30 11:14:19 -05001047 int has_owner;
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001048 int ret = read_has_owner(&has_owner);
1049 if (ret)
1050 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001051 if (!has_owner) {
1052 if (verbose)
1053 printf("TPM does not have an owner.\n");
1054 return 0;
1055 }
1056
1057 if (enable_activate_before) {
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001058 ret = enable_activate(0, verbose);
1059 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001060 dprintf(DEBUG_tcg,
1061 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001062 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001063 }
1064 }
1065
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001066 ret = build_and_send_cmd(0, TPM_ORD_ForceClear,
1067 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001068 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001069 goto err_exit;
1070
1071 if (!enable_activate_after) {
1072 if (verbose)
1073 printf("Owner successfully cleared.\n"
1074 "You will need to enable/activate the TPM again.\n\n");
1075 return 0;
1076 }
1077
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001078 return enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001079
1080err_exit:
1081 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1082
1083 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001084 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001085}
1086
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001087static int
1088set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001089{
Stefan Berger320df852015-11-30 11:14:19 -05001090 int has_owner;
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001091 int ret = read_has_owner(&has_owner);
1092 if (ret)
1093 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001094 if (has_owner) {
1095 if (verbose)
1096 printf("Must first remove owner.\n");
1097 return 0;
1098 }
1099
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001100 struct tpm_permanent_flags pf;
1101 ret = read_permanent_flags((char *)&pf, sizeof(pf));
1102 if (ret)
1103 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001104
1105 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1106 if (verbose)
1107 printf("TPM must first be enable.\n");
1108 return 0;
1109 }
1110
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001111 ret = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1112 (allow) ? CommandFlag_TRUE
1113 : CommandFlag_FALSE,
1114 sizeof(CommandFlag_TRUE),
1115 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001116 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001117 goto err_exit;
1118
1119 if (verbose)
1120 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1121
1122 return 0;
1123
1124err_exit:
1125 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1126 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001127 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001128}
1129
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001130static int
1131tpm_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001132{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001133 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001134
1135 switch (msgCode) {
1136 case TPM_PPI_OP_NOOP: /* no-op */
1137 break;
1138
1139 case TPM_PPI_OP_ENABLE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001140 ret = enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001141 break;
1142
1143 case TPM_PPI_OP_DISABLE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001144 ret = enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001145 break;
1146
1147 case TPM_PPI_OP_ACTIVATE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001148 ret = activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001149 break;
1150
1151 case TPM_PPI_OP_DEACTIVATE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001152 ret = activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001153 break;
1154
1155 case TPM_PPI_OP_CLEAR:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001156 ret = force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001157 break;
1158
1159 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001160 ret = set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001161 break;
1162
1163 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001164 ret = set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001165 break;
1166
1167 default:
1168 break;
1169 }
1170
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001171 if (ret)
1172 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001173
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001174 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001175}
1176
1177static int
1178get_tpm_state(void)
1179{
1180 int state = 0;
1181 struct tpm_permanent_flags pf;
1182 int has_owner;
1183
1184 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1185 read_has_owner(&has_owner))
1186 return ~0;
1187
1188 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1189 state |= TPM_STATE_ENABLED;
1190
1191 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1192 state |= TPM_STATE_ACTIVE;
1193
1194 if (has_owner) {
1195 state |= TPM_STATE_OWNED;
1196 } else {
1197 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1198 state |= TPM_STATE_OWNERINSTALL;
1199 }
1200
1201 return state;
1202}
1203
1204static void
1205show_tpm_menu(int state, int next_scancodes[7])
1206{
1207 int i = 0;
1208
1209 printf("\nThe current state of the TPM is:\n");
1210
1211 if (state & TPM_STATE_ENABLED)
1212 printf(" Enabled");
1213 else
1214 printf(" Disabled");
1215
1216 if (state & TPM_STATE_ACTIVE)
1217 printf(" and active\n");
1218 else
1219 printf(" and deactivated\n");
1220
1221 if (state & TPM_STATE_OWNED)
1222 printf(" Ownership has been taken\n");
1223 else {
1224 printf(" Ownership has not been taken\n");
1225 if (state & TPM_STATE_OWNERINSTALL)
1226 printf(" A user can take ownership of the TPM\n");
1227 else
1228 printf(" Taking ownership of the TPM has been disabled\n");
1229 }
1230
1231 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1232 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1233 printf("\nNote: To make use of all functionality, the TPM must be "
1234 "enabled and active.\n");
1235 }
1236
1237 printf("\nAvailable options are:\n");
1238 if (state & TPM_STATE_ENABLED) {
1239 printf(" d. Disable the TPM\n");
1240 next_scancodes[i++] = 32;
1241
1242 if (state & TPM_STATE_ACTIVE) {
1243 printf(" v. Deactivate the TPM\n");
1244 next_scancodes[i++] = 47;
1245
1246 if (state & TPM_STATE_OWNERINSTALL) {
1247 printf(" p. Prevent installation of an owner\n");
1248 next_scancodes[i++] = 25;
1249 } else {
1250 printf(" s. Allow installation of an owner\n");
1251 next_scancodes[i++] = 31;
1252 }
1253 } else {
1254 printf(" a. Activate the TPM\n");
1255 next_scancodes[i++] = 30;
1256 }
1257
1258 } else {
1259 printf(" e. Enable the TPM\n");
1260 next_scancodes[i++] = 18;
1261 }
1262
1263 if (state & TPM_STATE_OWNED) {
1264 printf(" c. Clear ownership\n");
1265 next_scancodes[i++] = 46;
1266 }
1267
1268 next_scancodes[i++] = 0;
1269}
1270
1271void
1272tpm_menu(void)
1273{
1274 if (!CONFIG_TCGBIOS)
1275 return;
1276
1277 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001278 tpm_ppi_code msgCode;
1279 int state = 0, i;
1280 int waitkey;
1281
1282 while (get_keystroke(0) >= 0)
1283 ;
1284 wait_threads();
1285
1286 printf("The Trusted Platform Module (TPM) is a hardware device in "
1287 "this machine.\n"
1288 "It can help verify the integrity of system software.\n\n");
1289
1290 for (;;) {
1291 if ((state = get_tpm_state()) != ~0) {
1292 show_tpm_menu(state, next_scancodes);
1293 } else {
1294 printf("TPM is not working correctly.\n");
1295 return;
1296 }
1297
1298 printf("\nIf no change is desired or if this menu was reached by "
1299 "mistake, press ESC to\n"
1300 "reboot the machine.\n");
1301
1302 msgCode = TPM_PPI_OP_NOOP;
1303
1304 waitkey = 1;
1305
1306 while (waitkey) {
1307 while ((scancode = get_keystroke(1000)) == ~0)
1308 ;
1309
1310 switch (scancode) {
1311 case 1:
1312 // ESC
1313 reset();
1314 break;
1315 case 18: /* e. enable */
1316 msgCode = TPM_PPI_OP_ENABLE;
1317 break;
1318 case 32: /* d. disable */
1319 msgCode = TPM_PPI_OP_DISABLE;
1320 break;
1321 case 30: /* a. activate */
1322 msgCode = TPM_PPI_OP_ACTIVATE;
1323 break;
1324 case 47: /* v. deactivate */
1325 msgCode = TPM_PPI_OP_DEACTIVATE;
1326 break;
1327 case 46: /* c. clear owner */
1328 msgCode = TPM_PPI_OP_CLEAR;
1329 break;
1330 case 25: /* p. prevent ownerinstall */
1331 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1332 break;
1333 case 31: /* s. allow ownerinstall */
1334 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1335 break;
1336 default:
1337 continue;
1338 }
1339
1340 /*
1341 * Using the next_scancodes array, check whether the
1342 * pressed key is currently a valid option.
1343 */
1344 for (i = 0; i < sizeof(next_scancodes); i++) {
1345 if (next_scancodes[i] == 0)
1346 break;
1347
1348 if (next_scancodes[i] == scancode) {
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001349 tpm_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001350 waitkey = 0;
1351 break;
1352 }
1353 }
1354 }
1355 }
1356}