blob: f9c6f74dd60c835073063eb3681c5f4dc8805efb [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 Berger74544fa2016-08-05 11:07:08 -040027#include "malloc.h" // malloc_high
Stefan Bergerb310dfa2015-03-23 14:22:16 -040028
Stefan Bergerf53b93b2016-02-02 13:09:12 -050029/****************************************************************
30 * TPM 1.2 commands
31 ****************************************************************/
32
Stefan Berger0d289b52015-06-09 19:56:29 -040033static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
34static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040035
Stefan Berger0d289b52015-06-09 19:56:29 -040036static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
Stefan Berger0d289b52015-06-09 19:56:29 -040037static const u8 PhysicalPresence_PRESENT[] = { 0x00, 0x08 };
38static const u8 PhysicalPresence_NOT_PRESENT_LOCK[] = { 0x00, 0x14 };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040039
40static const u8 CommandFlag_FALSE[1] = { 0x00 };
41static const u8 CommandFlag_TRUE[1] = { 0x01 };
42
Stefan Bergerf53b93b2016-02-02 13:09:12 -050043/****************************************************************
44 * TPM 2 commands
45 ****************************************************************/
Kevin O'Connor27065322015-11-28 14:25:41 -050046
Stefan Bergerf53b93b2016-02-02 13:09:12 -050047static const u8 Startup_SU_CLEAR[] = { 0x00, TPM2_SU_CLEAR};
48static const u8 Startup_SU_STATE[] = { 0x00, TPM2_SU_STATE};
49
50static const u8 TPM2_SelfTest_YES[] = { TPM2_YES }; /* full test */
51
52
53typedef u8 tpm_ppi_code;
Stefan Bergerb310dfa2015-03-23 14:22:16 -040054
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050055/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050056 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050057 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040058
Kevin O'Connor27065322015-11-28 14:25:41 -050059struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050060 /* length of the TCPA log buffer */
61 u32 log_area_minimum_length;
62
63 /* start address of TCPA log buffer */
64 u8 * log_area_start_address;
65
66 /* number of log entries written */
67 u32 entry_count;
68
69 /* address to write next log entry to */
70 u8 * log_area_next_entry;
71
72 /* address of last entry written (need for TCG_StatusCheck) */
73 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050074} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050075
Stefan Berger115d0082016-01-07 12:02:49 -050076static int TPM_has_physical_presence;
77
Stefan Bergerefc49cf2016-02-02 13:09:09 -050078static TPMVersion TPM_version;
79
Stefan Berger74544fa2016-08-05 11:07:08 -040080static u32 tpm20_pcr_selection_size;
81static struct tpml_pcr_selection *tpm20_pcr_selection;
82
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050083static struct tcpa_descriptor_rev2 *
84find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
85{
Kevin O'Connor27065322015-11-28 14:25:41 -050086 if (!rsdp) {
87 dprintf(DEBUG_tcg,
88 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
89 return NULL;
90 }
91 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050092 if (!rsdt)
93 return NULL;
94
Kevin O'Connor27065322015-11-28 14:25:41 -050095 u32 length = rsdt->length;
96 u16 off = offsetof(struct rsdt_descriptor, entry);
97 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050098 while ((off + sizeof(rsdt->entry[0])) <= length) {
99 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -0500100 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500101
102 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -0500103 if (tcpa->signature == TCPA_SIGNATURE
104 && checksum(tcpa, tcpa->length) == 0)
105 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500106
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500107 off += sizeof(rsdt->entry[0]);
108 ctr++;
109 }
110
Kevin O'Connor27065322015-11-28 14:25:41 -0500111 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
112 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500113}
114
Kevin O'Connor27065322015-11-28 14:25:41 -0500115static int
116tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500117{
Kevin O'Connor27065322015-11-28 14:25:41 -0500118 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
119 if (!tcpa)
120 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500121
Kevin O'Connor27065322015-11-28 14:25:41 -0500122 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
123 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
124 if (!log_area_start_address || !log_area_minimum_length)
125 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500126
Kevin O'Connor27065322015-11-28 14:25:41 -0500127 memset(log_area_start_address, 0, log_area_minimum_length);
128 tpm_state.log_area_start_address = log_area_start_address;
129 tpm_state.log_area_minimum_length = log_area_minimum_length;
130 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500131 tpm_state.log_area_last_entry = NULL;
132 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500133 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500134}
135
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500136/*
137 * Extend the ACPI log with the given entry by copying the
138 * entry data into the log.
139 * Input
140 * pcpes : Pointer to the event 'header' to be copied into the log
141 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500142 *
143 * Output:
144 * Returns an error code in case of faiure, 0 in case of success
145 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500146static int
Kevin O'Connor93784032016-02-05 22:28:17 -0500147tpm_log_event(struct tcg_pcr_event2_sha1 *entry, const void *event
148 , TPMVersion tpm_version)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500149{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500150 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
151 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
152
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500153 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500154 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500155
Kevin O'Connor93784032016-02-05 22:28:17 -0500156 u32 size = sizeof(*entry) + entry->eventdatasize;
157 u32 logsize = (tpm_state.log_area_next_entry + size
158 - tpm_state.log_area_start_address);
159 if (logsize > tpm_state.log_area_minimum_length) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500160 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500161 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500162 }
163
Kevin O'Connor93784032016-02-05 22:28:17 -0500164 switch (tpm_version) {
165 case TPM_VERSION_1_2: ;
166 struct pcpes *pcpes = (void*)tpm_state.log_area_next_entry;
167 pcpes->pcrindex = entry->pcrindex;
168 pcpes->eventtype = entry->eventtype;
169 memcpy(pcpes->digest, entry->digests[0].sha1, sizeof(pcpes->digest));
170 pcpes->eventdatasize = entry->eventdatasize;
171 memcpy(pcpes->event, event, entry->eventdatasize);
172 size = sizeof(*pcpes) + entry->eventdatasize;
173 break;
174 case TPM_VERSION_2: ;
175 struct tcg_pcr_event2_sha1 *e = (void*)tpm_state.log_area_next_entry;
176 memcpy(e, entry, sizeof(*e));
177 memcpy(e->event, event, entry->eventdatasize);
178 break;
179 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500180
181 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
182 tpm_state.log_area_next_entry += size;
183 tpm_state.entry_count++;
184
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500185 return 0;
186}
187
Kevin O'Connor93784032016-02-05 22:28:17 -0500188/*
189 * Initialize the log; a TPM2 log needs a special TPM 1.2 log entry
190 * as the first entry serving identification purposes
191 */
192static void
193tpm_log_init(void)
194{
195 struct TCG_EfiSpecIdEventStruct event = {
196 .signature = "Spec ID Event03",
197 .platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
198 .specVersionMinor = 0,
199 .specVersionMajor = 2,
200 .specErrata = 0,
201 .uintnSize = 2,
202 .numberOfAlgorithms = 1,
203 .digestSizes[0] = {
204 .algorithmId = TPM2_ALG_SHA1,
205 .digestSize = SHA1_BUFSIZE,
206 },
207 .vendorInfoSize = 0,
208 };
209 struct tcg_pcr_event2_sha1 entry = {
210 .eventtype = EV_NO_ACTION,
211 .eventdatasize = sizeof(event),
212 };
213
214 switch (TPM_version) {
215 case TPM_VERSION_1_2:
216 break;
217 case TPM_VERSION_2:
218 /* write a 1.2 type of entry */
219 tpm_log_event(&entry, &event, TPM_VERSION_1_2);
220 }
221}
222
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500223
224/****************************************************************
225 * Helper functions
226 ****************************************************************/
227
Kevin O'Connord559a232015-11-28 08:35:26 -0500228u8 TPM_working VARLOW;
229
Stefan Berger115d0082016-01-07 12:02:49 -0500230static int
Kevin O'Connord559a232015-11-28 08:35:26 -0500231tpm_is_working(void)
232{
233 return CONFIG_TCGBIOS && TPM_working;
234}
235
Stefan Berger115d0082016-01-07 12:02:49 -0500236int
237tpm_can_show_menu(void)
238{
Stefan Berger1d37d522016-02-02 13:09:11 -0500239 switch (TPM_version) {
240 case TPM_VERSION_1_2:
241 return tpm_is_working() && TPM_has_physical_presence;
242 case TPM_VERSION_2:
243 return tpm_is_working();
244 }
245 return 0;
Stefan Berger115d0082016-01-07 12:02:49 -0500246}
247
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400248/*
249 * Send a TPM command with the given ordinal. Append the given buffer
250 * containing all data in network byte order to the command (this is
251 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400252 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500253static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500254tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append,
255 u32 append_size, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400256{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500257 struct {
258 struct tpm_req_header trqh;
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500259 u8 cmd[10];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500260 } PACKED req = {
261 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500262 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500263 .trqh.ordinal = cpu_to_be32(ordinal),
264 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500265
266 switch (TPM_version) {
267 case TPM_VERSION_1_2:
268 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
269 break;
270 case TPM_VERSION_2:
271 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
272 break;
273 }
274
Stefan Bergerece25612015-11-12 10:14:46 -0500275 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400276 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400277 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400278 memset(obuffer, 0x0, sizeof(obuffer));
279
Kevin O'Connor71479612015-12-29 14:32:19 -0500280 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500281 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500282 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500283 }
284 if (append_size)
285 memcpy(req.cmd, append, append_size);
286
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500287 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
288 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500289 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
290 ordinal, req.cmd[0], req.cmd[1], ret);
291 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400292}
293
Stefan Bergere444dce2016-02-02 13:09:17 -0500294static int
295tpm20_hierarchycontrol(u32 hierarchy, u8 state)
296{
297 /* we will try to deactivate the TPM now - ignoring all errors */
298 struct tpm2_req_hierarchycontrol trh = {
299 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
300 .hdr.totlen = cpu_to_be32(sizeof(trh)),
301 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
302 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
303 .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
304 .authblock = {
305 .handle = cpu_to_be32(TPM2_RS_PW),
306 .noncesize = cpu_to_be16(0),
307 .contsession = TPM2_YES,
308 .pwdsize = cpu_to_be16(0),
309 },
310 .enable = cpu_to_be32(hierarchy),
311 .state = state,
312 };
313 struct tpm_rsp_header rsp;
314 u32 resp_length = sizeof(rsp);
315 int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
316 TPM_DURATION_TYPE_MEDIUM);
317 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
318 ret = -1;
319
320 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
321 ret);
322
323 return ret;
324}
325
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500326static void
327tpm_set_failure(void)
328{
Stefan Berger1d37d522016-02-02 13:09:11 -0500329 switch (TPM_version) {
330 case TPM_VERSION_1_2:
331 /*
332 * We will try to deactivate the TPM now - ignoring all errors
333 * Physical presence is asserted.
334 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500335
Stefan Berger1d37d522016-02-02 13:09:11 -0500336 tpm_build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
337 NULL, 0, TPM_DURATION_TYPE_SHORT);
338 break;
339 case TPM_VERSION_2:
Stefan Bergere444dce2016-02-02 13:09:17 -0500340 tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
341 tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
Stefan Berger1d37d522016-02-02 13:09:11 -0500342 break;
343 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500344
Kevin O'Connord559a232015-11-28 08:35:26 -0500345 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500346}
347
Kevin O'Connorca606362015-12-29 14:21:29 -0500348static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500349tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
Kevin O'Connorca606362015-12-29 14:21:29 -0500350{
351 struct tpm_req_getcap trgc = {
352 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
353 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
354 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
355 .capArea = cpu_to_be32(cap),
356 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
357 .subCap = cpu_to_be32(subcap)
358 };
359 u32 resp_size = rsize;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500360 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
361 TPM_DURATION_TYPE_SHORT);
362 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
Kevin O'Connorca606362015-12-29 14:21:29 -0500363 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
364 " = %x\n", cap, subcap, ret);
365 if (ret) {
366 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
367 tpm_set_failure();
368 }
369 return ret;
370}
371
372static int
Stefan Berger74544fa2016-08-05 11:07:08 -0400373tpm20_getcapability(u32 capability, u32 property, u32 count,
374 struct tpm_rsp_header *rsp, u32 rsize)
375{
376 struct tpm2_req_getcapability trg = {
377 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
378 .hdr.totlen = cpu_to_be32(sizeof(trg)),
379 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
380 .capability = cpu_to_be32(capability),
381 .property = cpu_to_be32(property),
382 .propertycount = cpu_to_be32(count),
383 };
384
385 u32 resp_size = rsize;
386 int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
387 TPM_DURATION_TYPE_SHORT);
388 ret = (ret ||
389 rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
390
391 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
392 ret);
393
394 return ret;
395}
396
397static int
398tpm20_get_pcrbanks(void)
399{
400 u8 buffer[128];
401 struct tpm2_res_getcapability *trg =
402 (struct tpm2_res_getcapability *)&buffer;
403
404 int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
405 sizeof(buffer));
406 if (ret)
407 return ret;
408
409 u32 size = be32_to_cpu(trg->hdr.totlen) -
410 offsetof(struct tpm2_res_getcapability, data);
411 tpm20_pcr_selection = malloc_high(size);
412 if (tpm20_pcr_selection) {
413 memcpy(tpm20_pcr_selection, &trg->data, size);
414 tpm20_pcr_selection_size = size;
415 } else {
416 warn_noalloc();
417 ret = -1;
418 }
419
420 return ret;
421}
422
423static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500424tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400425{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400426 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500427 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
428 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500429 if (ret)
430 return ret;
431
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400432 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500433 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
434 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500435 if (ret)
436 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400437
Kevin O'Connorca606362015-12-29 14:21:29 -0500438 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400439 for (i = 0; i < 3; i++)
440 durations.durations[i] = be32_to_cpu(durations.durations[i]);
441
442 for (i = 0; i < 4; i++)
443 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
444
445 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
446 timeouts.timeouts[0],
447 timeouts.timeouts[1],
448 timeouts.timeouts[2],
449 timeouts.timeouts[3]);
450
451 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
452 durations.durations[0],
453 durations.durations[1],
454 durations.durations[2]);
455
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500456 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400457
458 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400459}
460
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500461static void
462tpm20_set_timeouts(void)
463{
464 u32 durations[3] = {
465 TPM2_DEFAULT_DURATION_SHORT,
466 TPM2_DEFAULT_DURATION_MEDIUM,
467 TPM2_DEFAULT_DURATION_LONG,
468 };
469 u32 timeouts[4] = {
470 TIS2_DEFAULT_TIMEOUT_A,
471 TIS2_DEFAULT_TIMEOUT_B,
472 TIS2_DEFAULT_TIMEOUT_C,
473 TIS2_DEFAULT_TIMEOUT_D,
474 };
475
476 tpmhw_set_timeouts(timeouts, durations);
477}
478
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500479static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500480tpm12_extend(u32 pcrindex, const u8 *digest)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500481{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500482 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500483 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
484 .hdr.totlen = cpu_to_be32(sizeof(tre)),
485 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500486 .pcrindex = cpu_to_be32(pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500487 };
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500488 memcpy(tre.digest, digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500489
490 struct tpm_rsp_extend rsp;
491 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500492 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
493 TPM_DURATION_TYPE_SHORT);
494 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500495 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500496
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500497 return 0;
498}
499
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500500static int tpm20_extend(u32 pcrindex, const u8 *digest)
501{
502 struct tpm2_req_extend tre = {
503 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
504 .hdr.totlen = cpu_to_be32(sizeof(tre)),
505 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
506 .pcrindex = cpu_to_be32(pcrindex),
507 .authblocksize = cpu_to_be32(sizeof(tre.authblock)),
508 .authblock = {
509 .handle = cpu_to_be32(TPM2_RS_PW),
510 .noncesize = cpu_to_be16(0),
511 .contsession = TPM2_YES,
512 .pwdsize = cpu_to_be16(0),
513 },
514 .digest = {
515 .count = cpu_to_be32(1),
516 .hashalg = cpu_to_be16(TPM2_ALG_SHA1),
517 },
518 };
519 memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1));
520
521 struct tpm_rsp_header rsp;
522 u32 resp_length = sizeof(rsp);
523 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
524 TPM_DURATION_TYPE_SHORT);
525 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
526 return -1;
527
528 return 0;
529}
530
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500531static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500532tpm_extend(u32 pcrindex, const u8 *digest)
533{
Stefan Berger1d37d522016-02-02 13:09:11 -0500534 switch (TPM_version) {
535 case TPM_VERSION_1_2:
536 return tpm12_extend(pcrindex, digest);
537 case TPM_VERSION_2:
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500538 return tpm20_extend(pcrindex, digest);
Stefan Berger1d37d522016-02-02 13:09:11 -0500539 }
540 return -1;
541}
542
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500543/*
544 * Add a measurement to the log; the data at data_seg:data/length are
545 * appended to the TCG_PCClientPCREventStruct
546 *
547 * Input parameters:
548 * pcrindex : which PCR to extend
549 * event_type : type of event; specs section on 'Event Types'
550 * event : pointer to info (e.g., string) to be added to log as-is
551 * event_length: length of the event
552 * hashdata : pointer to the data to be hashed
553 * hashdata_length: length of the data to be hashed
554 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500555static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500556tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
557 const char *event, u32 event_length,
558 const u8 *hashdata, u32 hashdata_length)
559{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500560 if (!tpm_is_working())
561 return;
562
Kevin O'Connor93784032016-02-05 22:28:17 -0500563 struct tcg_pcr_event2_sha1 entry = {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500564 .pcrindex = pcrindex,
565 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500566 .eventdatasize = event_length,
Kevin O'Connor93784032016-02-05 22:28:17 -0500567 .count = 1,
568 .digests[0].hashtype = TPM2_ALG_SHA1,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500569 };
Kevin O'Connor93784032016-02-05 22:28:17 -0500570 sha1(hashdata, hashdata_length, entry.digests[0].sha1);
571 int ret = tpm_extend(entry.pcrindex, entry.digests[0].sha1);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500572 if (ret) {
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500573 tpm_set_failure();
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500574 return;
575 }
Kevin O'Connor93784032016-02-05 22:28:17 -0500576 tpm_log_event(&entry, event, TPM_version);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500577}
578
579
580/****************************************************************
581 * Setup and Measurements
582 ****************************************************************/
583
Kevin O'Connora6175422015-11-22 11:28:14 -0500584// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500585static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500586tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500587{
Kevin O'Connora6175422015-11-22 11:28:14 -0500588 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500589 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
590 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500591}
592
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500593/*
594 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
595 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500596static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500597tpm_add_event_separators(void)
598{
Kevin O'Connora6175422015-11-22 11:28:14 -0500599 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500600 u32 pcrIndex;
601 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
602 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
603 NULL, 0,
604 evt_separator,
605 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500606}
607
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500608static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500609tpm_smbios_measure(void)
610{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500611 struct pcctes pcctes = {
612 .eventid = 1,
613 .eventdatasize = SHA1_BUFSIZE,
614 };
615 struct smbios_entry_point *sep = SMBiosAddr;
616
617 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
618
619 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500620 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500621
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500622 sha1((const u8 *)sep->structure_table_address,
623 sep->structure_table_length, pcctes.digest);
624 tpm_add_measurement_to_log(1,
625 EV_EVENT_TAG,
626 (const char *)&pcctes, sizeof(pcctes),
627 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500628}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400629
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500630static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500631tpm12_read_permanent_flags(char *buf, int buf_len)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500632{
633 memset(buf, 0, buf_len);
634
635 struct tpm_res_getcap_perm_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500636 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
637 , &pf.hdr, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500638 if (ret)
639 return -1;
640
641 memcpy(buf, &pf.perm_flags, buf_len);
642
643 return 0;
644}
645
646static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500647tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500648{
Stefan Berger1d37d522016-02-02 13:09:11 -0500649 int ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
650 PhysicalPresence_PRESENT,
651 sizeof(PhysicalPresence_PRESENT),
652 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500653 if (!ret)
654 return 0;
655
656 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500657 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500658 if (ret)
659 return -1;
660
Stefan Bergera2206d32016-01-07 12:02:48 -0500661 /* check if hardware physical presence is supported */
662 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
663 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -0500664 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -0500665 }
666
Stefan Bergera2206d32016-01-07 12:02:48 -0500667 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
668 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Stefan Berger1d37d522016-02-02 13:09:11 -0500669 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
670 PhysicalPresence_CMD_ENABLE,
671 sizeof(PhysicalPresence_CMD_ENABLE),
672 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500673
Stefan Berger1d37d522016-02-02 13:09:11 -0500674 return tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
675 PhysicalPresence_PRESENT,
676 sizeof(PhysicalPresence_PRESENT),
677 TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -0500678 }
Stefan Bergere55e37f2016-01-07 12:02:47 -0500679 return -1;
680}
681
682static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500683tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400684{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400685 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger1d37d522016-02-02 13:09:11 -0500686 int ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
687 Startup_ST_CLEAR,
688 sizeof(Startup_ST_CLEAR),
689 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500690 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400691 /* with other firmware on the system the TPM may already have been
692 * initialized
693 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500694 ret = 0;
695 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400696 goto err_exit;
697
Stefan Berger115d0082016-01-07 12:02:49 -0500698 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -0500699 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -0500700 if (!ret)
701 TPM_has_physical_presence = 1;
702
Stefan Berger1d37d522016-02-02 13:09:11 -0500703 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500704 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500705 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500706
Stefan Berger1d37d522016-02-02 13:09:11 -0500707 ret = tpm_build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
708 TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500709 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400710 goto err_exit;
711
Stefan Berger1d37d522016-02-02 13:09:11 -0500712 ret = tpm_build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
713 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500714 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400715 goto err_exit;
716
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400717 return 0;
718
719err_exit:
720 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
721
Stefan Berger7fce1d92015-11-12 10:14:45 -0500722 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500723 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400724}
725
Stefan Berger1d37d522016-02-02 13:09:11 -0500726static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500727tpm20_startup(void)
728{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500729 tpm20_set_timeouts();
730
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500731 int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
732 Startup_SU_CLEAR,
733 sizeof(Startup_SU_CLEAR),
734 TPM_DURATION_TYPE_SHORT);
735
736 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
737 ret);
738
739 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
740 /* with other firmware on the system the TPM may already have been
741 * initialized
742 */
743 ret = 0;
744
745 if (ret)
746 goto err_exit;
747
748 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
749 TPM2_SelfTest_YES,
750 sizeof(TPM2_SelfTest_YES),
751 TPM_DURATION_TYPE_LONG);
752
753 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
754 ret);
755
756 if (ret)
757 goto err_exit;
758
Stefan Berger74544fa2016-08-05 11:07:08 -0400759 ret = tpm20_get_pcrbanks();
760 if (ret)
761 goto err_exit;
762
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500763 return 0;
764
765err_exit:
766 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
767
768 tpm_set_failure();
769 return -1;
770}
771
772static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500773tpm_startup(void)
774{
775 switch (TPM_version) {
776 case TPM_VERSION_1_2:
777 return tpm12_startup();
778 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500779 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -0500780 }
781 return -1;
782}
783
Kevin O'Connord6aca442015-06-10 11:00:17 -0400784void
785tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400786{
787 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400788 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400789
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500790 TPM_version = tpmhw_probe();
791 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -0500792 return;
793
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500794 dprintf(DEBUG_tcg,
795 "TCGBIOS: Detected a TPM %s.\n",
796 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
797
798 int ret = tpm_tcpa_probe();
Kevin O'Connor27065322015-11-28 14:25:41 -0500799 if (ret)
800 return;
801
Kevin O'Connor93784032016-02-05 22:28:17 -0500802 tpm_log_init();
803
Kevin O'Connor27065322015-11-28 14:25:41 -0500804 TPM_working = 1;
805
Quan Xu67643952015-04-30 19:43:04 -0400806 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400807 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400808
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500809 ret = tpm_startup();
810 if (ret)
811 return;
812
813 tpm_smbios_measure();
814 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400815}
816
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500817static int
818tpm20_stirrandom(void)
819{
820 struct tpm2b_stir stir = {
821 .size = cpu_to_be16(sizeof(stir.stir)),
822 .stir = rdtscll(),
823 };
824 /* set more bits to stir with */
825 stir.stir += swab64(rdtscll());
826
827 int ret = tpm_build_and_send_cmd(0, TPM2_CC_StirRandom,
828 (u8 *)&stir, sizeof(stir),
829 TPM_DURATION_TYPE_SHORT);
830
831 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
832 ret);
833
834 return ret;
835}
836
837static int
838tpm20_getrandom(u8 *buf, u16 buf_len)
839{
840 struct tpm2_res_getrandom rsp;
841
842 if (buf_len > sizeof(rsp.rnd.buffer))
843 return -1;
844
845 struct tpm2_req_getrandom trgr = {
846 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
847 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
848 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
849 .bytesRequested = cpu_to_be16(buf_len),
850 };
851 u32 resp_length = sizeof(rsp);
852
853 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
854 TPM_DURATION_TYPE_MEDIUM);
855 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
856 ret = -1;
857 else
858 memcpy(buf, rsp.rnd.buffer, buf_len);
859
860 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
861 ret);
862
863 return ret;
864}
865
866static int
867tpm20_hierarchychangeauth(u8 auth[20])
868{
869 struct tpm2_req_hierarchychangeauth trhca = {
870 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
871 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
872 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
873 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
874 .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
875 .authblock = {
876 .handle = cpu_to_be32(TPM2_RS_PW),
877 .noncesize = cpu_to_be16(0),
878 .contsession = TPM2_YES,
879 .pwdsize = cpu_to_be16(0),
880 },
881 .newAuth = {
882 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
883 },
884 };
885 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
886
887 struct tpm_rsp_header rsp;
888 u32 resp_length = sizeof(rsp);
889 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
890 TPM_DURATION_TYPE_MEDIUM);
891 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
892 ret = -1;
893
894 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
895 ret);
896
897 return ret;
898}
899
900static void
901tpm20_prepboot(void)
902{
903 int ret = tpm20_stirrandom();
904 if (ret)
905 goto err_exit;
906
907 u8 auth[20];
908 ret = tpm20_getrandom(&auth[0], sizeof(auth));
909 if (ret)
910 goto err_exit;
911
912 ret = tpm20_hierarchychangeauth(auth);
913 if (ret)
914 goto err_exit;
915
916 return;
917
918err_exit:
919 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
920
921 tpm_set_failure();
922}
923
Kevin O'Connord6aca442015-06-10 11:00:17 -0400924void
925tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400926{
Stefan Berger8b902b82016-01-07 12:02:50 -0500927 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400928 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400929
Stefan Berger1d37d522016-02-02 13:09:11 -0500930 switch (TPM_version) {
931 case TPM_VERSION_1_2:
932 if (TPM_has_physical_presence)
933 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
934 PhysicalPresence_NOT_PRESENT_LOCK,
935 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
936 TPM_DURATION_TYPE_SHORT);
937 break;
938 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500939 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -0500940 break;
941 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400942
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500943 tpm_add_action(4, "Calling INT 19h");
944 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400945}
946
Stefan Berger5aa2a752015-03-23 14:22:17 -0400947/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500948 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400949 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500950void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500951tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400952{
Kevin O'Connord559a232015-11-28 08:35:26 -0500953 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500954 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500955
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500956 struct pcctes_romex pcctes = {
957 .eventid = 7,
958 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400959 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500960 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500961 tpm_add_measurement_to_log(2,
962 EV_EVENT_TAG,
963 (const char *)&pcctes, sizeof(pcctes),
964 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500965}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400966
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500967void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400968tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
969{
Kevin O'Connord559a232015-11-28 08:35:26 -0500970 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500971 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400972
Stefan Berger4cdbc412015-11-30 11:14:18 -0500973 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500974 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500975
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500976 const char *string = "Booting BCV device 00h (Floppy)";
977 if (bootdrv == 0x80)
978 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500979 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400980
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500981 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
982 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500983 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500984 tpm_add_measurement_to_log(4, EV_IPL,
985 string, strlen(string),
986 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500987
988 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
989 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500990 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
991 string, strlen(string),
992 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400993}
994
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500995void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400996tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
997{
Kevin O'Connord559a232015-11-28 08:35:26 -0500998 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500999 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001000
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001001 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001002
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001003 /* specs: see section 'El Torito' */
1004 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001005 tpm_add_measurement_to_log(4, EV_IPL,
1006 string, strlen(string),
1007 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001008}
1009
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001010void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001011tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1012{
Kevin O'Connord559a232015-11-28 08:35:26 -05001013 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001014 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001015
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001016 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001017
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001018 /* specs: see section 'El Torito' */
1019 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001020 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1021 string, strlen(string),
1022 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001023}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001024
Kevin O'Connord6aca442015-06-10 11:00:17 -04001025void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001026tpm_s3_resume(void)
1027{
Kevin O'Connord559a232015-11-28 08:35:26 -05001028 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001029 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001030
1031 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1032
Stefan Berger1d37d522016-02-02 13:09:11 -05001033 int ret = -1;
1034
1035 switch (TPM_version) {
1036 case TPM_VERSION_1_2:
1037 ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
1038 Startup_ST_STATE,
1039 sizeof(Startup_ST_STATE),
1040 TPM_DURATION_TYPE_SHORT);
1041 break;
1042 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001043 ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
1044 Startup_SU_STATE,
1045 sizeof(Startup_SU_STATE),
1046 TPM_DURATION_TYPE_SHORT);
1047
1048 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
1049 ret);
1050
1051 if (ret)
1052 goto err_exit;
1053
1054
1055 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
1056 TPM2_SelfTest_YES, sizeof(TPM2_SelfTest_YES),
1057 TPM_DURATION_TYPE_LONG);
1058
1059 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
1060 ret);
1061
Stefan Berger1d37d522016-02-02 13:09:11 -05001062 break;
1063 }
1064
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001065 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001066 goto err_exit;
1067
Kevin O'Connord6aca442015-06-10 11:00:17 -04001068 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001069
1070err_exit:
1071 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1072
Stefan Berger7fce1d92015-11-12 10:14:45 -05001073 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001074}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001075
1076
1077/****************************************************************
1078 * BIOS interface
1079 ****************************************************************/
1080
Kevin O'Connor59076132015-11-28 13:55:09 -05001081u8 TPM_interface_shutdown VARLOW;
1082
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001083static inline void *input_buf32(struct bregs *regs)
1084{
1085 return MAKE_FLATPTR(regs->es, regs->di);
1086}
1087
1088static inline void *output_buf32(struct bregs *regs)
1089{
1090 return MAKE_FLATPTR(regs->ds, regs->si);
1091}
1092
1093static u32
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001094hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
1095 , void *event, int extend)
1096{
1097 if (pcpes->pcrindex >= 24)
1098 return TCG_INVALID_INPUT_PARA;
1099 if (hashdata)
1100 sha1(hashdata, hashdata_length, pcpes->digest);
1101 if (extend) {
1102 int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
1103 if (ret)
1104 return TCG_TCG_COMMAND_ERROR;
1105 }
Kevin O'Connor93784032016-02-05 22:28:17 -05001106 struct tcg_pcr_event2_sha1 entry = {
1107 .pcrindex = pcpes->pcrindex,
1108 .eventtype = pcpes->eventtype,
1109 .eventdatasize = pcpes->eventdatasize,
1110 .count = 1,
1111 .digests[0].hashtype = TPM2_ALG_SHA1,
1112 };
1113 memcpy(entry.digests[0].sha1, pcpes->digest, sizeof(entry.digests[0].sha1));
1114 int ret = tpm_log_event(&entry, pcpes->event, TPM_version);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001115 if (ret)
1116 return TCG_PC_LOGOVERFLOW;
1117 return 0;
1118}
1119
1120static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001121hash_log_extend_event_int(const struct hleei_short *hleei_s,
1122 struct hleeo *hleeo)
1123{
1124 u32 rc = 0;
1125 struct hleo hleo;
1126 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1127 const void *logdataptr;
1128 u32 logdatalen;
1129 struct pcpes *pcpes;
1130 u32 pcrindex;
1131
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001132 /* short or long version? */
1133 switch (hleei_s->ipblength) {
1134 case sizeof(struct hleei_short):
1135 /* short */
1136 logdataptr = hleei_s->logdataptr;
1137 logdatalen = hleei_s->logdatalen;
1138 pcrindex = hleei_s->pcrindex;
1139 break;
1140
1141 case sizeof(struct hleei_long):
1142 /* long */
1143 logdataptr = hleei_l->logdataptr;
1144 logdatalen = hleei_l->logdatalen;
1145 pcrindex = hleei_l->pcrindex;
1146 break;
1147
1148 default:
1149 /* bad input block */
1150 rc = TCG_INVALID_INPUT_PARA;
1151 goto err_exit;
1152 }
1153
1154 pcpes = (struct pcpes *)logdataptr;
1155
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001156 if (pcpes->pcrindex != pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001157 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001158 rc = TCG_INVALID_INPUT_PARA;
1159 goto err_exit;
1160 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001161 rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
1162 , pcpes->event, 1);
1163 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001164 goto err_exit;
1165
1166 hleeo->opblength = sizeof(struct hleeo);
1167 hleeo->reserved = 0;
1168 hleeo->eventnumber = hleo.eventnumber;
Stefan Berger2b237502016-01-07 12:02:46 -05001169 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001170
1171err_exit:
1172 if (rc != 0) {
1173 hleeo->opblength = 4;
1174 hleeo->reserved = 0;
1175 }
1176
1177 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001178}
1179
1180static u32
1181pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1182{
1183 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001184 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001185
Stefan Berger7092de32016-02-02 13:09:19 -05001186 if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001187 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1188 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001189 rc = TCG_INVALID_INPUT_PARA;
1190 goto err_exit;
1191 }
1192
Stefan Berger7092de32016-02-02 13:09:19 -05001193 u16 tag = be16_to_cpu(trh->tag);
1194
1195 switch (TPM_version) {
1196 case TPM_VERSION_1_2:
1197 if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
1198 && tag != TPM_TAG_RQU_AUTH2_CMD) {
1199 rc = TCG_INVALID_INPUT_PARA;
1200 goto err_exit;
1201 }
1202 break;
1203 case TPM_VERSION_2:
1204 if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
1205 rc = TCG_INVALID_INPUT_PARA;
1206 goto err_exit;
1207 }
1208 }
1209
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001210 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001211 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1212 TPM_DURATION_TYPE_LONG /* worst case */);
1213 if (ret) {
1214 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001215 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001216 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001217
1218 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1219 pttto->reserved = 0;
1220
1221err_exit:
1222 if (rc != 0) {
1223 pttto->opblength = 4;
1224 pttto->reserved = 0;
1225 }
1226
1227 return rc;
1228}
1229
1230static u32
1231shutdown_preboot_interface(void)
1232{
Kevin O'Connor59076132015-11-28 13:55:09 -05001233 TPM_interface_shutdown = 1;
1234 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001235}
1236
1237static u32
1238hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1239{
1240 u32 rc = 0;
1241 u16 size;
1242 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001243
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001244 size = hlei->ipblength;
1245 if (size != sizeof(*hlei)) {
1246 rc = TCG_INVALID_INPUT_PARA;
1247 goto err_exit;
1248 }
1249
1250 pcpes = (struct pcpes *)hlei->logdataptr;
1251
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001252 if (pcpes->pcrindex != hlei->pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001253 || pcpes->eventtype != hlei->logeventtype
1254 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001255 rc = TCG_INVALID_INPUT_PARA;
1256 goto err_exit;
1257 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001258 rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
1259 , pcpes->event, 0);
1260 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001261 goto err_exit;
1262
1263 /* updating the log was fine */
1264 hleo->opblength = sizeof(struct hleo);
1265 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001266 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001267
1268err_exit:
1269 if (rc != 0) {
1270 hleo->opblength = 2;
1271 hleo->reserved = 0;
1272 }
1273
1274 return rc;
1275}
1276
1277static u32
1278hash_all_int(const struct hai *hai, u8 *hash)
1279{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001280 if (hai->ipblength != sizeof(struct hai) ||
1281 hai->hashdataptr == 0 ||
1282 hai->hashdatalen == 0 ||
1283 hai->algorithmid != TPM_ALG_SHA)
1284 return TCG_INVALID_INPUT_PARA;
1285
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001286 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1287 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001288}
1289
1290static u32
1291tss_int(struct ti *ti, struct to *to)
1292{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001293 to->opblength = sizeof(struct to);
1294 to->reserved = 0;
1295
Kevin O'Connor59076132015-11-28 13:55:09 -05001296 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001297}
1298
1299static u32
1300compact_hash_log_extend_event_int(u8 *buffer,
1301 u32 info,
1302 u32 length,
1303 u32 pcrindex,
1304 u32 *edx_ptr)
1305{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001306 struct pcpes pcpes = {
1307 .pcrindex = pcrindex,
1308 .eventtype = EV_COMPACT_HASH,
1309 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001310 };
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001311 u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
1312 if (rc)
1313 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001314
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001315 *edx_ptr = tpm_state.entry_count;
1316 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001317}
1318
1319void VISIBLE32FLAT
1320tpm_interrupt_handler32(struct bregs *regs)
1321{
1322 if (!CONFIG_TCGBIOS)
1323 return;
1324
1325 set_cf(regs, 0);
1326
Kevin O'Connor59076132015-11-28 13:55:09 -05001327 if (TPM_interface_shutdown && regs->al) {
1328 regs->eax = TCG_INTERFACE_SHUTDOWN;
1329 return;
1330 }
1331
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001332 switch ((enum irq_ids)regs->al) {
1333 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001334 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001335 /* no TPM available */
1336 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1337 } else {
1338 regs->eax = 0;
1339 regs->ebx = TCG_MAGIC;
1340 regs->ch = TCG_VERSION_MAJOR;
1341 regs->cl = TCG_VERSION_MINOR;
1342 regs->edx = 0x0;
1343 regs->esi = (u32)tpm_state.log_area_start_address;
1344 regs->edi = (u32)tpm_state.log_area_last_entry;
1345 }
1346 break;
1347
1348 case TCG_HashLogExtendEvent:
1349 regs->eax =
1350 hash_log_extend_event_int(
1351 (struct hleei_short *)input_buf32(regs),
1352 (struct hleeo *)output_buf32(regs));
1353 break;
1354
1355 case TCG_PassThroughToTPM:
1356 regs->eax =
1357 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1358 (struct pttto *)output_buf32(regs));
1359 break;
1360
1361 case TCG_ShutdownPreBootInterface:
1362 regs->eax = shutdown_preboot_interface();
1363 break;
1364
1365 case TCG_HashLogEvent:
1366 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1367 (struct hleo*)output_buf32(regs));
1368 break;
1369
1370 case TCG_HashAll:
1371 regs->eax =
1372 hash_all_int((struct hai*)input_buf32(regs),
1373 (u8 *)output_buf32(regs));
1374 break;
1375
1376 case TCG_TSS:
1377 regs->eax = tss_int((struct ti*)input_buf32(regs),
1378 (struct to*)output_buf32(regs));
1379 break;
1380
1381 case TCG_CompactHashLogExtendEvent:
1382 regs->eax =
1383 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1384 regs->esi,
1385 regs->ecx,
1386 regs->edx,
1387 &regs->edx);
1388 break;
1389
1390 default:
1391 set_cf(regs, 1);
1392 }
1393
1394 return;
1395}
Stefan Berger320df852015-11-30 11:14:19 -05001396
Kevin O'Connor26e36172015-12-29 12:20:23 -05001397
1398/****************************************************************
1399 * TPM Configuration Menu
1400 ****************************************************************/
1401
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001402static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001403tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001404{
Stefan Berger320df852015-11-30 11:14:19 -05001405 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001406 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1407 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001408 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001409 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001410
1411 *has_owner = oauth.flag;
1412
1413 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001414}
1415
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001416static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001417tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001418{
Stefan Berger320df852015-11-30 11:14:19 -05001419 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001420 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001421 if (ret)
1422 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001423
1424 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1425 return 0;
1426
Stefan Berger1d37d522016-02-02 13:09:11 -05001427 ret = tpm_build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1428 : TPM_ORD_PhysicalDisable,
1429 NULL, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001430 if (ret) {
1431 if (enable)
1432 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1433 else
1434 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1435 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001436 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001437}
1438
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001439static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001440tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001441{
Stefan Berger320df852015-11-30 11:14:19 -05001442 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001443 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001444 if (ret)
1445 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001446
1447 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1448 return 0;
1449
1450 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1451 return 0;
1452
Stefan Berger1d37d522016-02-02 13:09:11 -05001453 ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1454 activate ? CommandFlag_FALSE
1455 : CommandFlag_TRUE,
1456 activate ? sizeof(CommandFlag_FALSE)
1457 : sizeof(CommandFlag_TRUE),
1458 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001459 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001460 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001461
1462 if (activate && allow_reset) {
1463 if (verbose) {
1464 printf("Requiring a reboot to activate the TPM.\n");
1465
1466 msleep(2000);
1467 }
1468 reset();
1469 }
1470
1471 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001472}
1473
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001474static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001475tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001476{
Stefan Berger1d37d522016-02-02 13:09:11 -05001477 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001478 if (ret)
1479 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001480
Stefan Berger1d37d522016-02-02 13:09:11 -05001481 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001482}
1483
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001484static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001485tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1486 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001487{
Stefan Berger320df852015-11-30 11:14:19 -05001488 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001489 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001490 if (ret)
1491 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001492 if (!has_owner) {
1493 if (verbose)
1494 printf("TPM does not have an owner.\n");
1495 return 0;
1496 }
1497
1498 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001499 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001500 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001501 dprintf(DEBUG_tcg,
1502 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001503 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001504 }
1505 }
1506
Stefan Berger1d37d522016-02-02 13:09:11 -05001507 ret = tpm_build_and_send_cmd(0, TPM_ORD_ForceClear,
1508 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001509 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001510 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001511
1512 if (!enable_activate_after) {
1513 if (verbose)
1514 printf("Owner successfully cleared.\n"
1515 "You will need to enable/activate the TPM again.\n\n");
1516 return 0;
1517 }
1518
Stefan Berger1d37d522016-02-02 13:09:11 -05001519 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001520}
1521
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001522static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001523tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001524{
Stefan Berger320df852015-11-30 11:14:19 -05001525 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001526 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001527 if (ret)
1528 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001529 if (has_owner) {
1530 if (verbose)
1531 printf("Must first remove owner.\n");
1532 return 0;
1533 }
1534
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001535 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001536 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001537 if (ret)
1538 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001539
1540 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1541 if (verbose)
1542 printf("TPM must first be enable.\n");
1543 return 0;
1544 }
1545
Stefan Berger1d37d522016-02-02 13:09:11 -05001546 ret = tpm_build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1547 (allow) ? CommandFlag_TRUE
1548 : CommandFlag_FALSE,
1549 sizeof(CommandFlag_TRUE),
1550 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001551 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001552 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001553
1554 if (verbose)
1555 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1556
1557 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001558}
1559
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001560static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001561tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001562{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001563 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001564
1565 switch (msgCode) {
1566 case TPM_PPI_OP_NOOP: /* no-op */
1567 break;
1568
1569 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001570 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001571 break;
1572
1573 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001574 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001575 break;
1576
1577 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001578 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001579 break;
1580
1581 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001582 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001583 break;
1584
1585 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001586 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001587 break;
1588
1589 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001590 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001591 break;
1592
1593 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001594 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001595 break;
1596
1597 default:
1598 break;
1599 }
1600
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001601 if (ret)
1602 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001603
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001604 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001605}
1606
1607static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001608tpm20_clearcontrol(u8 disable, int verbose)
1609{
1610 struct tpm2_req_clearcontrol trc = {
1611 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1612 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1613 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1614 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1615 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1616 .authblock = {
1617 .handle = cpu_to_be32(TPM2_RS_PW),
1618 .noncesize = cpu_to_be16(0),
1619 .contsession = TPM2_YES,
1620 .pwdsize = cpu_to_be16(0),
1621 },
1622 .disable = disable,
1623 };
1624 struct tpm_rsp_header rsp;
1625 u32 resp_length = sizeof(rsp);
1626 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1627 TPM_DURATION_TYPE_SHORT);
1628 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1629 ret = -1;
1630
1631 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1632 ret);
1633
1634 return ret;
1635}
1636
1637static int
1638tpm20_clear(void)
1639{
1640 struct tpm2_req_clear trq = {
1641 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1642 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1643 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1644 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1645 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1646 .authblock = {
1647 .handle = cpu_to_be32(TPM2_RS_PW),
1648 .noncesize = cpu_to_be16(0),
1649 .contsession = TPM2_YES,
1650 .pwdsize = cpu_to_be16(0),
1651 },
1652 };
1653 struct tpm_rsp_header rsp;
1654 u32 resp_length = sizeof(rsp);
1655 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1656 TPM_DURATION_TYPE_MEDIUM);
1657 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1658 ret = -1;
1659
1660 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1661 ret);
1662
1663 return ret;
1664}
1665
1666static int
1667tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1668{
1669 int ret = 0;
1670
1671 switch (msgCode) {
1672 case TPM_PPI_OP_NOOP: /* no-op */
1673 break;
1674
1675 case TPM_PPI_OP_CLEAR:
1676 ret = tpm20_clearcontrol(0, verbose);
1677 if (!ret)
1678 ret = tpm20_clear();
1679 break;
1680 }
1681
1682 if (ret)
1683 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
1684
1685 return ret;
1686}
1687
1688static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001689tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05001690{
1691 int state = 0;
1692 struct tpm_permanent_flags pf;
1693 int has_owner;
1694
Stefan Berger1d37d522016-02-02 13:09:11 -05001695 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
1696 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05001697 return ~0;
1698
1699 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1700 state |= TPM_STATE_ENABLED;
1701
1702 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1703 state |= TPM_STATE_ACTIVE;
1704
1705 if (has_owner) {
1706 state |= TPM_STATE_OWNED;
1707 } else {
1708 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1709 state |= TPM_STATE_OWNERINSTALL;
1710 }
1711
1712 return state;
1713}
1714
1715static void
Stefan Berger1d37d522016-02-02 13:09:11 -05001716tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05001717{
1718 int i = 0;
1719
1720 printf("\nThe current state of the TPM is:\n");
1721
1722 if (state & TPM_STATE_ENABLED)
1723 printf(" Enabled");
1724 else
1725 printf(" Disabled");
1726
1727 if (state & TPM_STATE_ACTIVE)
1728 printf(" and active\n");
1729 else
1730 printf(" and deactivated\n");
1731
1732 if (state & TPM_STATE_OWNED)
1733 printf(" Ownership has been taken\n");
1734 else {
1735 printf(" Ownership has not been taken\n");
1736 if (state & TPM_STATE_OWNERINSTALL)
1737 printf(" A user can take ownership of the TPM\n");
1738 else
1739 printf(" Taking ownership of the TPM has been disabled\n");
1740 }
1741
1742 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1743 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1744 printf("\nNote: To make use of all functionality, the TPM must be "
1745 "enabled and active.\n");
1746 }
1747
1748 printf("\nAvailable options are:\n");
1749 if (state & TPM_STATE_ENABLED) {
1750 printf(" d. Disable the TPM\n");
1751 next_scancodes[i++] = 32;
1752
1753 if (state & TPM_STATE_ACTIVE) {
1754 printf(" v. Deactivate the TPM\n");
1755 next_scancodes[i++] = 47;
1756
1757 if (state & TPM_STATE_OWNERINSTALL) {
1758 printf(" p. Prevent installation of an owner\n");
1759 next_scancodes[i++] = 25;
1760 } else {
1761 printf(" s. Allow installation of an owner\n");
1762 next_scancodes[i++] = 31;
1763 }
1764 } else {
1765 printf(" a. Activate the TPM\n");
1766 next_scancodes[i++] = 30;
1767 }
1768
1769 } else {
1770 printf(" e. Enable the TPM\n");
1771 next_scancodes[i++] = 18;
1772 }
1773
1774 if (state & TPM_STATE_OWNED) {
1775 printf(" c. Clear ownership\n");
1776 next_scancodes[i++] = 46;
1777 }
1778
1779 next_scancodes[i++] = 0;
1780}
1781
Stefan Berger1d37d522016-02-02 13:09:11 -05001782static void
1783tpm12_menu(void)
Stefan Berger320df852015-11-30 11:14:19 -05001784{
Stefan Berger320df852015-11-30 11:14:19 -05001785 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001786 tpm_ppi_code msgCode;
1787 int state = 0, i;
1788 int waitkey;
1789
Stefan Berger320df852015-11-30 11:14:19 -05001790 printf("The Trusted Platform Module (TPM) is a hardware device in "
1791 "this machine.\n"
1792 "It can help verify the integrity of system software.\n\n");
1793
1794 for (;;) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001795 if ((state = tpm12_get_tpm_state()) != ~0) {
1796 tpm12_show_tpm_menu(state, next_scancodes);
Stefan Berger320df852015-11-30 11:14:19 -05001797 } else {
1798 printf("TPM is not working correctly.\n");
1799 return;
1800 }
1801
1802 printf("\nIf no change is desired or if this menu was reached by "
1803 "mistake, press ESC to\n"
1804 "reboot the machine.\n");
1805
1806 msgCode = TPM_PPI_OP_NOOP;
1807
1808 waitkey = 1;
1809
1810 while (waitkey) {
1811 while ((scancode = get_keystroke(1000)) == ~0)
1812 ;
1813
1814 switch (scancode) {
1815 case 1:
1816 // ESC
1817 reset();
1818 break;
1819 case 18: /* e. enable */
1820 msgCode = TPM_PPI_OP_ENABLE;
1821 break;
1822 case 32: /* d. disable */
1823 msgCode = TPM_PPI_OP_DISABLE;
1824 break;
1825 case 30: /* a. activate */
1826 msgCode = TPM_PPI_OP_ACTIVATE;
1827 break;
1828 case 47: /* v. deactivate */
1829 msgCode = TPM_PPI_OP_DEACTIVATE;
1830 break;
1831 case 46: /* c. clear owner */
1832 msgCode = TPM_PPI_OP_CLEAR;
1833 break;
1834 case 25: /* p. prevent ownerinstall */
1835 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1836 break;
1837 case 31: /* s. allow ownerinstall */
1838 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1839 break;
1840 default:
1841 continue;
1842 }
1843
1844 /*
1845 * Using the next_scancodes array, check whether the
1846 * pressed key is currently a valid option.
1847 */
1848 for (i = 0; i < sizeof(next_scancodes); i++) {
1849 if (next_scancodes[i] == 0)
1850 break;
1851
1852 if (next_scancodes[i] == scancode) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001853 tpm12_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001854 waitkey = 0;
1855 break;
1856 }
1857 }
1858 }
1859 }
1860}
Stefan Berger1d37d522016-02-02 13:09:11 -05001861
Stefan Berger7d596dc2016-02-02 13:09:16 -05001862static void
1863tpm20_menu(void)
1864{
1865 int scan_code;
1866 tpm_ppi_code msgCode;
1867
1868 for (;;) {
1869 printf("1. Clear TPM\n");
1870
1871 printf("\nIf no change is desired or if this menu was reached by "
1872 "mistake, press ESC to\n"
1873 "reboot the machine.\n");
1874
1875 msgCode = TPM_PPI_OP_NOOP;
1876
1877 while ((scan_code = get_keystroke(1000)) == ~0)
1878 ;
1879
1880 switch (scan_code) {
1881 case 1:
1882 // ESC
1883 reset();
1884 break;
1885 case 2:
1886 msgCode = TPM_PPI_OP_CLEAR;
1887 break;
1888 default:
1889 continue;
1890 }
1891
1892 tpm20_process_cfg(msgCode, 0);
1893 }
1894}
1895
Stefan Berger1d37d522016-02-02 13:09:11 -05001896void
1897tpm_menu(void)
1898{
1899 if (!CONFIG_TCGBIOS)
1900 return;
1901
1902 while (get_keystroke(0) >= 0)
1903 ;
1904 wait_threads();
1905
1906 switch (TPM_version) {
1907 case TPM_VERSION_1_2:
1908 tpm12_menu();
1909 break;
1910 case TPM_VERSION_2:
Stefan Berger7d596dc2016-02-02 13:09:16 -05001911 tpm20_menu();
Stefan Berger1d37d522016-02-02 13:09:11 -05001912 break;
1913 }
1914}