blob: 55e38a958843bc12bd43c1aef5913800cc322d6d [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 = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500475 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
476 .hdr.totlen = cpu_to_be32(sizeof(tre)),
477 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
478 .pcrindex = cpu_to_be32(pcpes->pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500479 };
480 memcpy(tre.digest, pcpes->digest, sizeof(tre.digest));
481
482 struct tpm_rsp_extend rsp;
483 u32 resp_length = sizeof(rsp);
Kevin O'Connora0599152015-11-28 08:08:57 -0500484 u32 rc = transmit(0, &tre.hdr, &rsp, &resp_length, TPM_DURATION_TYPE_SHORT);
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500485 if (rc || resp_length != sizeof(rsp)) {
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500486 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500487 return rc;
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500488 }
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500489
490 rc = tpm_log_event(pcpes, event);
491 if (rc)
492 tpm_set_failure();
493 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500494}
495
Kevin O'Connor92244402015-11-22 16:54:18 -0500496static void
497tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
498{
499 if (hashdata)
500 sha1(hashdata, hashdata_length, pcpes->digest);
501}
502
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500503/*
504 * Add a measurement to the log; the data at data_seg:data/length are
505 * appended to the TCG_PCClientPCREventStruct
506 *
507 * Input parameters:
508 * pcrindex : which PCR to extend
509 * event_type : type of event; specs section on 'Event Types'
510 * event : pointer to info (e.g., string) to be added to log as-is
511 * event_length: length of the event
512 * hashdata : pointer to the data to be hashed
513 * hashdata_length: length of the data to be hashed
514 */
515static u32
516tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
517 const char *event, u32 event_length,
518 const u8 *hashdata, u32 hashdata_length)
519{
520 struct pcpes pcpes = {
521 .pcrindex = pcrindex,
522 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500523 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500524 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500525 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500526 return tpm_log_extend_event(&pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500527}
528
529
530/****************************************************************
531 * Setup and Measurements
532 ****************************************************************/
533
Kevin O'Connora6175422015-11-22 11:28:14 -0500534// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500535static u32
Kevin O'Connora6175422015-11-22 11:28:14 -0500536tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500537{
Kevin O'Connora6175422015-11-22 11:28:14 -0500538 u32 len = strlen(string);
539 return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
540 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500541}
542
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500543/*
544 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
545 */
546static u32
547tpm_add_event_separators(void)
548{
549 u32 rc;
550 u32 pcrIndex = 0;
551
552 if (!CONFIG_TCGBIOS)
553 return 0;
554
555 if (!has_working_tpm())
556 return TCG_GENERAL_ERROR;
557
Kevin O'Connora6175422015-11-22 11:28:14 -0500558 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500559 while (pcrIndex <= 7) {
Kevin O'Connora6175422015-11-22 11:28:14 -0500560 rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
561 NULL, 0,
562 (u8 *)evt_separator,
563 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500564 if (rc)
565 break;
566 pcrIndex ++;
567 }
568
569 return rc;
570}
571
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500572static u32
573tpm_smbios_measure(void)
574{
575 if (!CONFIG_TCGBIOS)
576 return 0;
577
578 if (!has_working_tpm())
579 return TCG_GENERAL_ERROR;
580
581 u32 rc;
582 struct pcctes pcctes = {
583 .eventid = 1,
584 .eventdatasize = SHA1_BUFSIZE,
585 };
586 struct smbios_entry_point *sep = SMBiosAddr;
587
588 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
589
590 if (!sep)
591 return 0;
592
593 rc = sha1((const u8 *)sep->structure_table_address,
594 sep->structure_table_length, pcctes.digest);
595 if (rc)
596 return rc;
597
598 return tpm_add_measurement_to_log(1,
599 EV_EVENT_TAG,
600 (const char *)&pcctes, sizeof(pcctes),
601 (u8 *)&pcctes, sizeof(pcctes));
602}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400603
604static u32
605tpm_startup(void)
606{
607 u32 rc;
608 u32 returnCode;
609
610 if (!has_working_tpm())
611 return TCG_GENERAL_ERROR;
612
613 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger5aa2a752015-03-23 14:22:17 -0400614 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400615 Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400616 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400617
618 dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n",
619 returnCode);
620
621 if (CONFIG_COREBOOT) {
622 /* with other firmware on the system the TPM may already have been
623 * initialized
624 */
625 if (returnCode == TPM_INVALID_POSTINIT)
626 returnCode = 0;
627 }
628
629 if (rc || returnCode)
630 goto err_exit;
631
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500632 rc = determine_timeouts();
633 if (rc)
634 goto err_exit;
635
Stefan Berger5aa2a752015-03-23 14:22:17 -0400636 rc = build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400637 NULL, 0, &returnCode, TPM_DURATION_TYPE_LONG);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400638
639 dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n",
640 returnCode);
641
642 if (rc || returnCode)
643 goto err_exit;
644
Stefan Berger5aa2a752015-03-23 14:22:17 -0400645 rc = build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400646 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400647
648 dprintf(DEBUG_tcg, "Return code from TSC_ResetEstablishmentBit = 0x%08x\n",
649 returnCode);
650
651 if (rc || (returnCode != 0 && returnCode != TPM_BAD_LOCALITY))
652 goto err_exit;
653
Stefan Berger2aff1c12015-05-26 15:48:33 -0400654 rc = tpm_smbios_measure();
655 if (rc)
656 goto err_exit;
657
Kevin O'Connor12575332015-11-22 11:34:38 -0500658 rc = tpm_add_action(2, "Start Option ROM Scan");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400659 if (rc)
660 goto err_exit;
661
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400662 return 0;
663
664err_exit:
665 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
666
Stefan Berger7fce1d92015-11-12 10:14:45 -0500667 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400668 if (rc)
669 return rc;
670 return TCG_TCG_COMMAND_ERROR;
671}
672
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500673/*
674 initialize the TCPA ACPI subsystem; find the ACPI tables and determine
675 where the TCPA table is.
676 */
677static void
678tpm_acpi_init(void)
679{
680 tpm_state.if_shutdown = 0;
681 tpm_state.tpm_probed = 0;
682 tpm_state.tpm_found = 0;
683 tpm_state.tpm_working = 0;
684
685 if (!has_working_tpm()) {
686 tpm_state.if_shutdown = 1;
687 return;
688 }
689
690 reset_acpi_log();
691}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400692
Kevin O'Connord6aca442015-06-10 11:00:17 -0400693void
694tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400695{
696 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400697 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400698
699 tpm_acpi_init();
Quan Xu67643952015-04-30 19:43:04 -0400700 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400701 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400702
Kevin O'Connord6aca442015-06-10 11:00:17 -0400703 tpm_startup();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400704}
705
Kevin O'Connord6aca442015-06-10 11:00:17 -0400706void
707tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400708{
709 u32 rc;
710 u32 returnCode;
711
712 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400713 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400714
715 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400716 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400717
Stefan Berger5aa2a752015-03-23 14:22:17 -0400718 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400719 PhysicalPresence_CMD_ENABLE,
720 sizeof(PhysicalPresence_CMD_ENABLE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400721 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400722 if (rc || returnCode)
723 goto err_exit;
724
Stefan Berger5aa2a752015-03-23 14:22:17 -0400725 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400726 PhysicalPresence_NOT_PRESENT_LOCK,
727 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400728 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400729 if (rc || returnCode)
730 goto err_exit;
731
Kevin O'Connor12575332015-11-22 11:34:38 -0500732 rc = tpm_add_action(4, "Calling INT 19h");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400733 if (rc)
734 goto err_exit;
735
736 rc = tpm_add_event_separators();
737 if (rc)
738 goto err_exit;
739
Kevin O'Connord6aca442015-06-10 11:00:17 -0400740 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400741
742err_exit:
743 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
744
Stefan Berger7fce1d92015-11-12 10:14:45 -0500745 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400746}
747
Stefan Berger5aa2a752015-03-23 14:22:17 -0400748/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500749 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400750 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500751u32
752tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400753{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500754 if (!CONFIG_TCGBIOS)
755 return 0;
Stefan Berger5aa2a752015-03-23 14:22:17 -0400756
Stefan Berger7fce1d92015-11-12 10:14:45 -0500757 if (!has_working_tpm())
758 return TCG_GENERAL_ERROR;
759
Stefan Berger5aa2a752015-03-23 14:22:17 -0400760 u32 rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500761 struct pcctes_romex pcctes = {
762 .eventid = 7,
763 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400764 };
765
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500766 rc = sha1((const u8 *)addr, len, pcctes.digest);
Stefan Berger6c376b42015-11-12 10:14:49 -0500767 if (rc)
768 return rc;
769
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500770 return tpm_add_measurement_to_log(2,
771 EV_EVENT_TAG,
772 (const char *)&pcctes, sizeof(pcctes),
773 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500774}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400775
Stefan Berger2aff1c12015-05-26 15:48:33 -0400776u32
777tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
778{
779 if (!CONFIG_TCGBIOS)
780 return 0;
781
782 if (!has_working_tpm())
783 return TCG_GENERAL_ERROR;
784
Stefan Berger4cdbc412015-11-30 11:14:18 -0500785 if (length < 0x200)
786 return TCG_INVALID_INPUT_PARA;
787
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500788 const char *string = "Booting BCV device 00h (Floppy)";
789 if (bootdrv == 0x80)
790 string = "Booting BCV device 80h (HDD)";
791 u32 rc = tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400792 if (rc)
793 return rc;
794
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500795 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
796 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500797 string = "MBR";
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500798 rc = tpm_add_measurement_to_log(4, EV_IPL,
799 string, strlen(string),
800 addr, 0x1b8);
801 if (rc)
802 return rc;
803
804 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
805 string = "MBR PARTITION_TABLE";
806 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
807 string, strlen(string),
808 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400809}
810
811u32
812tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
813{
814 if (!CONFIG_TCGBIOS)
815 return 0;
816
817 if (!has_working_tpm())
818 return TCG_GENERAL_ERROR;
819
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500820 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400821 if (rc)
822 return rc;
823
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500824 /* specs: see section 'El Torito' */
825 const char *string = "EL TORITO IPL";
826 return tpm_add_measurement_to_log(4, EV_IPL,
827 string, strlen(string),
828 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400829}
830
831u32
832tpm_add_cdrom_catalog(const u8 *addr, u32 length)
833{
834 if (!CONFIG_TCGBIOS)
835 return 0;
836
837 if (!has_working_tpm())
838 return TCG_GENERAL_ERROR;
839
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500840 u32 rc = tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400841 if (rc)
842 return rc;
843
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500844 /* specs: see section 'El Torito' */
845 const char *string = "BOOT CATALOG";
846 return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
847 string, strlen(string),
848 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400849}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400850
Kevin O'Connord6aca442015-06-10 11:00:17 -0400851void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400852tpm_s3_resume(void)
853{
854 u32 rc;
855 u32 returnCode;
856
857 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400858 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400859
860 if (!has_working_tpm())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400861 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400862
863 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
864
Stefan Berger5aa2a752015-03-23 14:22:17 -0400865 rc = build_and_send_cmd(0, TPM_ORD_Startup,
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400866 Startup_ST_STATE, sizeof(Startup_ST_STATE),
Stefan Bergerfc2e7152015-06-09 19:56:31 -0400867 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400868
869 dprintf(DEBUG_tcg, "TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
870 returnCode);
871
872 if (rc || returnCode)
873 goto err_exit;
874
Kevin O'Connord6aca442015-06-10 11:00:17 -0400875 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400876
877err_exit:
878 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
879
Stefan Berger7fce1d92015-11-12 10:14:45 -0500880 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400881}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500882
883
884/****************************************************************
885 * BIOS interface
886 ****************************************************************/
887
888static inline void *input_buf32(struct bregs *regs)
889{
890 return MAKE_FLATPTR(regs->es, regs->di);
891}
892
893static inline void *output_buf32(struct bregs *regs)
894{
895 return MAKE_FLATPTR(regs->ds, regs->si);
896}
897
898static u32
899hash_log_extend_event_int(const struct hleei_short *hleei_s,
900 struct hleeo *hleeo)
901{
902 u32 rc = 0;
903 struct hleo hleo;
904 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
905 const void *logdataptr;
906 u32 logdatalen;
907 struct pcpes *pcpes;
908 u32 pcrindex;
909
910 if (is_preboot_if_shutdown() != 0) {
911 rc = TCG_INTERFACE_SHUTDOWN;
912 goto err_exit;
913 }
914
915 /* short or long version? */
916 switch (hleei_s->ipblength) {
917 case sizeof(struct hleei_short):
918 /* short */
919 logdataptr = hleei_s->logdataptr;
920 logdatalen = hleei_s->logdatalen;
921 pcrindex = hleei_s->pcrindex;
922 break;
923
924 case sizeof(struct hleei_long):
925 /* long */
926 logdataptr = hleei_l->logdataptr;
927 logdatalen = hleei_l->logdatalen;
928 pcrindex = hleei_l->pcrindex;
929 break;
930
931 default:
932 /* bad input block */
933 rc = TCG_INVALID_INPUT_PARA;
934 goto err_exit;
935 }
936
937 pcpes = (struct pcpes *)logdataptr;
938
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500939 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
940 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500941 rc = TCG_INVALID_INPUT_PARA;
942 goto err_exit;
943 }
944
Kevin O'Connor92244402015-11-22 16:54:18 -0500945 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500946 rc = tpm_log_extend_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500947 if (rc)
948 goto err_exit;
949
950 hleeo->opblength = sizeof(struct hleeo);
951 hleeo->reserved = 0;
952 hleeo->eventnumber = hleo.eventnumber;
953
954err_exit:
955 if (rc != 0) {
956 hleeo->opblength = 4;
957 hleeo->reserved = 0;
958 }
959
960 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500961}
962
963static u32
964pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
965{
966 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500967
968 if (is_preboot_if_shutdown()) {
969 rc = TCG_INTERFACE_SHUTDOWN;
970 goto err_exit;
971 }
972
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500973 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500974
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500975 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
976 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
977 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500978 rc = TCG_INVALID_INPUT_PARA;
979 goto err_exit;
980 }
981
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500982 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
983 rc = transmit(0, trh, pttto->tpmopout, &resbuflen,
984 TPM_DURATION_TYPE_LONG /* worst case */);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500985 if (rc)
986 goto err_exit;
987
988 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
989 pttto->reserved = 0;
990
991err_exit:
992 if (rc != 0) {
993 pttto->opblength = 4;
994 pttto->reserved = 0;
995 }
996
997 return rc;
998}
999
1000static u32
1001shutdown_preboot_interface(void)
1002{
1003 u32 rc = 0;
1004
1005 if (!is_preboot_if_shutdown()) {
1006 tpm_state.if_shutdown = 1;
1007 } else {
1008 rc = TCG_INTERFACE_SHUTDOWN;
1009 }
1010
1011 return rc;
1012}
1013
1014static u32
1015hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1016{
1017 u32 rc = 0;
1018 u16 size;
1019 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001020
1021 if (is_preboot_if_shutdown() != 0) {
1022 rc = TCG_INTERFACE_SHUTDOWN;
1023 goto err_exit;
1024 }
1025
1026 size = hlei->ipblength;
1027 if (size != sizeof(*hlei)) {
1028 rc = TCG_INVALID_INPUT_PARA;
1029 goto err_exit;
1030 }
1031
1032 pcpes = (struct pcpes *)hlei->logdataptr;
1033
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001034 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
1035 || pcpes->eventtype != hlei->logeventtype
1036 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001037 rc = TCG_INVALID_INPUT_PARA;
1038 goto err_exit;
1039 }
1040
Kevin O'Connor92244402015-11-22 16:54:18 -05001041 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001042 rc = tpm_log_event(pcpes, pcpes->event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001043 if (rc)
1044 goto err_exit;
1045
1046 /* updating the log was fine */
1047 hleo->opblength = sizeof(struct hleo);
1048 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001049 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001050
1051err_exit:
1052 if (rc != 0) {
1053 hleo->opblength = 2;
1054 hleo->reserved = 0;
1055 }
1056
1057 return rc;
1058}
1059
1060static u32
1061hash_all_int(const struct hai *hai, u8 *hash)
1062{
1063 if (is_preboot_if_shutdown() != 0)
1064 return TCG_INTERFACE_SHUTDOWN;
1065
1066 if (hai->ipblength != sizeof(struct hai) ||
1067 hai->hashdataptr == 0 ||
1068 hai->hashdatalen == 0 ||
1069 hai->algorithmid != TPM_ALG_SHA)
1070 return TCG_INVALID_INPUT_PARA;
1071
1072 return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1073}
1074
1075static u32
1076tss_int(struct ti *ti, struct to *to)
1077{
1078 u32 rc = 0;
1079
1080 if (is_preboot_if_shutdown() == 0) {
1081 rc = TCG_PC_UNSUPPORTED;
1082 } else {
1083 rc = TCG_INTERFACE_SHUTDOWN;
1084 }
1085
1086 to->opblength = sizeof(struct to);
1087 to->reserved = 0;
1088
1089 return rc;
1090}
1091
1092static u32
1093compact_hash_log_extend_event_int(u8 *buffer,
1094 u32 info,
1095 u32 length,
1096 u32 pcrindex,
1097 u32 *edx_ptr)
1098{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001099 struct pcpes pcpes = {
1100 .pcrindex = pcrindex,
1101 .eventtype = EV_COMPACT_HASH,
1102 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001103 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001104
1105 if (is_preboot_if_shutdown() != 0)
1106 return TCG_INTERFACE_SHUTDOWN;
1107
Kevin O'Connor92244402015-11-22 16:54:18 -05001108 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001109 u32 rc = tpm_log_extend_event(&pcpes, &info);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001110 if (rc == 0)
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001111 *edx_ptr = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001112
1113 return rc;
1114}
1115
1116void VISIBLE32FLAT
1117tpm_interrupt_handler32(struct bregs *regs)
1118{
1119 if (!CONFIG_TCGBIOS)
1120 return;
1121
1122 set_cf(regs, 0);
1123
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001124 switch ((enum irq_ids)regs->al) {
1125 case TCG_StatusCheck:
1126 if (is_tpm_present() == 0) {
1127 /* no TPM available */
1128 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1129 } else {
1130 regs->eax = 0;
1131 regs->ebx = TCG_MAGIC;
1132 regs->ch = TCG_VERSION_MAJOR;
1133 regs->cl = TCG_VERSION_MINOR;
1134 regs->edx = 0x0;
1135 regs->esi = (u32)tpm_state.log_area_start_address;
1136 regs->edi = (u32)tpm_state.log_area_last_entry;
1137 }
1138 break;
1139
1140 case TCG_HashLogExtendEvent:
1141 regs->eax =
1142 hash_log_extend_event_int(
1143 (struct hleei_short *)input_buf32(regs),
1144 (struct hleeo *)output_buf32(regs));
1145 break;
1146
1147 case TCG_PassThroughToTPM:
1148 regs->eax =
1149 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1150 (struct pttto *)output_buf32(regs));
1151 break;
1152
1153 case TCG_ShutdownPreBootInterface:
1154 regs->eax = shutdown_preboot_interface();
1155 break;
1156
1157 case TCG_HashLogEvent:
1158 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1159 (struct hleo*)output_buf32(regs));
1160 break;
1161
1162 case TCG_HashAll:
1163 regs->eax =
1164 hash_all_int((struct hai*)input_buf32(regs),
1165 (u8 *)output_buf32(regs));
1166 break;
1167
1168 case TCG_TSS:
1169 regs->eax = tss_int((struct ti*)input_buf32(regs),
1170 (struct to*)output_buf32(regs));
1171 break;
1172
1173 case TCG_CompactHashLogExtendEvent:
1174 regs->eax =
1175 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1176 regs->esi,
1177 regs->ecx,
1178 regs->edx,
1179 &regs->edx);
1180 break;
1181
1182 default:
1183 set_cf(regs, 1);
1184 }
1185
1186 return;
1187}
Stefan Berger320df852015-11-30 11:14:19 -05001188
Kevin O'Connor26e36172015-12-29 12:20:23 -05001189
1190/****************************************************************
1191 * TPM Configuration Menu
1192 ****************************************************************/
1193
Stefan Berger320df852015-11-30 11:14:19 -05001194static u32
1195read_stclear_flags(char *buf, int buf_len)
1196{
1197 u32 rc;
1198 u32 returnCode;
1199 struct tpm_res_getcap_stclear_flags stcf;
1200
1201 memset(buf, 0, buf_len);
1202
1203 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1204 GetCapability_STClear_Flags,
1205 sizeof(GetCapability_STClear_Flags),
1206 (u8 *)&stcf, sizeof(stcf),
1207 &returnCode, TPM_DURATION_TYPE_SHORT);
1208
1209 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1210 "= 0x%08x\n", returnCode);
1211
1212 if (rc || returnCode)
1213 goto err_exit;
1214
1215 memcpy(buf, &stcf.stclear_flags, buf_len);
1216
1217 return 0;
1218
1219err_exit:
1220 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1221
1222 tpm_set_failure();
1223 if (rc)
1224 return rc;
1225 return TCG_TCG_COMMAND_ERROR;
1226}
1227
1228static u32
1229assert_physical_presence(int verbose)
1230{
1231 u32 rc = 0;
1232 u32 returnCode;
1233 struct tpm_stclear_flags stcf;
1234
1235 rc = read_stclear_flags((char *)&stcf, sizeof(stcf));
1236 if (rc) {
1237 dprintf(DEBUG_tcg,
1238 "Error reading STClear flags: 0x%08x\n", rc);
1239 return rc;
1240 }
1241
1242 if (stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE])
1243 /* physical presence already asserted */
1244 return 0;
1245
1246 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
1247 PhysicalPresence_CMD_ENABLE,
1248 sizeof(PhysicalPresence_CMD_ENABLE),
1249 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
1250
1251 dprintf(DEBUG_tcg,
1252 "Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n",
1253 returnCode);
1254
1255 if (rc || returnCode) {
1256 if (verbose)
1257 printf("Error: Could not enable physical presence.\n\n");
1258 goto err_exit;
1259 }
1260
1261 rc = build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
1262 PhysicalPresence_PRESENT,
1263 sizeof(PhysicalPresence_PRESENT),
1264 NULL, 0, &returnCode, TPM_DURATION_TYPE_SHORT);
1265
1266 dprintf(DEBUG_tcg,
1267 "Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n",
1268 returnCode);
1269
1270 if (rc || returnCode) {
1271 if (verbose)
1272 printf("Error: Could not set presence flag.\n\n");
1273 goto err_exit;
1274 }
1275
1276 return 0;
1277
1278err_exit:
1279 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1280
1281 tpm_set_failure();
1282 if (rc)
1283 return rc;
1284 return TCG_TCG_COMMAND_ERROR;
1285}
1286
1287static u32
1288read_permanent_flags(char *buf, int buf_len)
1289{
1290 u32 rc;
1291 u32 returnCode;
1292 struct tpm_res_getcap_perm_flags pf;
1293
1294 memset(buf, 0, buf_len);
1295
1296 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1297 GetCapability_Permanent_Flags,
1298 sizeof(GetCapability_Permanent_Flags),
1299 (u8 *)&pf, sizeof(pf),
1300 &returnCode, TPM_DURATION_TYPE_SHORT);
1301
1302 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1303 "= 0x%08x\n", returnCode);
1304
1305 if (rc || returnCode)
1306 goto err_exit;
1307
1308 memcpy(buf, &pf.perm_flags, buf_len);
1309
1310 return 0;
1311
1312err_exit:
1313 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1314
1315 tpm_set_failure();
1316 if (rc)
1317 return rc;
1318 return TCG_TCG_COMMAND_ERROR;
1319}
1320
1321static u32
1322read_has_owner(int *has_owner)
1323{
1324 u32 rc;
1325 u32 returnCode;
1326 struct tpm_res_getcap_ownerauth oauth;
1327
1328 rc = build_and_send_cmd(0, TPM_ORD_GetCapability,
1329 GetCapability_OwnerAuth,
1330 sizeof(GetCapability_OwnerAuth),
1331 (u8 *)&oauth, sizeof(oauth),
1332 &returnCode, TPM_DURATION_TYPE_SHORT);
1333
1334 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability() "
1335 "= 0x%08x\n", returnCode);
1336
1337 if (rc || returnCode)
1338 goto err_exit;
1339
1340 *has_owner = oauth.flag;
1341
1342 return 0;
1343
1344err_exit:
1345 dprintf(DEBUG_tcg,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1346
1347 tpm_set_failure();
1348 if (rc)
1349 return rc;
1350 return TCG_TCG_COMMAND_ERROR;
1351}
1352
1353static u32
1354enable_tpm(int enable, u32 *returnCode, int verbose)
1355{
1356 u32 rc;
1357 struct tpm_permanent_flags pf;
1358
1359 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1360 if (rc)
1361 return rc;
1362
1363 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1364 return 0;
1365
1366 rc = assert_physical_presence(verbose);
1367 if (rc) {
1368 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1369 return rc;
1370 }
1371
1372 rc = build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1373 : TPM_ORD_PhysicalDisable,
1374 NULL, 0, NULL, 0, returnCode,
1375 TPM_DURATION_TYPE_SHORT);
1376 if (enable)
1377 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalEnable = 0x%08x\n",
1378 *returnCode);
1379 else
1380 dprintf(DEBUG_tcg, "Return code from TPM_PhysicalDisable = 0x%08x\n",
1381 *returnCode);
1382
1383 if (rc || *returnCode)
1384 goto err_exit;
1385
1386 return 0;
1387
1388err_exit:
1389 if (enable)
1390 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1391 else
1392 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1393
1394 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1395
1396 tpm_set_failure();
1397 if (rc)
1398 return rc;
1399 return TCG_TCG_COMMAND_ERROR;
1400}
1401
1402static u32
1403activate_tpm(int activate, int allow_reset, u32 *returnCode, int verbose)
1404{
1405 u32 rc;
1406 struct tpm_permanent_flags pf;
1407
1408 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1409 if (rc)
1410 return rc;
1411
1412 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1413 return 0;
1414
1415 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1416 return 0;
1417
1418 rc = assert_physical_presence(verbose);
1419 if (rc) {
1420 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1421 return rc;
1422 }
1423
1424 rc = build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1425 activate ? CommandFlag_FALSE
1426 : CommandFlag_TRUE,
1427 activate ? sizeof(CommandFlag_FALSE)
1428 : sizeof(CommandFlag_TRUE),
1429 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
1430
1431 dprintf(DEBUG_tcg,
1432 "Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
1433 activate ? 0 : 1, *returnCode);
1434
1435 if (rc || *returnCode)
1436 goto err_exit;
1437
1438 if (activate && allow_reset) {
1439 if (verbose) {
1440 printf("Requiring a reboot to activate the TPM.\n");
1441
1442 msleep(2000);
1443 }
1444 reset();
1445 }
1446
1447 return 0;
1448
1449err_exit:
1450 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1451
1452 tpm_set_failure();
1453 if (rc)
1454 return rc;
1455 return TCG_TCG_COMMAND_ERROR;
1456}
1457
1458static u32
1459enable_activate(int allow_reset, u32 *returnCode, int verbose)
1460{
1461 u32 rc;
1462
1463 rc = enable_tpm(1, returnCode, verbose);
1464 if (rc)
1465 return rc;
1466
1467 rc = activate_tpm(1, allow_reset, returnCode, verbose);
1468
1469 return rc;
1470}
1471
1472static u32
1473force_clear(int enable_activate_before, int enable_activate_after,
1474 u32 *returnCode, int verbose)
1475{
1476 u32 rc;
1477 int has_owner;
1478
1479 rc = read_has_owner(&has_owner);
1480 if (rc)
1481 return rc;
1482 if (!has_owner) {
1483 if (verbose)
1484 printf("TPM does not have an owner.\n");
1485 return 0;
1486 }
1487
1488 if (enable_activate_before) {
1489 rc = enable_activate(0, returnCode, verbose);
1490 if (rc) {
1491 dprintf(DEBUG_tcg,
1492 "TCGBIOS: Enabling/activating the TPM failed.\n");
1493 return rc;
1494 }
1495 }
1496
1497 rc = assert_physical_presence(verbose);
1498 if (rc) {
1499 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1500 return rc;
1501 }
1502
1503 rc = build_and_send_cmd(0, TPM_ORD_ForceClear,
1504 NULL, 0, NULL, 0, returnCode,
1505 TPM_DURATION_TYPE_SHORT);
1506
1507 dprintf(DEBUG_tcg, "Return code from TPM_ForceClear() = 0x%08x\n",
1508 *returnCode);
1509
1510 if (rc || *returnCode)
1511 goto err_exit;
1512
1513 if (!enable_activate_after) {
1514 if (verbose)
1515 printf("Owner successfully cleared.\n"
1516 "You will need to enable/activate the TPM again.\n\n");
1517 return 0;
1518 }
1519
1520 enable_activate(1, returnCode, verbose);
1521
1522 return 0;
1523
1524err_exit:
1525 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1526
1527 tpm_set_failure();
1528 if (rc)
1529 return rc;
1530 return TCG_TCG_COMMAND_ERROR;
1531}
1532
1533static u32
1534set_owner_install(int allow, u32 *returnCode, int verbose)
1535{
1536 u32 rc;
1537 int has_owner;
1538 struct tpm_permanent_flags pf;
1539
1540 rc = read_has_owner(&has_owner);
1541 if (rc)
1542 return rc;
1543 if (has_owner) {
1544 if (verbose)
1545 printf("Must first remove owner.\n");
1546 return 0;
1547 }
1548
1549 rc = read_permanent_flags((char *)&pf, sizeof(pf));
1550 if (rc)
1551 return rc;
1552
1553 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1554 if (verbose)
1555 printf("TPM must first be enable.\n");
1556 return 0;
1557 }
1558
1559 rc = assert_physical_presence(verbose);
1560 if (rc) {
1561 dprintf(DEBUG_tcg, "TCGBIOS: Asserting physical presence failed.\n");
1562 return rc;
1563 }
1564
1565 rc = build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1566 (allow) ? CommandFlag_TRUE :
1567 CommandFlag_FALSE,
1568 sizeof(CommandFlag_TRUE),
1569 NULL, 0, returnCode, TPM_DURATION_TYPE_SHORT);
1570
1571 dprintf(DEBUG_tcg, "Return code from TPM_SetOwnerInstall() = 0x%08x\n",
1572 *returnCode);
1573
1574 if (rc || *returnCode)
1575 goto err_exit;
1576
1577 if (verbose)
1578 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1579
1580 return 0;
1581
1582err_exit:
1583 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1584 tpm_set_failure();
1585 if (rc)
1586 return rc;
1587 return TCG_TCG_COMMAND_ERROR;
1588}
1589
1590static u32
1591tpm_process_cfg(tpm_ppi_code msgCode, int verbose, u32 *returnCode)
1592{
1593 u32 rc = 0;
1594
1595 switch (msgCode) {
1596 case TPM_PPI_OP_NOOP: /* no-op */
1597 break;
1598
1599 case TPM_PPI_OP_ENABLE:
1600 rc = enable_tpm(1, returnCode, verbose);
1601 break;
1602
1603 case TPM_PPI_OP_DISABLE:
1604 rc = enable_tpm(0, returnCode, verbose);
1605 break;
1606
1607 case TPM_PPI_OP_ACTIVATE:
1608 rc = activate_tpm(1, 1, returnCode, verbose);
1609 break;
1610
1611 case TPM_PPI_OP_DEACTIVATE:
1612 rc = activate_tpm(0, 1, returnCode, verbose);
1613 break;
1614
1615 case TPM_PPI_OP_CLEAR:
1616 rc = force_clear(1, 0, returnCode, verbose);
1617 break;
1618
1619 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
1620 rc = set_owner_install(1, returnCode, verbose);
1621 break;
1622
1623 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
1624 rc = set_owner_install(0, returnCode, verbose);
1625 break;
1626
1627 default:
1628 break;
1629 }
1630
1631 if (rc)
1632 printf("Op %d: An error occurred: 0x%x TPM return code: 0x%x\n",
1633 msgCode, rc, *returnCode);
1634
1635 return rc;
1636}
1637
1638static int
1639get_tpm_state(void)
1640{
1641 int state = 0;
1642 struct tpm_permanent_flags pf;
1643 int has_owner;
1644
1645 if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
1646 read_has_owner(&has_owner))
1647 return ~0;
1648
1649 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1650 state |= TPM_STATE_ENABLED;
1651
1652 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1653 state |= TPM_STATE_ACTIVE;
1654
1655 if (has_owner) {
1656 state |= TPM_STATE_OWNED;
1657 } else {
1658 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1659 state |= TPM_STATE_OWNERINSTALL;
1660 }
1661
1662 return state;
1663}
1664
1665static void
1666show_tpm_menu(int state, int next_scancodes[7])
1667{
1668 int i = 0;
1669
1670 printf("\nThe current state of the TPM is:\n");
1671
1672 if (state & TPM_STATE_ENABLED)
1673 printf(" Enabled");
1674 else
1675 printf(" Disabled");
1676
1677 if (state & TPM_STATE_ACTIVE)
1678 printf(" and active\n");
1679 else
1680 printf(" and deactivated\n");
1681
1682 if (state & TPM_STATE_OWNED)
1683 printf(" Ownership has been taken\n");
1684 else {
1685 printf(" Ownership has not been taken\n");
1686 if (state & TPM_STATE_OWNERINSTALL)
1687 printf(" A user can take ownership of the TPM\n");
1688 else
1689 printf(" Taking ownership of the TPM has been disabled\n");
1690 }
1691
1692 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1693 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1694 printf("\nNote: To make use of all functionality, the TPM must be "
1695 "enabled and active.\n");
1696 }
1697
1698 printf("\nAvailable options are:\n");
1699 if (state & TPM_STATE_ENABLED) {
1700 printf(" d. Disable the TPM\n");
1701 next_scancodes[i++] = 32;
1702
1703 if (state & TPM_STATE_ACTIVE) {
1704 printf(" v. Deactivate the TPM\n");
1705 next_scancodes[i++] = 47;
1706
1707 if (state & TPM_STATE_OWNERINSTALL) {
1708 printf(" p. Prevent installation of an owner\n");
1709 next_scancodes[i++] = 25;
1710 } else {
1711 printf(" s. Allow installation of an owner\n");
1712 next_scancodes[i++] = 31;
1713 }
1714 } else {
1715 printf(" a. Activate the TPM\n");
1716 next_scancodes[i++] = 30;
1717 }
1718
1719 } else {
1720 printf(" e. Enable the TPM\n");
1721 next_scancodes[i++] = 18;
1722 }
1723
1724 if (state & TPM_STATE_OWNED) {
1725 printf(" c. Clear ownership\n");
1726 next_scancodes[i++] = 46;
1727 }
1728
1729 next_scancodes[i++] = 0;
1730}
1731
1732void
1733tpm_menu(void)
1734{
1735 if (!CONFIG_TCGBIOS)
1736 return;
1737
1738 int scancode, next_scancodes[7];
1739 u32 rc, returnCode;
1740 tpm_ppi_code msgCode;
1741 int state = 0, i;
1742 int waitkey;
1743
1744 while (get_keystroke(0) >= 0)
1745 ;
1746 wait_threads();
1747
1748 printf("The Trusted Platform Module (TPM) is a hardware device in "
1749 "this machine.\n"
1750 "It can help verify the integrity of system software.\n\n");
1751
1752 for (;;) {
1753 if ((state = get_tpm_state()) != ~0) {
1754 show_tpm_menu(state, next_scancodes);
1755 } else {
1756 printf("TPM is not working correctly.\n");
1757 return;
1758 }
1759
1760 printf("\nIf no change is desired or if this menu was reached by "
1761 "mistake, press ESC to\n"
1762 "reboot the machine.\n");
1763
1764 msgCode = TPM_PPI_OP_NOOP;
1765
1766 waitkey = 1;
1767
1768 while (waitkey) {
1769 while ((scancode = get_keystroke(1000)) == ~0)
1770 ;
1771
1772 switch (scancode) {
1773 case 1:
1774 // ESC
1775 reset();
1776 break;
1777 case 18: /* e. enable */
1778 msgCode = TPM_PPI_OP_ENABLE;
1779 break;
1780 case 32: /* d. disable */
1781 msgCode = TPM_PPI_OP_DISABLE;
1782 break;
1783 case 30: /* a. activate */
1784 msgCode = TPM_PPI_OP_ACTIVATE;
1785 break;
1786 case 47: /* v. deactivate */
1787 msgCode = TPM_PPI_OP_DEACTIVATE;
1788 break;
1789 case 46: /* c. clear owner */
1790 msgCode = TPM_PPI_OP_CLEAR;
1791 break;
1792 case 25: /* p. prevent ownerinstall */
1793 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1794 break;
1795 case 31: /* s. allow ownerinstall */
1796 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1797 break;
1798 default:
1799 continue;
1800 }
1801
1802 /*
1803 * Using the next_scancodes array, check whether the
1804 * pressed key is currently a valid option.
1805 */
1806 for (i = 0; i < sizeof(next_scancodes); i++) {
1807 if (next_scancodes[i] == 0)
1808 break;
1809
1810 if (next_scancodes[i] == scancode) {
1811 rc = tpm_process_cfg(msgCode, 1, &returnCode);
1812
1813 if (rc)
1814 printf("An error occurred: 0x%x\n", rc);
1815 waitkey = 0;
1816 break;
1817 }
1818 }
1819 }
1820 }
1821}