blob: aa93e5e2d58f0f6e783d6f00336e0f1652ea6c42 [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
63static struct tcpa_descriptor_rev2 *
64find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
65{
Kevin O'Connor27065322015-11-28 14:25:41 -050066 if (!rsdp) {
67 dprintf(DEBUG_tcg,
68 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
69 return NULL;
70 }
71 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050072 if (!rsdt)
73 return NULL;
74
Kevin O'Connor27065322015-11-28 14:25:41 -050075 u32 length = rsdt->length;
76 u16 off = offsetof(struct rsdt_descriptor, entry);
77 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050078 while ((off + sizeof(rsdt->entry[0])) <= length) {
79 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -050080 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050081
82 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -050083 if (tcpa->signature == TCPA_SIGNATURE
84 && checksum(tcpa, tcpa->length) == 0)
85 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050086
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050087 off += sizeof(rsdt->entry[0]);
88 ctr++;
89 }
90
Kevin O'Connor27065322015-11-28 14:25:41 -050091 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
92 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050093}
94
Kevin O'Connor27065322015-11-28 14:25:41 -050095static int
96tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050097{
Kevin O'Connor27065322015-11-28 14:25:41 -050098 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
99 if (!tcpa)
100 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500101
Kevin O'Connor27065322015-11-28 14:25:41 -0500102 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
103 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
104 if (!log_area_start_address || !log_area_minimum_length)
105 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500106
Kevin O'Connor27065322015-11-28 14:25:41 -0500107 memset(log_area_start_address, 0, log_area_minimum_length);
108 tpm_state.log_area_start_address = log_area_start_address;
109 tpm_state.log_area_minimum_length = log_area_minimum_length;
110 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500111 tpm_state.log_area_last_entry = NULL;
112 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500113 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500114}
115
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500116/*
117 * Extend the ACPI log with the given entry by copying the
118 * entry data into the log.
119 * Input
120 * pcpes : Pointer to the event 'header' to be copied into the log
121 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500122 *
123 * Output:
124 * Returns an error code in case of faiure, 0 in case of success
125 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500126static int
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500127tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500128{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500129 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
130 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
131
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500132 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500133 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500134
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500135 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500136
137 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
138 tpm_state.log_area_minimum_length) {
139 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500140 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500141 }
142
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500143 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
144 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500145 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500146
147 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
148 tpm_state.log_area_next_entry += size;
149 tpm_state.entry_count++;
150
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500151 return 0;
152}
153
154
155/****************************************************************
156 * Helper functions
157 ****************************************************************/
158
Kevin O'Connord559a232015-11-28 08:35:26 -0500159u8 TPM_working VARLOW;
160
161int
162tpm_is_working(void)
163{
164 return CONFIG_TCGBIOS && TPM_working;
165}
166
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400167/*
168 * Send a TPM command with the given ordinal. Append the given buffer
169 * containing all data in network byte order to the command (this is
170 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400171 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500172static int
Stefan Berger47b9df52015-11-21 14:54:40 -0500173build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500174 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400175{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500176 struct {
177 struct tpm_req_header trqh;
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500178 u8 cmd[2];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500179 } PACKED req = {
180 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500181 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500182 .trqh.ordinal = cpu_to_be32(ordinal),
183 };
Stefan Bergerece25612015-11-12 10:14:46 -0500184 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400185 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400186 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400187 memset(obuffer, 0x0, sizeof(obuffer));
188
Kevin O'Connor71479612015-12-29 14:32:19 -0500189 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500190 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500191 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500192 }
193 if (append_size)
194 memcpy(req.cmd, append, append_size);
195
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500196 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
197 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500198 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
199 ordinal, req.cmd[0], req.cmd[1], ret);
200 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400201}
202
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500203static void
204tpm_set_failure(void)
205{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500206 /* we will try to deactivate the TPM now - ignoring all errors */
207 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
208 PhysicalPresence_CMD_ENABLE,
209 sizeof(PhysicalPresence_CMD_ENABLE),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500210 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500211
212 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
213 PhysicalPresence_PRESENT,
214 sizeof(PhysicalPresence_PRESENT),
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500215 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500216
217 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500218 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500219
Kevin O'Connord559a232015-11-28 08:35:26 -0500220 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500221}
222
Kevin O'Connorca606362015-12-29 14:21:29 -0500223static int
224tpm_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
225{
226 struct tpm_req_getcap trgc = {
227 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
228 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
229 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
230 .capArea = cpu_to_be32(cap),
231 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
232 .subCap = cpu_to_be32(subcap)
233 };
234 u32 resp_size = rsize;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500235 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
236 TPM_DURATION_TYPE_SHORT);
237 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
Kevin O'Connorca606362015-12-29 14:21:29 -0500238 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
239 " = %x\n", cap, subcap, ret);
240 if (ret) {
241 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
242 tpm_set_failure();
243 }
244 return ret;
245}
246
247static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400248determine_timeouts(void)
249{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400250 struct tpm_res_getcap_timeouts timeouts;
Kevin O'Connorca606362015-12-29 14:21:29 -0500251 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
252 , &timeouts.hdr, sizeof(timeouts));
253 if (ret)
254 return ret;
255
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400256 struct tpm_res_getcap_durations durations;
Kevin O'Connorca606362015-12-29 14:21:29 -0500257 ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
258 , &durations.hdr, sizeof(durations));
259 if (ret)
260 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400261
Kevin O'Connorca606362015-12-29 14:21:29 -0500262 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400263 for (i = 0; i < 3; i++)
264 durations.durations[i] = be32_to_cpu(durations.durations[i]);
265
266 for (i = 0; i < 4; i++)
267 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
268
269 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
270 timeouts.timeouts[0],
271 timeouts.timeouts[1],
272 timeouts.timeouts[2],
273 timeouts.timeouts[3]);
274
275 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
276 durations.durations[0],
277 durations.durations[1],
278 durations.durations[2]);
279
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500280 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400281
282 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400283}
284
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500285static int
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500286tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500287{
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500288 if (pcpes->pcrindex >= 24)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500289 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500290
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500291 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500292 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
293 .hdr.totlen = cpu_to_be32(sizeof(tre)),
294 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
295 .pcrindex = cpu_to_be32(pcpes->pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500296 };
297 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
298
299 struct tpm_rsp_extend rsp;
300 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500301 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
302 TPM_DURATION_TYPE_SHORT);
303 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500304 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500305
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500306 return tpm_log_event(pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500307}
308
Kevin O'Connor92244402015-11-22 16:54:18 -0500309static void
310tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
311{
312 if (hashdata)
313 sha1(hashdata, hashdata_length, pcpes->digest);
314}
315
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500316/*
317 * Add a measurement to the log; the data at data_seg:data/length are
318 * appended to the TCG_PCClientPCREventStruct
319 *
320 * Input parameters:
321 * pcrindex : which PCR to extend
322 * event_type : type of event; specs section on 'Event Types'
323 * event : pointer to info (e.g., string) to be added to log as-is
324 * event_length: length of the event
325 * hashdata : pointer to the data to be hashed
326 * hashdata_length: length of the data to be hashed
327 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500328static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500329tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
330 const char *event, u32 event_length,
331 const u8 *hashdata, u32 hashdata_length)
332{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500333 if (!tpm_is_working())
334 return;
335
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500336 struct pcpes pcpes = {
337 .pcrindex = pcrindex,
338 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500339 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500340 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500341 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500342 int ret = tpm_log_extend_event(&pcpes, event);
343 if (ret)
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500344 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500345}
346
347
348/****************************************************************
349 * Setup and Measurements
350 ****************************************************************/
351
Kevin O'Connora6175422015-11-22 11:28:14 -0500352// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500353static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500354tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500355{
Kevin O'Connora6175422015-11-22 11:28:14 -0500356 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500357 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
358 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500359}
360
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500361/*
362 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
363 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500364static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500365tpm_add_event_separators(void)
366{
Kevin O'Connora6175422015-11-22 11:28:14 -0500367 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500368 u32 pcrIndex;
369 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
370 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
371 NULL, 0,
372 evt_separator,
373 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500374}
375
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500376static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500377tpm_smbios_measure(void)
378{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500379 struct pcctes pcctes = {
380 .eventid = 1,
381 .eventdatasize = SHA1_BUFSIZE,
382 };
383 struct smbios_entry_point *sep = SMBiosAddr;
384
385 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
386
387 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500388 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500389
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500390 sha1((const u8 *)sep->structure_table_address,
391 sep->structure_table_length, pcctes.digest);
392 tpm_add_measurement_to_log(1,
393 EV_EVENT_TAG,
394 (const char *)&pcctes, sizeof(pcctes),
395 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500396}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400397
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500398static int
Stefan Bergere55e37f2016-01-07 12:02:47 -0500399read_stclear_flags(char *buf, int buf_len)
400{
401 memset(buf, 0, buf_len);
402
403 struct tpm_res_getcap_stclear_flags stcf;
404 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_VOLATILE
405 , &stcf.hdr, sizeof(stcf));
406 if (ret) {
407 dprintf(DEBUG_tcg, "Error reading STClear flags: 0x%08x\n", ret);
408 return -1;
409 }
410
411 memcpy(buf, &stcf.stclear_flags, buf_len);
412
413 return 0;
414}
415
416static int
417read_permanent_flags(char *buf, int buf_len)
418{
419 memset(buf, 0, buf_len);
420
421 struct tpm_res_getcap_perm_flags pf;
422 int ret = tpm_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
423 , &pf.hdr, sizeof(pf));
424 if (ret)
425 return -1;
426
427 memcpy(buf, &pf.perm_flags, buf_len);
428
429 return 0;
430}
431
432static int
433assert_physical_presence(int verbose)
434{
435 struct tpm_stclear_flags stcf;
436 int ret = read_stclear_flags((char *)&stcf, sizeof(stcf));
437 if (ret)
438 return -1;
439
440 if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
441 /* physical presence already asserted */
442 return 0;
443
444 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
445 PhysicalPresence_CMD_ENABLE,
446 sizeof(PhysicalPresence_CMD_ENABLE),
447 TPM_DURATION_TYPE_SHORT);
448 if (ret) {
449 if (verbose)
450 printf("Error: Could not enable physical presence.\n\n");
451 goto err_exit;
452 }
453
454 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
455 PhysicalPresence_PRESENT,
456 sizeof(PhysicalPresence_PRESENT),
457 TPM_DURATION_TYPE_SHORT);
458 if (ret) {
459 if (verbose)
460 printf("Error: Could not set presence flag.\n\n");
461 goto err_exit;
462 }
463
464 return 0;
465
466err_exit:
467 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
468 tpm_set_failure();
469 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed: %x\n", ret);
470 return -1;
471}
472
473static int
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400474tpm_startup(void)
475{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400476 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500477 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
478 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
479 TPM_DURATION_TYPE_SHORT);
480 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400481 /* with other firmware on the system the TPM may already have been
482 * initialized
483 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500484 ret = 0;
485 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400486 goto err_exit;
487
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500488 ret = determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500489 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500490 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500491
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500492 ret = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
493 TPM_DURATION_TYPE_LONG);
494 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400495 goto err_exit;
496
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500497 ret = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
498 TPM_DURATION_TYPE_SHORT);
499 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400500 goto err_exit;
501
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400502 return 0;
503
504err_exit:
505 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
506
Stefan Berger7fce1d92015-11-12 10:14:45 -0500507 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500508 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400509}
510
Kevin O'Connord6aca442015-06-10 11:00:17 -0400511void
512tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400513{
514 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400515 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400516
Kevin O'Connor27065322015-11-28 14:25:41 -0500517 int ret = tpmhw_probe();
518 if (ret)
519 return;
520
521 ret = tpm_tcpa_probe();
522 if (ret)
523 return;
524
525 TPM_working = 1;
526
Quan Xu67643952015-04-30 19:43:04 -0400527 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400528 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400529
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500530 ret = tpm_startup();
531 if (ret)
532 return;
533
534 tpm_smbios_measure();
535 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400536}
537
Kevin O'Connord6aca442015-06-10 11:00:17 -0400538void
539tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400540{
Kevin O'Connord559a232015-11-28 08:35:26 -0500541 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400542 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400543
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500544 int ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
545 PhysicalPresence_CMD_ENABLE,
546 sizeof(PhysicalPresence_CMD_ENABLE),
547 TPM_DURATION_TYPE_SHORT);
548 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400549 goto err_exit;
550
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500551 ret = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
552 PhysicalPresence_NOT_PRESENT_LOCK,
553 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
554 TPM_DURATION_TYPE_SHORT);
555 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400556 goto err_exit;
557
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500558 tpm_add_action(4, "Calling INT 19h");
559 tpm_add_event_separators();
Stefan Berger2aff1c12015-05-26 15:48:33 -0400560
Kevin O'Connord6aca442015-06-10 11:00:17 -0400561 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400562
563err_exit:
564 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
565
Stefan Berger7fce1d92015-11-12 10:14:45 -0500566 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400567}
568
Stefan Berger5aa2a752015-03-23 14:22:17 -0400569/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500570 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400571 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500572void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500573tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400574{
Kevin O'Connord559a232015-11-28 08:35:26 -0500575 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500576 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500577
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500578 struct pcctes_romex pcctes = {
579 .eventid = 7,
580 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400581 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500582 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500583 tpm_add_measurement_to_log(2,
584 EV_EVENT_TAG,
585 (const char *)&pcctes, sizeof(pcctes),
586 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500587}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400588
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500589void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400590tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
591{
Kevin O'Connord559a232015-11-28 08:35:26 -0500592 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500593 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400594
Stefan Berger4cdbc412015-11-30 11:14:18 -0500595 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500596 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500597
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500598 const char *string = "Booting BCV device 00h (Floppy)";
599 if (bootdrv == 0x80)
600 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500601 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400602
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500603 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
604 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500605 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500606 tpm_add_measurement_to_log(4, EV_IPL,
607 string, strlen(string),
608 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500609
610 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
611 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500612 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
613 string, strlen(string),
614 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400615}
616
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500617void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400618tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
619{
Kevin O'Connord559a232015-11-28 08:35:26 -0500620 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500621 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400622
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500623 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400624
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500625 /* specs: see section 'El Torito' */
626 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500627 tpm_add_measurement_to_log(4, EV_IPL,
628 string, strlen(string),
629 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400630}
631
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500632void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400633tpm_add_cdrom_catalog(const u8 *addr, u32 length)
634{
Kevin O'Connord559a232015-11-28 08:35:26 -0500635 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500636 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400637
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500638 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400639
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500640 /* specs: see section 'El Torito' */
641 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500642 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
643 string, strlen(string),
644 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400645}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400646
Kevin O'Connord6aca442015-06-10 11:00:17 -0400647void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400648tpm_s3_resume(void)
649{
Kevin O'Connord559a232015-11-28 08:35:26 -0500650 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400651 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400652
653 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
654
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500655 int ret = build_and_send_cmd(0, TPM_ORD_Startup,
656 Startup_ST_STATE, sizeof(Startup_ST_STATE),
657 TPM_DURATION_TYPE_SHORT);
658 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400659 goto err_exit;
660
Kevin O'Connord6aca442015-06-10 11:00:17 -0400661 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400662
663err_exit:
664 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
665
Stefan Berger7fce1d92015-11-12 10:14:45 -0500666 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400667}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500668
669
670/****************************************************************
671 * BIOS interface
672 ****************************************************************/
673
Kevin O'Connor59076132015-11-28 13:55:09 -0500674u8 TPM_interface_shutdown VARLOW;
675
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500676static inline void *input_buf32(struct bregs *regs)
677{
678 return MAKE_FLATPTR(regs->es, regs->di);
679}
680
681static inline void *output_buf32(struct bregs *regs)
682{
683 return MAKE_FLATPTR(regs->ds, regs->si);
684}
685
686static u32
687hash_log_extend_event_int(const struct hleei_short *hleei_s,
688 struct hleeo *hleeo)
689{
690 u32 rc = 0;
691 struct hleo hleo;
692 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
693 const void *logdataptr;
694 u32 logdatalen;
695 struct pcpes *pcpes;
696 u32 pcrindex;
697
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500698 /* short or long version? */
699 switch (hleei_s->ipblength) {
700 case sizeof(struct hleei_short):
701 /* short */
702 logdataptr = hleei_s->logdataptr;
703 logdatalen = hleei_s->logdatalen;
704 pcrindex = hleei_s->pcrindex;
705 break;
706
707 case sizeof(struct hleei_long):
708 /* long */
709 logdataptr = hleei_l->logdataptr;
710 logdatalen = hleei_l->logdatalen;
711 pcrindex = hleei_l->pcrindex;
712 break;
713
714 default:
715 /* bad input block */
716 rc = TCG_INVALID_INPUT_PARA;
717 goto err_exit;
718 }
719
720 pcpes = (struct pcpes *)logdataptr;
721
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500722 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
723 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500724 rc = TCG_INVALID_INPUT_PARA;
725 goto err_exit;
726 }
727
Kevin O'Connor92244402015-11-22 16:54:18 -0500728 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500729 int ret = tpm_log_extend_event(pcpes, pcpes->event);
730 if (ret) {
731 rc = TCG_TCG_COMMAND_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500732 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500733 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500734
735 hleeo->opblength = sizeof(struct hleeo);
736 hleeo->reserved = 0;
737 hleeo->eventnumber = hleo.eventnumber;
Stefan Berger2b237502016-01-07 12:02:46 -0500738 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500739
740err_exit:
741 if (rc != 0) {
742 hleeo->opblength = 4;
743 hleeo->reserved = 0;
744 }
745
746 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500747}
748
749static u32
750pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
751{
752 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500753 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500754
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500755 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
756 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
757 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500758 rc = TCG_INVALID_INPUT_PARA;
759 goto err_exit;
760 }
761
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500762 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500763 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
764 TPM_DURATION_TYPE_LONG /* worst case */);
765 if (ret) {
766 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500767 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500768 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500769
770 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
771 pttto->reserved = 0;
772
773err_exit:
774 if (rc != 0) {
775 pttto->opblength = 4;
776 pttto->reserved = 0;
777 }
778
779 return rc;
780}
781
782static u32
783shutdown_preboot_interface(void)
784{
Kevin O'Connor59076132015-11-28 13:55:09 -0500785 TPM_interface_shutdown = 1;
786 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500787}
788
789static u32
790hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
791{
792 u32 rc = 0;
793 u16 size;
794 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500795
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500796 size = hlei->ipblength;
797 if (size != sizeof(*hlei)) {
798 rc = TCG_INVALID_INPUT_PARA;
799 goto err_exit;
800 }
801
802 pcpes = (struct pcpes *)hlei->logdataptr;
803
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500804 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
805 || pcpes->eventtype != hlei->logeventtype
806 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500807 rc = TCG_INVALID_INPUT_PARA;
808 goto err_exit;
809 }
810
Kevin O'Connor92244402015-11-22 16:54:18 -0500811 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500812 int ret = tpm_log_event(pcpes, pcpes->event);
813 if (ret) {
814 rc = TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500815 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500816 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500817
818 /* updating the log was fine */
819 hleo->opblength = sizeof(struct hleo);
820 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -0500821 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500822
823err_exit:
824 if (rc != 0) {
825 hleo->opblength = 2;
826 hleo->reserved = 0;
827 }
828
829 return rc;
830}
831
832static u32
833hash_all_int(const struct hai *hai, u8 *hash)
834{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500835 if (hai->ipblength != sizeof(struct hai) ||
836 hai->hashdataptr == 0 ||
837 hai->hashdatalen == 0 ||
838 hai->algorithmid != TPM_ALG_SHA)
839 return TCG_INVALID_INPUT_PARA;
840
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500841 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
842 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500843}
844
845static u32
846tss_int(struct ti *ti, struct to *to)
847{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500848 to->opblength = sizeof(struct to);
849 to->reserved = 0;
850
Kevin O'Connor59076132015-11-28 13:55:09 -0500851 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500852}
853
854static u32
855compact_hash_log_extend_event_int(u8 *buffer,
856 u32 info,
857 u32 length,
858 u32 pcrindex,
859 u32 *edx_ptr)
860{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500861 struct pcpes pcpes = {
862 .pcrindex = pcrindex,
863 .eventtype = EV_COMPACT_HASH,
864 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500865 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500866
Kevin O'Connor92244402015-11-22 16:54:18 -0500867 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500868 int ret = tpm_log_extend_event(&pcpes, &info);
869 if (ret)
870 return TCG_TCG_COMMAND_ERROR;
871 *edx_ptr = tpm_state.entry_count;
872 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500873}
874
875void VISIBLE32FLAT
876tpm_interrupt_handler32(struct bregs *regs)
877{
878 if (!CONFIG_TCGBIOS)
879 return;
880
881 set_cf(regs, 0);
882
Kevin O'Connor59076132015-11-28 13:55:09 -0500883 if (TPM_interface_shutdown && regs->al) {
884 regs->eax = TCG_INTERFACE_SHUTDOWN;
885 return;
886 }
887
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500888 switch ((enum irq_ids)regs->al) {
889 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -0500890 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500891 /* no TPM available */
892 regs->eax = TCG_PC_TPM_NOT_PRESENT;
893 } else {
894 regs->eax = 0;
895 regs->ebx = TCG_MAGIC;
896 regs->ch = TCG_VERSION_MAJOR;
897 regs->cl = TCG_VERSION_MINOR;
898 regs->edx = 0x0;
899 regs->esi = (u32)tpm_state.log_area_start_address;
900 regs->edi = (u32)tpm_state.log_area_last_entry;
901 }
902 break;
903
904 case TCG_HashLogExtendEvent:
905 regs->eax =
906 hash_log_extend_event_int(
907 (struct hleei_short *)input_buf32(regs),
908 (struct hleeo *)output_buf32(regs));
909 break;
910
911 case TCG_PassThroughToTPM:
912 regs->eax =
913 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
914 (struct pttto *)output_buf32(regs));
915 break;
916
917 case TCG_ShutdownPreBootInterface:
918 regs->eax = shutdown_preboot_interface();
919 break;
920
921 case TCG_HashLogEvent:
922 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
923 (struct hleo*)output_buf32(regs));
924 break;
925
926 case TCG_HashAll:
927 regs->eax =
928 hash_all_int((struct hai*)input_buf32(regs),
929 (u8 *)output_buf32(regs));
930 break;
931
932 case TCG_TSS:
933 regs->eax = tss_int((struct ti*)input_buf32(regs),
934 (struct to*)output_buf32(regs));
935 break;
936
937 case TCG_CompactHashLogExtendEvent:
938 regs->eax =
939 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
940 regs->esi,
941 regs->ecx,
942 regs->edx,
943 &regs->edx);
944 break;
945
946 default:
947 set_cf(regs, 1);
948 }
949
950 return;
951}
Stefan Berger320df852015-11-30 11:14:19 -0500952
Kevin O'Connor26e36172015-12-29 12:20:23 -0500953
954/****************************************************************
955 * TPM Configuration Menu
956 ****************************************************************/
957
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500958static int
Stefan Berger320df852015-11-30 11:14:19 -0500959read_has_owner(int *has_owner)
960{
Stefan Berger320df852015-11-30 11:14:19 -0500961 struct tpm_res_getcap_ownerauth oauth;
Kevin O'Connorca606362015-12-29 14:21:29 -0500962 int ret = tpm_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
963 , &oauth.hdr, sizeof(oauth));
964 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500965 return -1;
Stefan Berger320df852015-11-30 11:14:19 -0500966
967 *has_owner = oauth.flag;
968
969 return 0;
Stefan Berger320df852015-11-30 11:14:19 -0500970}
971
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500972static int
973enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -0500974{
Stefan Berger320df852015-11-30 11:14:19 -0500975 struct tpm_permanent_flags pf;
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500976 int ret = read_permanent_flags((char *)&pf, sizeof(pf));
977 if (ret)
978 return -1;
Stefan Berger320df852015-11-30 11:14:19 -0500979
980 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
981 return 0;
982
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500983 ret = assert_physical_presence(verbose);
984 if (ret)
985 return -1;
Stefan Berger320df852015-11-30 11:14:19 -0500986
Kevin O'Connor16a9e792015-12-29 23:04:15 -0500987 ret = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
988 : TPM_ORD_PhysicalDisable,
989 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500990 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -0500991 goto err_exit;
992
993 return 0;
994
995err_exit:
996 if (enable)
997 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
998 else
999 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1000
1001 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1002
1003 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001004 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001005}
1006
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001007static int
1008activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001009{
Stefan Berger320df852015-11-30 11:14:19 -05001010 struct tpm_permanent_flags pf;
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001011 int ret = read_permanent_flags((char *)&pf, sizeof(pf));
1012 if (ret)
1013 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001014
1015 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1016 return 0;
1017
1018 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1019 return 0;
1020
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001021 ret = assert_physical_presence(verbose);
1022 if (ret)
1023 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001024
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001025 ret = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1026 activate ? CommandFlag_FALSE
1027 : CommandFlag_TRUE,
1028 activate ? sizeof(CommandFlag_FALSE)
1029 : sizeof(CommandFlag_TRUE),
1030 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001031 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001032 goto err_exit;
1033
1034 if (activate && allow_reset) {
1035 if (verbose) {
1036 printf("Requiring a reboot to activate the TPM.\n");
1037
1038 msleep(2000);
1039 }
1040 reset();
1041 }
1042
1043 return 0;
1044
1045err_exit:
1046 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1047
1048 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001049 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001050}
1051
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001052static int
1053enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001054{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001055 int ret = enable_tpm(1, verbose);
1056 if (ret)
1057 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001058
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001059 return activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001060}
1061
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001062static int
1063force_clear(int enable_activate_before, int enable_activate_after, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001064{
Stefan Berger320df852015-11-30 11:14:19 -05001065 int has_owner;
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001066 int ret = read_has_owner(&has_owner);
1067 if (ret)
1068 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001069 if (!has_owner) {
1070 if (verbose)
1071 printf("TPM does not have an owner.\n");
1072 return 0;
1073 }
1074
1075 if (enable_activate_before) {
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001076 ret = enable_activate(0, verbose);
1077 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001078 dprintf(DEBUG_tcg,
1079 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001080 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001081 }
1082 }
1083
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001084 ret = assert_physical_presence(verbose);
1085 if (ret)
1086 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001087
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001088 ret = build_and_send_cmd(0, TPM_ORD_ForceClear,
1089 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001090 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001091 goto err_exit;
1092
1093 if (!enable_activate_after) {
1094 if (verbose)
1095 printf("Owner successfully cleared.\n"
1096 "You will need to enable/activate the TPM again.\n\n");
1097 return 0;
1098 }
1099
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001100 return enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001101
1102err_exit:
1103 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1104
1105 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001106 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001107}
1108
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001109static int
1110set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001111{
Stefan Berger320df852015-11-30 11:14:19 -05001112 int has_owner;
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001113 int ret = read_has_owner(&has_owner);
1114 if (ret)
1115 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001116 if (has_owner) {
1117 if (verbose)
1118 printf("Must first remove owner.\n");
1119 return 0;
1120 }
1121
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001122 struct tpm_permanent_flags pf;
1123 ret = read_permanent_flags((char *)&pf, sizeof(pf));
1124 if (ret)
1125 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001126
1127 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1128 if (verbose)
1129 printf("TPM must first be enable.\n");
1130 return 0;
1131 }
1132
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001133 ret = assert_physical_presence(verbose);
1134 if (ret)
1135 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001136
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001137 ret = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1138 (allow) ? CommandFlag_TRUE
1139 : CommandFlag_FALSE,
1140 sizeof(CommandFlag_TRUE),
1141 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001142 if (ret)
Stefan Berger320df852015-11-30 11:14:19 -05001143 goto err_exit;
1144
1145 if (verbose)
1146 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1147
1148 return 0;
1149
1150err_exit:
1151 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1152 tpm_set_failure();
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001153 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001154}
1155
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001156static int
1157tpm_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001158{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001159 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001160
1161 switch (msgCode) {
1162 case TPM_PPI_OP_NOOP: /* no-op */
1163 break;
1164
1165 case TPM_PPI_OP_ENABLE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001166 ret = enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001167 break;
1168
1169 case TPM_PPI_OP_DISABLE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001170 ret = enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001171 break;
1172
1173 case TPM_PPI_OP_ACTIVATE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001174 ret = activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001175 break;
1176
1177 case TPM_PPI_OP_DEACTIVATE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001178 ret = activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001179 break;
1180
1181 case TPM_PPI_OP_CLEAR:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001182 ret = force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001183 break;
1184
1185 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001186 ret = set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001187 break;
1188
1189 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001190 ret = set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001191 break;
1192
1193 default:
1194 break;
1195 }
1196
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001197 if (ret)
1198 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001199
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001200 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001201}
1202
1203static int
1204get_tpm_state(void)
1205{
1206 int state = 0;
1207 struct tpm_permanent_flags pf;
1208 int has_owner;
1209
1210 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1211 read_has_owner(&has_owner))
1212 return ~0;
1213
1214 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1215 state |= TPM_STATE_ENABLED;
1216
1217 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1218 state |= TPM_STATE_ACTIVE;
1219
1220 if (has_owner) {
1221 state |= TPM_STATE_OWNED;
1222 } else {
1223 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1224 state |= TPM_STATE_OWNERINSTALL;
1225 }
1226
1227 return state;
1228}
1229
1230static void
1231show_tpm_menu(int state, int next_scancodes[7])
1232{
1233 int i = 0;
1234
1235 printf("\nThe current state of the TPM is:\n");
1236
1237 if (state & TPM_STATE_ENABLED)
1238 printf(" Enabled");
1239 else
1240 printf(" Disabled");
1241
1242 if (state & TPM_STATE_ACTIVE)
1243 printf(" and active\n");
1244 else
1245 printf(" and deactivated\n");
1246
1247 if (state & TPM_STATE_OWNED)
1248 printf(" Ownership has been taken\n");
1249 else {
1250 printf(" Ownership has not been taken\n");
1251 if (state & TPM_STATE_OWNERINSTALL)
1252 printf(" A user can take ownership of the TPM\n");
1253 else
1254 printf(" Taking ownership of the TPM has been disabled\n");
1255 }
1256
1257 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1258 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1259 printf("\nNote: To make use of all functionality, the TPM must be "
1260 "enabled and active.\n");
1261 }
1262
1263 printf("\nAvailable options are:\n");
1264 if (state & TPM_STATE_ENABLED) {
1265 printf(" d. Disable the TPM\n");
1266 next_scancodes[i++] = 32;
1267
1268 if (state & TPM_STATE_ACTIVE) {
1269 printf(" v. Deactivate the TPM\n");
1270 next_scancodes[i++] = 47;
1271
1272 if (state & TPM_STATE_OWNERINSTALL) {
1273 printf(" p. Prevent installation of an owner\n");
1274 next_scancodes[i++] = 25;
1275 } else {
1276 printf(" s. Allow installation of an owner\n");
1277 next_scancodes[i++] = 31;
1278 }
1279 } else {
1280 printf(" a. Activate the TPM\n");
1281 next_scancodes[i++] = 30;
1282 }
1283
1284 } else {
1285 printf(" e. Enable the TPM\n");
1286 next_scancodes[i++] = 18;
1287 }
1288
1289 if (state & TPM_STATE_OWNED) {
1290 printf(" c. Clear ownership\n");
1291 next_scancodes[i++] = 46;
1292 }
1293
1294 next_scancodes[i++] = 0;
1295}
1296
1297void
1298tpm_menu(void)
1299{
1300 if (!CONFIG_TCGBIOS)
1301 return;
1302
1303 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001304 tpm_ppi_code msgCode;
1305 int state = 0, i;
1306 int waitkey;
1307
1308 while (get_keystroke(0) >= 0)
1309 ;
1310 wait_threads();
1311
1312 printf("The Trusted Platform Module (TPM) is a hardware device in "
1313 "this machine.\n"
1314 "It can help verify the integrity of system software.\n\n");
1315
1316 for (;;) {
1317 if ((state = get_tpm_state()) != ~0) {
1318 show_tpm_menu(state, next_scancodes);
1319 } else {
1320 printf("TPM is not working correctly.\n");
1321 return;
1322 }
1323
1324 printf("\nIf no change is desired or if this menu was reached by "
1325 "mistake, press ESC to\n"
1326 "reboot the machine.\n");
1327
1328 msgCode = TPM_PPI_OP_NOOP;
1329
1330 waitkey = 1;
1331
1332 while (waitkey) {
1333 while ((scancode = get_keystroke(1000)) == ~0)
1334 ;
1335
1336 switch (scancode) {
1337 case 1:
1338 // ESC
1339 reset();
1340 break;
1341 case 18: /* e. enable */
1342 msgCode = TPM_PPI_OP_ENABLE;
1343 break;
1344 case 32: /* d. disable */
1345 msgCode = TPM_PPI_OP_DISABLE;
1346 break;
1347 case 30: /* a. activate */
1348 msgCode = TPM_PPI_OP_ACTIVATE;
1349 break;
1350 case 47: /* v. deactivate */
1351 msgCode = TPM_PPI_OP_DEACTIVATE;
1352 break;
1353 case 46: /* c. clear owner */
1354 msgCode = TPM_PPI_OP_CLEAR;
1355 break;
1356 case 25: /* p. prevent ownerinstall */
1357 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1358 break;
1359 case 31: /* s. allow ownerinstall */
1360 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1361 break;
1362 default:
1363 continue;
1364 }
1365
1366 /*
1367 * Using the next_scancodes array, check whether the
1368 * pressed key is currently a valid option.
1369 */
1370 for (i = 0; i < sizeof(next_scancodes); i++) {
1371 if (next_scancodes[i] == 0)
1372 break;
1373
1374 if (next_scancodes[i] == scancode) {
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001375 tpm_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001376 waitkey = 0;
1377 break;
1378 }
1379 }
1380 }
1381 }
1382}