blob: 7b93d87926342f1db5ade63d219e43928fc23562 [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
Stefan Berger0d289b52015-06-09 19:56:29 -040039static const u8 GetCapability_Permanent_Flags[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040040 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
41 0x00, 0x00, 0x01, 0x08
42};
43
Stefan Berger320df852015-11-30 11:14:19 -050044static const u8 GetCapability_STClear_Flags[] = {
45 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
46 0x00, 0x00, 0x01, 0x09
47};
48
Stefan Berger0d289b52015-06-09 19:56:29 -040049static const u8 GetCapability_OwnerAuth[] = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040050 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
51 0x00, 0x00, 0x01, 0x11
52};
53
54static const u8 GetCapability_Timeouts[] = {
55 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
56 0x00, 0x00, 0x01, 0x15
57};
58
59static const u8 GetCapability_Durations[] = {
60 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
61 0x00, 0x00, 0x01, 0x20
62};
63
64
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050065/****************************************************************
66 * TPM state tracking
67 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040068
69typedef struct {
70 u8 tpm_probed:1;
71 u8 tpm_found:1;
72 u8 tpm_working:1;
73 u8 if_shutdown:1;
74 u8 tpm_driver_to_use:4;
Stefan Berger60bb9e92015-11-21 14:54:42 -050075 struct tcpa_descriptor_rev2 *tcpa;
76
77 /* length of the TCPA log buffer */
78 u32 log_area_minimum_length;
79
80 /* start address of TCPA log buffer */
81 u8 * log_area_start_address;
82
83 /* number of log entries written */
84 u32 entry_count;
85
86 /* address to write next log entry to */
87 u8 * log_area_next_entry;
88
89 /* address of last entry written (need for TCG_StatusCheck) */
90 u8 * log_area_last_entry;
Stefan Bergerb310dfa2015-03-23 14:22:16 -040091} tpm_state_t;
92
Stefan Berger60bb9e92015-11-21 14:54:42 -050093tpm_state_t tpm_state VARLOW = {
Stefan Bergerb310dfa2015-03-23 14:22:16 -040094 .tpm_driver_to_use = TPM_INVALID_DRIVER,
95};
96
Stefan Berger320df852015-11-30 11:14:19 -050097typedef u8 tpm_ppi_code;
98
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050099static u32
100is_preboot_if_shutdown(void)
101{
102 return tpm_state.if_shutdown;
103}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400104
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400105
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500106/****************************************************************
107 * TPM hardware interface
108 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400109
110static u32
111is_tpm_present(void)
112{
113 u32 rc = 0;
114 unsigned int i;
115
116 for (i = 0; i < TPM_NUM_DRIVERS; i++) {
117 struct tpm_driver *td = &tpm_drivers[i];
118 if (td->probe() != 0) {
119 td->init();
120 tpm_state.tpm_driver_to_use = i;
121 rc = 1;
122 break;
123 }
124 }
125
126 return rc;
127}
128
129static void
130probe_tpm(void)
131{
132 if (!tpm_state.tpm_probed) {
133 tpm_state.tpm_probed = 1;
134 tpm_state.tpm_found = (is_tpm_present() != 0);
135 tpm_state.tpm_working = tpm_state.tpm_found;
136 }
137}
138
139static int
140has_working_tpm(void)
141{
142 probe_tpm();
143
144 return tpm_state.tpm_working;
145}
146
Stefan Berger320df852015-11-30 11:14:19 -0500147int
148tpm_is_working(void)
149{
150 if (!CONFIG_TCGBIOS)
151 return 0;
152
153 return tpm_state.tpm_working;
154}
155
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400156static u32
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500157transmit(u8 locty, struct tpm_req_header *req,
158 void *respbuffer, u32 *respbufferlen,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400159 enum tpmDurationType to_t)
160{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400161 if (tpm_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
162 return TCG_FATAL_COM_ERROR;
163
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500164 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400165
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500166 u32 irc = td->activate(locty);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400167 if (irc != 0) {
168 /* tpm could not be activated */
169 return TCG_FATAL_COM_ERROR;
170 }
171
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500172 irc = td->senddata((void*)req, be32_to_cpu(req->totlen));
173 if (irc != 0)
174 return TCG_FATAL_COM_ERROR;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400175
176 irc = td->waitdatavalid();
177 if (irc != 0)
178 return TCG_FATAL_COM_ERROR;
179
180 irc = td->waitrespready(to_t);
181 if (irc != 0)
182 return TCG_FATAL_COM_ERROR;
183
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500184 irc = td->readresp(respbuffer, respbufferlen);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400185 if (irc != 0)
186 return TCG_FATAL_COM_ERROR;
187
188 td->ready();
189
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500190 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400191}
192
193
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500194/****************************************************************
195 * ACPI TCPA table interface
196 ****************************************************************/
197
198static struct tcpa_descriptor_rev2 *
199find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
200{
201 u32 ctr = 0;
202 struct tcpa_descriptor_rev2 *tcpa = NULL;
203 struct rsdt_descriptor *rsdt;
204 u32 length;
205 u16 off;
206
207 rsdt = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
208 if (!rsdt)
209 return NULL;
210
211 length = rsdt->length;
212 off = offsetof(struct rsdt_descriptor, entry);
213
214 while ((off + sizeof(rsdt->entry[0])) <= length) {
215 /* try all pointers to structures */
216 tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
217
218 /* valid TCPA ACPI table ? */
219 if (tcpa->signature == TCPA_SIGNATURE &&
220 checksum((u8 *)tcpa, tcpa->length) == 0)
221 break;
222
223 tcpa = NULL;
224 off += sizeof(rsdt->entry[0]);
225 ctr++;
226 }
227
228 /* cache it */
229 if (tcpa)
230 tpm_state.tcpa = tcpa;
231
232 return tcpa;
233}
234
235static struct tcpa_descriptor_rev2 *
236find_tcpa_table(void)
237{
238 struct tcpa_descriptor_rev2 *tcpa = NULL;
239 struct rsdp_descriptor *rsdp = RsdpAddr;
240
241 if (tpm_state.tcpa)
242 return tpm_state.tcpa;
243
244 if (rsdp)
245 tcpa = find_tcpa_by_rsdp(rsdp);
246 else
247 tpm_state.if_shutdown = 1;
248
249 if (!rsdp)
250 dprintf(DEBUG_tcg,
251 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
252 else if (!tcpa)
253 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
254
255 return tcpa;
256}
257
258static u8 *
259get_lasa_base_ptr(u32 *log_area_minimum_length)
260{
261 u8 *log_area_start_address = 0;
262 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
263
264 if (tcpa) {
265 log_area_start_address = (u8 *)(long)tcpa->log_area_start_address;
266 if (log_area_minimum_length)
267 *log_area_minimum_length = tcpa->log_area_minimum_length;
268 }
269
270 return log_area_start_address;
271}
272
273/* clear the ACPI log */
274static void
275reset_acpi_log(void)
276{
277 tpm_state.log_area_start_address =
278 get_lasa_base_ptr(&tpm_state.log_area_minimum_length);
279
280 if (tpm_state.log_area_start_address)
281 memset(tpm_state.log_area_start_address, 0,
282 tpm_state.log_area_minimum_length);
283
284 tpm_state.log_area_next_entry = tpm_state.log_area_start_address;
285 tpm_state.log_area_last_entry = NULL;
286 tpm_state.entry_count = 0;
287}
288
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500289/*
290 * Extend the ACPI log with the given entry by copying the
291 * entry data into the log.
292 * Input
293 * pcpes : Pointer to the event 'header' to be copied into the log
294 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500295 *
296 * Output:
297 * Returns an error code in case of faiure, 0 in case of success
298 */
299static u32
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500300tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500301{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500302 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
303 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
304
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500305 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500306 return TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500307
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500308 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500309
310 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
311 tpm_state.log_area_minimum_length) {
312 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500313 return TCG_PC_LOGOVERFLOW;
314 }
315
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500316 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
317 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500318 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500319
320 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
321 tpm_state.log_area_next_entry += size;
322 tpm_state.entry_count++;
323
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500324 return 0;
325}
326
327
328/****************************************************************
329 * Helper functions
330 ****************************************************************/
331
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400332/*
333 * Send a TPM command with the given ordinal. Append the given buffer
334 * containing all data in network byte order to the command (this is
335 * the custom part per command) and expect a response of the given size.
336 * If a buffer is provided, the response will be copied into it.
337 */
338static u32
Stefan Berger47b9df52015-11-21 14:54:40 -0500339build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append, u32 append_size,
340 u8 *resbuffer, u32 return_size, u32 *returnCode,
341 enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400342{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500343 struct {
344 struct tpm_req_header trqh;
345 u8 cmd[20];
346 } PACKED req = {
347 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500348 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500349 .trqh.ordinal = cpu_to_be32(ordinal),
350 };
Stefan Bergerece25612015-11-12 10:14:46 -0500351 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400352 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400353 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400354 memset(obuffer, 0x0, sizeof(obuffer));
355
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500356 if (return_size > sizeof(obuffer) || append_size > sizeof(req.cmd)) {
357 warn_internalerror();
358 return TCG_FIRMWARE_ERROR;
359 }
360 if (append_size)
361 memcpy(req.cmd, append, append_size);
362
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500363 u32 rc = transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400364 if (rc)
365 return rc;
366
367 *returnCode = be32_to_cpu(trsh->errcode);
368
369 if (resbuffer)
370 memcpy(resbuffer, trsh, return_size);
371
372 return 0;
373}
374
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500375static void
376tpm_set_failure(void)
377{
378 u32 returnCode;
379
380 /* we will try to deactivate the TPM now - ignoring all errors */
381 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
382 PhysicalPresence_CMD_ENABLE,
383 sizeof(PhysicalPresence_CMD_ENABLE),
384 NULL, 0, &returnCode,
385 TPM_DURATION_TYPE_SHORT);
386
387 build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
388 PhysicalPresence_PRESENT,
389 sizeof(PhysicalPresence_PRESENT),
390 NULL, 0, &returnCode,
391 TPM_DURATION_TYPE_SHORT);
392
393 build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
394 NULL, 0, NULL, 0, &returnCode,
395 TPM_DURATION_TYPE_SHORT);
396
397 tpm_state.tpm_working = 0;
398}
399
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400400static u32
401determine_timeouts(void)
402{
403 u32 rc;
404 u32 returnCode;
405 struct tpm_res_getcap_timeouts timeouts;
406 struct tpm_res_getcap_durations durations;
407 struct tpm_driver *td = &tpm_drivers[tpm_state.tpm_driver_to_use];
408 u32 i;
409
Stefan Berger5aa2a752015-03-23 14:22:17 -0400410 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400411 GetCapability_Timeouts,
412 sizeof(GetCapability_Timeouts),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400413 (u8 *)&timeouts, sizeof(timeouts),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400414 &returnCode, TPM_DURATION_TYPE_SHORT);
415
416 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)"
417 " = 0x%08x\n", returnCode);
418
419 if (rc || returnCode)
420 goto err_exit;
421
Stefan Berger5aa2a752015-03-23 14:22:17 -0400422 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400423 GetCapability_Durations,
424 sizeof(GetCapability_Durations),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400425 (u8 *)&durations, sizeof(durations),
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400426 &returnCode, TPM_DURATION_TYPE_SHORT);
427
428 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)"
429 " = 0x%08x\n", returnCode);
430
431 if (rc || returnCode)
432 goto err_exit;
433
434 for (i = 0; i < 3; i++)
435 durations.durations[i] = be32_to_cpu(durations.durations[i]);
436
437 for (i = 0; i < 4; i++)
438 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
439
440 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
441 timeouts.timeouts[0],
442 timeouts.timeouts[1],
443 timeouts.timeouts[2],
444 timeouts.timeouts[3]);
445
446 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
447 durations.durations[0],
448 durations.durations[1],
449 durations.durations[2]);
450
451
452 td->set_timeouts(timeouts.timeouts, durations.durations);
453
454 return 0;
455
456err_exit:
457 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
458
Stefan Berger7fce1d92015-11-12 10:14:45 -0500459 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400460 if (rc)
461 return rc;
462 return TCG_TCG_COMMAND_ERROR;
463}
464
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500465static u32
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500466tpm_log_extend_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500467{
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500468 if (!has_working_tpm())
469 return TCG_GENERAL_ERROR;
470
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500471 if (pcpes->pcrindex >= 24)
472 return TCG_INVALID_INPUT_PARA;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500473
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500474 struct tpm_req_extend tre = {
475 .tag = cpu_to_be16(TPM_TAG_RQU_CMD),
476 .totlen = cpu_to_be32(sizeof(tre)),
477 .ordinal = cpu_to_be32(TPM_ORD_Extend),
478 .pcrindex = cpu_to_be32(pcpes->pcrindex),
479 };
480 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
481
482 struct tpm_rsp_extend rsp;
483 u32 resp_length = sizeof(rsp);
484 u32 rc = transmit(0, (void*)&tre, &rsp, &resp_length,
485 TPM_DURATION_TYPE_SHORT);
486 if (rc || resp_length != sizeof(rsp)) {
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500487 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500488 return rc;
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500489 }
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500490
491 rc = tpm_log_event(pcpes, event);
492 if (rc)
493 tpm_set_failure();
494 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500495}
496
Kevin O'Connor92244402015-11-22 16:54:18 -0500497static void
498tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
499{
500 if (hashdata)
501 sha1(hashdata, hashdata_length, pcpes->digest);
502}
503
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500504/*
505 * Add a measurement to the log; the data at data_seg:data/length are
506 * appended to the TCG_PCClientPCREventStruct
507 *
508 * Input parameters:
509 * pcrindex : which PCR to extend
510 * event_type : type of event; specs section on 'Event Types'
511 * event : pointer to info (e.g., string) to be added to log as-is
512 * event_length: length of the event
513 * hashdata : pointer to the data to be hashed
514 * hashdata_length: length of the data to be hashed
515 */
516static u32
517tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
518 const char *event, u32 event_length,
519 const u8 *hashdata, u32 hashdata_length)
520{
521 struct pcpes pcpes = {
522 .pcrindex = pcrindex,
523 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500524 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500525 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500526 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500527 return tpm_log_extend_event(&pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500528}
529
530
531/****************************************************************
532 * Setup and Measurements
533 ****************************************************************/
534
Kevin O'Connora6175422015-11-22 11:28:14 -0500535// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500536static u32
Kevin O'Connora6175422015-11-22 11:28:14 -0500537tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500538{
Kevin O'Connora6175422015-11-22 11:28:14 -0500539 u32 len = strlen(string);
540 return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
541 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500542}
543
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500544/*
545 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
546 */
547static u32
548tpm_add_event_separators(void)
549{
550 u32 rc;
551 u32 pcrIndex = 0;
552
553 if (!CONFIG_TCGBIOS)
554 return 0;
555
556 if (!has_working_tpm())
557 return TCG_GENERAL_ERROR;
558
Kevin O'Connora6175422015-11-22 11:28:14 -0500559 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500560 while (pcrIndex <= 7) {
Kevin O'Connora6175422015-11-22 11:28:14 -0500561 rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
562 NULL, 0,
563 (u8 *)evt_separator,
564 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500565 if (rc)
566 break;
567 pcrIndex ++;
568 }
569
570 return rc;
571}
572
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500573static u32
574tpm_smbios_measure(void)
575{
576 if (!CONFIG_TCGBIOS)
577 return 0;
578
579 if (!has_working_tpm())
580 return TCG_GENERAL_ERROR;
581
582 u32 rc;
583 struct pcctes pcctes = {
584 .eventid = 1,
585 .eventdatasize = SHA1_BUFSIZE,
586 };
587 struct smbios_entry_point *sep = SMBiosAddr;
588
589 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
590
591 if (!sep)
592 return 0;
593
594 rc = sha1((const u8 *)sep->structure_table_address,
595 sep->structure_table_length, pcctes.digest);
596 if (rc)
597 return rc;
598
599 return tpm_add_measurement_to_log(1,
600 EV_EVENT_TAG,
601 (const char *)&pcctes, sizeof(pcctes),
602 (u8 *)&pcctes, sizeof(pcctes));
603}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400604
605static u32
606tpm_startup(void)
607{
608 u32 rc;
609 u32 returnCode;
610
611 if (!has_working_tpm())
612 return TCG_GENERAL_ERROR;
613
614 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400615 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400616 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400617 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400618
619 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
620 returnCode);
621
622 if (CONFIG_COREBOOT) {
623 /* with other firmware on the system the TPM may already have been
624 * initialized
625 */
626 if (returnCode == TPM_INVALID_POSTINIT)
627 returnCode = 0;
628 }
629
630 if (rc || returnCode)
631 goto err_exit;
632
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500633 rc = determine_timeouts();
634 if (rc)
635 goto err_exit;
636
Stefan Berger5aa2a752015-03-23 14:22:17 -0400637 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400638 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400639
640 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
641 returnCode);
642
643 if (rc || returnCode)
644 goto err_exit;
645
Stefan Berger5aa2a752015-03-23 14:22:17 -0400646 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400647 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400648
649 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
650 returnCode);
651
652 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
653 goto err_exit;
654
Stefan Berger2aff1c12015-05-26 15:48:33 -0400655 rc = tpm_smbios_measure();
656 if (rc)
657 goto err_exit;
658
Kevin O'Connor12575332015-11-22 11:34:38 -0500659 rc = tpm_add_action(2, "Start Option ROM Scan");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400660 if (rc)
661 goto err_exit;
662
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400663 return 0;
664
665err_exit:
666 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
667
Stefan Berger7fce1d92015-11-12 10:14:45 -0500668 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400669 if (rc)
670 return rc;
671 return TCG_TCG_COMMAND_ERROR;
672}
673
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500674/*
675 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
676 where the TCPA table is.
677 */
678static void
679tpm_acpi_init(void)
680{
681 tpm_state.if_shutdown = 0;
682 tpm_state.tpm_probed = 0;
683 tpm_state.tpm_found = 0;
684 tpm_state.tpm_working = 0;
685
686 if (!has_working_tpm()) {
687 tpm_state.if_shutdown = 1;
688 return;
689 }
690
691 reset_acpi_log();
692}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400693
Kevin O'Connord6aca442015-06-10 11:00:17 -0400694void
695tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400696{
697 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400698 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400699
700 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400701 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400702 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400703
Kevin O'Connord6aca442015-06-10 11:00:17 -0400704 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400705}
706
Kevin O'Connord6aca442015-06-10 11:00:17 -0400707void
708tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400709{
710 u32 rc;
711 u32 returnCode;
712
713 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400714 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400715
716 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400717 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400718
Stefan Berger5aa2a752015-03-23 14:22:17 -0400719 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400720 PhysicalPresence_CMD_ENABLE,
721 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400722 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400723 if (rc || returnCode)
724 goto err_exit;
725
Stefan Berger5aa2a752015-03-23 14:22:17 -0400726 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400727 PhysicalPresence_NOT_PRESENT_LOCK,
728 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400729 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400730 if (rc || returnCode)
731 goto err_exit;
732
Kevin O'Connor12575332015-11-22 11:34:38 -0500733 rc = tpm_add_action(4, "Calling INT 19h");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400734 if (rc)
735 goto err_exit;
736
737 rc = tpm_add_event_separators();
738 if (rc)
739 goto err_exit;
740
Kevin O'Connord6aca442015-06-10 11:00:17 -0400741 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400742
743err_exit:
744 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
745
Stefan Berger7fce1d92015-11-12 10:14:45 -0500746 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400747}
748
Stefan Berger5aa2a752015-03-23 14:22:17 -0400749/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500750 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400751 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500752u32
753tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400754{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500755 if (!CONFIG_TCGBIOS)
756 return 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400757
Stefan Berger7fce1d92015-11-12 10:14:45 -0500758 if (!has_working_tpm())
759 return TCG_GENERAL_ERROR;
760
Stefan Berger5aa2a752015-03-23 14:22:17 -0400761 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500762 struct pcctes_romex pcctes = {
763 .eventid = 7,
764 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400765 };
766
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500767 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500768 if (rc)
769 return rc;
770
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500771 return tpm_add_measurement_to_log(2,
772 EV_EVENT_TAG,
773 (const char *)&pcctes, sizeof(pcctes),
774 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500775}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400776
Stefan Berger2aff1c12015-05-26 15:48:33 -0400777u32
778tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
779{
780 if (!CONFIG_TCGBIOS)
781 return 0;
782
783 if (!has_working_tpm())
784 return TCG_GENERAL_ERROR;
785
Stefan Berger4cdbc412015-11-30 11:14:18 -0500786 if (length < 0x200)
787 return TCG_INVALID_INPUT_PARA;
788
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500789 const char *string = "Booting BCV device 00h (Floppy)";
790 if (bootdrv == 0x80)
791 string = "Booting BCV device 80h (HDD)";
792 u32 rc = tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400793 if (rc)
794 return rc;
795
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500796 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
797 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500798 string = "MBR";
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500799 rc = tpm_add_measurement_to_log(4, EV_IPL,
800 string, strlen(string),
801 addr, 0x1b8);
802 if (rc)
803 return rc;
804
805 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
806 string = "MBR PARTITION_TABLE";
807 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
808 string, strlen(string),
809 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400810}
811
812u32
813tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
814{
815 if (!CONFIG_TCGBIOS)
816 return 0;
817
818 if (!has_working_tpm())
819 return TCG_GENERAL_ERROR;
820
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500821 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400822 if (rc)
823 return rc;
824
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500825 /* specs: see section 'El Torito' */
826 const char *string = "EL TORITO IPL";
827 return tpm_add_measurement_to_log(4, EV_IPL,
828 string, strlen(string),
829 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400830}
831
832u32
833tpm_add_cdrom_catalog(const u8 *addr, u32 length)
834{
835 if (!CONFIG_TCGBIOS)
836 return 0;
837
838 if (!has_working_tpm())
839 return TCG_GENERAL_ERROR;
840
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500841 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400842 if (rc)
843 return rc;
844
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500845 /* specs: see section 'El Torito' */
846 const char *string = "BOOT CATALOG";
847 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
848 string, strlen(string),
849 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400850}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400851
Kevin O'Connord6aca442015-06-10 11:00:17 -0400852void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400853tpm_s3_resume(void)
854{
855 u32 rc;
856 u32 returnCode;
857
858 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400859 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400860
861 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400862 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400863
864 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
865
Stefan Berger5aa2a752015-03-23 14:22:17 -0400866 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400867 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400868 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400869
870 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
871 returnCode);
872
873 if (rc || returnCode)
874 goto err_exit;
875
Kevin O'Connord6aca442015-06-10 11:00:17 -0400876 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400877
878err_exit:
879 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
880
Stefan Berger7fce1d92015-11-12 10:14:45 -0500881 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400882}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500883
884
885/****************************************************************
886 * BIOS interface
887 ****************************************************************/
888
889static inline void *input_buf32(struct bregs *regs)
890{
891 return MAKE_FLATPTR(regs->es, regs->di);
892}
893
894static inline void *output_buf32(struct bregs *regs)
895{
896 return MAKE_FLATPTR(regs->ds, regs->si);
897}
898
899static u32
900hash_log_extend_event_int(const struct hleei_short *hleei_s,
901 struct hleeo *hleeo)
902{
903 u32 rc = 0;
904 struct hleo hleo;
905 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
906 const void *logdataptr;
907 u32 logdatalen;
908 struct pcpes *pcpes;
909 u32 pcrindex;
910
911 if (is_preboot_if_shutdown() != 0) {
912 rc = TCG_INTERFACE_SHUTDOWN;
913 goto err_exit;
914 }
915
916 /* short or long version? */
917 switch (hleei_s->ipblength) {
918 case sizeof(struct hleei_short):
919 /* short */
920 logdataptr = hleei_s->logdataptr;
921 logdatalen = hleei_s->logdatalen;
922 pcrindex = hleei_s->pcrindex;
923 break;
924
925 case sizeof(struct hleei_long):
926 /* long */
927 logdataptr = hleei_l->logdataptr;
928 logdatalen = hleei_l->logdatalen;
929 pcrindex = hleei_l->pcrindex;
930 break;
931
932 default:
933 /* bad input block */
934 rc = TCG_INVALID_INPUT_PARA;
935 goto err_exit;
936 }
937
938 pcpes = (struct pcpes *)logdataptr;
939
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500940 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
941 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500942 rc = TCG_INVALID_INPUT_PARA;
943 goto err_exit;
944 }
945
Kevin O'Connor92244402015-11-22 16:54:18 -0500946 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500947 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500948 if (rc)
949 goto err_exit;
950
951 hleeo->opblength = sizeof(struct hleeo);
952 hleeo->reserved = 0;
953 hleeo->eventnumber = hleo.eventnumber;
954
955err_exit:
956 if (rc != 0) {
957 hleeo->opblength = 4;
958 hleeo->reserved = 0;
959 }
960
961 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500962}
963
964static u32
965pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
966{
967 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500968
969 if (is_preboot_if_shutdown()) {
970 rc = TCG_INTERFACE_SHUTDOWN;
971 goto err_exit;
972 }
973
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500974 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500975
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500976 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
977 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
978 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500979 rc = TCG_INVALID_INPUT_PARA;
980 goto err_exit;
981 }
982
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500983 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
984 rc = transmit(0, trh, pttto->tpmopout, &resbuflen,
985 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500986 if (rc)
987 goto err_exit;
988
989 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
990 pttto->reserved = 0;
991
992err_exit:
993 if (rc != 0) {
994 pttto->opblength = 4;
995 pttto->reserved = 0;
996 }
997
998 return rc;
999}
1000
1001static u32
1002shutdown_preboot_interface(void)
1003{
1004 u32 rc = 0;
1005
1006 if (!is_preboot_if_shutdown()) {
1007 tpm_state.if_shutdown = 1;
1008 } else {
1009 rc = TCG_INTERFACE_SHUTDOWN;
1010 }
1011
1012 return rc;
1013}
1014
1015static u32
1016hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1017{
1018 u32 rc = 0;
1019 u16 size;
1020 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001021
1022 if (is_preboot_if_shutdown() != 0) {
1023 rc = TCG_INTERFACE_SHUTDOWN;
1024 goto err_exit;
1025 }
1026
1027 size = hlei->ipblength;
1028 if (size != sizeof(*hlei)) {
1029 rc = TCG_INVALID_INPUT_PARA;
1030 goto err_exit;
1031 }
1032
1033 pcpes = (struct pcpes *)hlei->logdataptr;
1034
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001035 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
1036 || pcpes->eventtype != hlei->logeventtype
1037 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001038 rc = TCG_INVALID_INPUT_PARA;
1039 goto err_exit;
1040 }
1041
Kevin O'Connor92244402015-11-22 16:54:18 -05001042 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001043 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001044 if (rc)
1045 goto err_exit;
1046
1047 /* updating the log was fine */
1048 hleo->opblength = sizeof(struct hleo);
1049 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001050 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001051
1052err_exit:
1053 if (rc != 0) {
1054 hleo->opblength = 2;
1055 hleo->reserved = 0;
1056 }
1057
1058 return rc;
1059}
1060
1061static u32
1062hash_all_int(const struct hai *hai, u8 *hash)
1063{
1064 if (is_preboot_if_shutdown() != 0)
1065 return TCG_INTERFACE_SHUTDOWN;
1066
1067 if (hai->ipblength != sizeof(struct hai) ||
1068 hai->hashdataptr == 0 ||
1069 hai->hashdatalen == 0 ||
1070 hai->algorithmid != TPM_ALG_SHA)
1071 return TCG_INVALID_INPUT_PARA;
1072
1073 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1074}
1075
1076static u32
1077tss_int(struct ti *ti, struct to *to)
1078{
1079 u32 rc = 0;
1080
1081 if (is_preboot_if_shutdown() == 0) {
1082 rc = TCG_PC_UNSUPPORTED;
1083 } else {
1084 rc = TCG_INTERFACE_SHUTDOWN;
1085 }
1086
1087 to->opblength = sizeof(struct to);
1088 to->reserved = 0;
1089
1090 return rc;
1091}
1092
1093static u32
1094compact_hash_log_extend_event_int(u8 *buffer,
1095 u32 info,
1096 u32 length,
1097 u32 pcrindex,
1098 u32 *edx_ptr)
1099{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001100 struct pcpes pcpes = {
1101 .pcrindex = pcrindex,
1102 .eventtype = EV_COMPACT_HASH,
1103 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001104 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001105
1106 if (is_preboot_if_shutdown() != 0)
1107 return TCG_INTERFACE_SHUTDOWN;
1108
Kevin O'Connor92244402015-11-22 16:54:18 -05001109 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001110 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001111 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001112 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001113
1114 return rc;
1115}
1116
1117void VISIBLE32FLAT
1118tpm_interrupt_handler32(struct bregs *regs)
1119{
1120 if (!CONFIG_TCGBIOS)
1121 return;
1122
1123 set_cf(regs, 0);
1124
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001125 switch ((enum irq_ids)regs->al) {
1126 case TCG_StatusCheck:
1127 if (is_tpm_present() == 0) {
1128 /* no TPM available */
1129 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1130 } else {
1131 regs->eax = 0;
1132 regs->ebx = TCG_MAGIC;
1133 regs->ch = TCG_VERSION_MAJOR;
1134 regs->cl = TCG_VERSION_MINOR;
1135 regs->edx = 0x0;
1136 regs->esi = (u32)tpm_state.log_area_start_address;
1137 regs->edi = (u32)tpm_state.log_area_last_entry;
1138 }
1139 break;
1140
1141 case TCG_HashLogExtendEvent:
1142 regs->eax =
1143 hash_log_extend_event_int(
1144 (struct hleei_short *)input_buf32(regs),
1145 (struct hleeo *)output_buf32(regs));
1146 break;
1147
1148 case TCG_PassThroughToTPM:
1149 regs->eax =
1150 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1151 (struct pttto *)output_buf32(regs));
1152 break;
1153
1154 case TCG_ShutdownPreBootInterface:
1155 regs->eax = shutdown_preboot_interface();
1156 break;
1157
1158 case TCG_HashLogEvent:
1159 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1160 (struct hleo*)output_buf32(regs));
1161 break;
1162
1163 case TCG_HashAll:
1164 regs->eax =
1165 hash_all_int((struct hai*)input_buf32(regs),
1166 (u8 *)output_buf32(regs));
1167 break;
1168
1169 case TCG_TSS:
1170 regs->eax = tss_int((struct ti*)input_buf32(regs),
1171 (struct to*)output_buf32(regs));
1172 break;
1173
1174 case TCG_CompactHashLogExtendEvent:
1175 regs->eax =
1176 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1177 regs->esi,
1178 regs->ecx,
1179 regs->edx,
1180 &regs->edx);
1181 break;
1182
1183 default:
1184 set_cf(regs, 1);
1185 }
1186
1187 return;
1188}
Stefan Berger320df852015-11-30 11:14:19 -05001189
1190static u32
1191read_stclear_flags(char *buf, int buf_len)
1192{
1193 u32 rc;
1194 u32 returnCode;
1195 struct tpm_res_getcap_stclear_flags stcf;
1196
1197 memset(buf, 0, buf_len);
1198
1199 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1200 GetCapability_STClear_Flags,
1201 sizeof(GetCapability_STClear_Flags),
1202 (u8 *)&stcf, sizeof(stcf),
1203 &returnCode, TPM_DURATION_TYPE_SHORT);
1204
1205 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1206 "= 0x%08x\n", returnCode);
1207
1208 if (rc || returnCode)
1209 goto err_exit;
1210
1211 memcpy(buf, &stcf.stclear_flags, buf_len);
1212
1213 return 0;
1214
1215err_exit:
1216 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1217
1218 tpm_set_failure();
1219 if (rc)
1220 return rc;
1221 return TCG_TCG_COMMAND_ERROR;
1222}
1223
1224static u32
1225assert_physical_presence(int verbose)
1226{
1227 u32 rc = 0;
1228 u32 returnCode;
1229 struct tpm_stclear_flags stcf;
1230
1231 rc = read_stclear_flags((char *)&stcf, sizeof(stcf));
1232 if (rc) {
1233 dprintf(DEBUG_tcg,
1234 "Error reading STClear flags: 0x%08x\n", rc);
1235 return rc;
1236 }
1237
1238 if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
1239 /* physical presence already asserted */
1240 return 0;
1241
1242 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
1243 PhysicalPresence_CMD_ENABLE,
1244 sizeof(PhysicalPresence_CMD_ENABLE),
1245 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
1246
1247 dprintf(DEBUG_tcg,
1248 "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n",
1249 returnCode);
1250
1251 if (rc || returnCode) {
1252 if (verbose)
1253 printf("Error: Could not enable physical presence.\n\n");
1254 goto err_exit;
1255 }
1256
1257 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
1258 PhysicalPresence_PRESENT,
1259 sizeof(PhysicalPresence_PRESENT),
1260 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
1261
1262 dprintf(DEBUG_tcg,
1263 "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n",
1264 returnCode);
1265
1266 if (rc || returnCode) {
1267 if (verbose)
1268 printf("Error: Could not set presence flag.\n\n");
1269 goto err_exit;
1270 }
1271
1272 return 0;
1273
1274err_exit:
1275 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1276
1277 tpm_set_failure();
1278 if (rc)
1279 return rc;
1280 return TCG_TCG_COMMAND_ERROR;
1281}
1282
1283static u32
1284read_permanent_flags(char *buf, int buf_len)
1285{
1286 u32 rc;
1287 u32 returnCode;
1288 struct tpm_res_getcap_perm_flags pf;
1289
1290 memset(buf, 0, buf_len);
1291
1292 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1293 GetCapability_Permanent_Flags,
1294 sizeof(GetCapability_Permanent_Flags),
1295 (u8 *)&pf, sizeof(pf),
1296 &returnCode, TPM_DURATION_TYPE_SHORT);
1297
1298 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1299 "= 0x%08x\n", returnCode);
1300
1301 if (rc || returnCode)
1302 goto err_exit;
1303
1304 memcpy(buf, &pf.perm_flags, buf_len);
1305
1306 return 0;
1307
1308err_exit:
1309 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1310
1311 tpm_set_failure();
1312 if (rc)
1313 return rc;
1314 return TCG_TCG_COMMAND_ERROR;
1315}
1316
1317static u32
1318read_has_owner(int *has_owner)
1319{
1320 u32 rc;
1321 u32 returnCode;
1322 struct tpm_res_getcap_ownerauth oauth;
1323
1324 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1325 GetCapability_OwnerAuth,
1326 sizeof(GetCapability_OwnerAuth),
1327 (u8 *)&oauth, sizeof(oauth),
1328 &returnCode, TPM_DURATION_TYPE_SHORT);
1329
1330 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1331 "= 0x%08x\n", returnCode);
1332
1333 if (rc || returnCode)
1334 goto err_exit;
1335
1336 *has_owner = oauth.flag;
1337
1338 return 0;
1339
1340err_exit:
1341 dprintf(DEBUG_tcg,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1342
1343 tpm_set_failure();
1344 if (rc)
1345 return rc;
1346 return TCG_TCG_COMMAND_ERROR;
1347}
1348
1349static u32
1350enable_tpm(int enable, u32 *returnCode, int verbose)
1351{
1352 u32 rc;
1353 struct tpm_permanent_flags pf;
1354
1355 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1356 if (rc)
1357 return rc;
1358
1359 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1360 return 0;
1361
1362 rc = assert_physical_presence(verbose);
1363 if (rc) {
1364 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1365 return rc;
1366 }
1367
1368 rc = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1369 : TPM_ORD_PhysicalDisable,
1370 NULL, 0, NULL, 0, returnCode,
1371 TPM_DURATION_TYPE_SHORT);
1372 if (enable)
1373 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n",
1374 *returnCode);
1375 else
1376 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n",
1377 *returnCode);
1378
1379 if (rc || *returnCode)
1380 goto err_exit;
1381
1382 return 0;
1383
1384err_exit:
1385 if (enable)
1386 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1387 else
1388 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1389
1390 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1391
1392 tpm_set_failure();
1393 if (rc)
1394 return rc;
1395 return TCG_TCG_COMMAND_ERROR;
1396}
1397
1398static u32
1399activate_tpm(int activate, int allow_reset, u32 *returnCode, int verbose)
1400{
1401 u32 rc;
1402 struct tpm_permanent_flags pf;
1403
1404 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1405 if (rc)
1406 return rc;
1407
1408 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1409 return 0;
1410
1411 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1412 return 0;
1413
1414 rc = assert_physical_presence(verbose);
1415 if (rc) {
1416 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1417 return rc;
1418 }
1419
1420 rc = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1421 activate ? CommandFlag_FALSE
1422 : CommandFlag_TRUE,
1423 activate ? sizeof(CommandFlag_FALSE)
1424 : sizeof(CommandFlag_TRUE),
1425 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
1426
1427 dprintf(DEBUG_tcg,
1428 "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
1429 activate ? 0 : 1, *returnCode);
1430
1431 if (rc || *returnCode)
1432 goto err_exit;
1433
1434 if (activate && allow_reset) {
1435 if (verbose) {
1436 printf("Requiring a reboot to activate the TPM.\n");
1437
1438 msleep(2000);
1439 }
1440 reset();
1441 }
1442
1443 return 0;
1444
1445err_exit:
1446 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1447
1448 tpm_set_failure();
1449 if (rc)
1450 return rc;
1451 return TCG_TCG_COMMAND_ERROR;
1452}
1453
1454static u32
1455enable_activate(int allow_reset, u32 *returnCode, int verbose)
1456{
1457 u32 rc;
1458
1459 rc = enable_tpm(1, returnCode, verbose);
1460 if (rc)
1461 return rc;
1462
1463 rc = activate_tpm(1, allow_reset, returnCode, verbose);
1464
1465 return rc;
1466}
1467
1468static u32
1469force_clear(int enable_activate_before, int enable_activate_after,
1470 u32 *returnCode, int verbose)
1471{
1472 u32 rc;
1473 int has_owner;
1474
1475 rc = read_has_owner(&has_owner);
1476 if (rc)
1477 return rc;
1478 if (!has_owner) {
1479 if (verbose)
1480 printf("TPM does not have an owner.\n");
1481 return 0;
1482 }
1483
1484 if (enable_activate_before) {
1485 rc = enable_activate(0, returnCode, verbose);
1486 if (rc) {
1487 dprintf(DEBUG_tcg,
1488 "TCGBIOS: Enabling/activating the TPM failed.\n");
1489 return rc;
1490 }
1491 }
1492
1493 rc = assert_physical_presence(verbose);
1494 if (rc) {
1495 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1496 return rc;
1497 }
1498
1499 rc = build_and_send_cmd(0, TPM_ORD_ForceClear,
1500 NULL, 0, NULL, 0, returnCode,
1501 TPM_DURATION_TYPE_SHORT);
1502
1503 dprintf(DEBUG_tcg, "Return code from TPM_ForceClear() = 0x%08x\n",
1504 *returnCode);
1505
1506 if (rc || *returnCode)
1507 goto err_exit;
1508
1509 if (!enable_activate_after) {
1510 if (verbose)
1511 printf("Owner successfully cleared.\n"
1512 "You will need to enable/activate the TPM again.\n\n");
1513 return 0;
1514 }
1515
1516 enable_activate(1, returnCode, verbose);
1517
1518 return 0;
1519
1520err_exit:
1521 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1522
1523 tpm_set_failure();
1524 if (rc)
1525 return rc;
1526 return TCG_TCG_COMMAND_ERROR;
1527}
1528
1529static u32
1530set_owner_install(int allow, u32 *returnCode, int verbose)
1531{
1532 u32 rc;
1533 int has_owner;
1534 struct tpm_permanent_flags pf;
1535
1536 rc = read_has_owner(&has_owner);
1537 if (rc)
1538 return rc;
1539 if (has_owner) {
1540 if (verbose)
1541 printf("Must first remove owner.\n");
1542 return 0;
1543 }
1544
1545 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1546 if (rc)
1547 return rc;
1548
1549 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1550 if (verbose)
1551 printf("TPM must first be enable.\n");
1552 return 0;
1553 }
1554
1555 rc = assert_physical_presence(verbose);
1556 if (rc) {
1557 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1558 return rc;
1559 }
1560
1561 rc = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1562 (allow) ? CommandFlag_TRUE :
1563 CommandFlag_FALSE,
1564 sizeof(CommandFlag_TRUE),
1565 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
1566
1567 dprintf(DEBUG_tcg, "Return code from TPM_SetOwnerInstall() = 0x%08x\n",
1568 *returnCode);
1569
1570 if (rc || *returnCode)
1571 goto err_exit;
1572
1573 if (verbose)
1574 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1575
1576 return 0;
1577
1578err_exit:
1579 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1580 tpm_set_failure();
1581 if (rc)
1582 return rc;
1583 return TCG_TCG_COMMAND_ERROR;
1584}
1585
1586static u32
1587tpm_process_cfg(tpm_ppi_code msgCode, int verbose, u32 *returnCode)
1588{
1589 u32 rc = 0;
1590
1591 switch (msgCode) {
1592 case TPM_PPI_OP_NOOP: /* no-op */
1593 break;
1594
1595 case TPM_PPI_OP_ENABLE:
1596 rc = enable_tpm(1, returnCode, verbose);
1597 break;
1598
1599 case TPM_PPI_OP_DISABLE:
1600 rc = enable_tpm(0, returnCode, verbose);
1601 break;
1602
1603 case TPM_PPI_OP_ACTIVATE:
1604 rc = activate_tpm(1, 1, returnCode, verbose);
1605 break;
1606
1607 case TPM_PPI_OP_DEACTIVATE:
1608 rc = activate_tpm(0, 1, returnCode, verbose);
1609 break;
1610
1611 case TPM_PPI_OP_CLEAR:
1612 rc = force_clear(1, 0, returnCode, verbose);
1613 break;
1614
1615 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
1616 rc = set_owner_install(1, returnCode, verbose);
1617 break;
1618
1619 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
1620 rc = set_owner_install(0, returnCode, verbose);
1621 break;
1622
1623 default:
1624 break;
1625 }
1626
1627 if (rc)
1628 printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
1629 msgCode, rc, *returnCode);
1630
1631 return rc;
1632}
1633
1634static int
1635get_tpm_state(void)
1636{
1637 int state = 0;
1638 struct tpm_permanent_flags pf;
1639 int has_owner;
1640
1641 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1642 read_has_owner(&has_owner))
1643 return ~0;
1644
1645 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1646 state |= TPM_STATE_ENABLED;
1647
1648 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1649 state |= TPM_STATE_ACTIVE;
1650
1651 if (has_owner) {
1652 state |= TPM_STATE_OWNED;
1653 } else {
1654 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1655 state |= TPM_STATE_OWNERINSTALL;
1656 }
1657
1658 return state;
1659}
1660
1661static void
1662show_tpm_menu(int state, int next_scancodes[7])
1663{
1664 int i = 0;
1665
1666 printf("\nThe current state of the TPM is:\n");
1667
1668 if (state & TPM_STATE_ENABLED)
1669 printf(" Enabled");
1670 else
1671 printf(" Disabled");
1672
1673 if (state & TPM_STATE_ACTIVE)
1674 printf(" and active\n");
1675 else
1676 printf(" and deactivated\n");
1677
1678 if (state & TPM_STATE_OWNED)
1679 printf(" Ownership has been taken\n");
1680 else {
1681 printf(" Ownership has not been taken\n");
1682 if (state & TPM_STATE_OWNERINSTALL)
1683 printf(" A user can take ownership of the TPM\n");
1684 else
1685 printf(" Taking ownership of the TPM has been disabled\n");
1686 }
1687
1688 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1689 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1690 printf("\nNote: To make use of all functionality, the TPM must be "
1691 "enabled and active.\n");
1692 }
1693
1694 printf("\nAvailable options are:\n");
1695 if (state & TPM_STATE_ENABLED) {
1696 printf(" d. Disable the TPM\n");
1697 next_scancodes[i++] = 32;
1698
1699 if (state & TPM_STATE_ACTIVE) {
1700 printf(" v. Deactivate the TPM\n");
1701 next_scancodes[i++] = 47;
1702
1703 if (state & TPM_STATE_OWNERINSTALL) {
1704 printf(" p. Prevent installation of an owner\n");
1705 next_scancodes[i++] = 25;
1706 } else {
1707 printf(" s. Allow installation of an owner\n");
1708 next_scancodes[i++] = 31;
1709 }
1710 } else {
1711 printf(" a. Activate the TPM\n");
1712 next_scancodes[i++] = 30;
1713 }
1714
1715 } else {
1716 printf(" e. Enable the TPM\n");
1717 next_scancodes[i++] = 18;
1718 }
1719
1720 if (state & TPM_STATE_OWNED) {
1721 printf(" c. Clear ownership\n");
1722 next_scancodes[i++] = 46;
1723 }
1724
1725 next_scancodes[i++] = 0;
1726}
1727
1728void
1729tpm_menu(void)
1730{
1731 if (!CONFIG_TCGBIOS)
1732 return;
1733
1734 int scancode, next_scancodes[7];
1735 u32 rc, returnCode;
1736 tpm_ppi_code msgCode;
1737 int state = 0, i;
1738 int waitkey;
1739
1740 while (get_keystroke(0) >= 0)
1741 ;
1742 wait_threads();
1743
1744 printf("The Trusted Platform Module (TPM) is a hardware device in "
1745 "this machine.\n"
1746 "It can help verify the integrity of system software.\n\n");
1747
1748 for (;;) {
1749 if ((state = get_tpm_state()) != ~0) {
1750 show_tpm_menu(state, next_scancodes);
1751 } else {
1752 printf("TPM is not working correctly.\n");
1753 return;
1754 }
1755
1756 printf("\nIf no change is desired or if this menu was reached by "
1757 "mistake, press ESC to\n"
1758 "reboot the machine.\n");
1759
1760 msgCode = TPM_PPI_OP_NOOP;
1761
1762 waitkey = 1;
1763
1764 while (waitkey) {
1765 while ((scancode = get_keystroke(1000)) == ~0)
1766 ;
1767
1768 switch (scancode) {
1769 case 1:
1770 // ESC
1771 reset();
1772 break;
1773 case 18: /* e. enable */
1774 msgCode = TPM_PPI_OP_ENABLE;
1775 break;
1776 case 32: /* d. disable */
1777 msgCode = TPM_PPI_OP_DISABLE;
1778 break;
1779 case 30: /* a. activate */
1780 msgCode = TPM_PPI_OP_ACTIVATE;
1781 break;
1782 case 47: /* v. deactivate */
1783 msgCode = TPM_PPI_OP_DEACTIVATE;
1784 break;
1785 case 46: /* c. clear owner */
1786 msgCode = TPM_PPI_OP_CLEAR;
1787 break;
1788 case 25: /* p. prevent ownerinstall */
1789 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1790 break;
1791 case 31: /* s. allow ownerinstall */
1792 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1793 break;
1794 default:
1795 continue;
1796 }
1797
1798 /*
1799 * Using the next_scancodes array, check whether the
1800 * pressed key is currently a valid option.
1801 */
1802 for (i = 0; i < sizeof(next_scancodes); i++) {
1803 if (next_scancodes[i] == 0)
1804 break;
1805
1806 if (next_scancodes[i] == scancode) {
1807 rc = tpm_process_cfg(msgCode, 1, &returnCode);
1808
1809 if (rc)
1810 printf("An error occurred: 0x%x\n", rc);
1811 waitkey = 0;
1812 break;
1813 }
1814 }
1815 }
1816 }
1817}