blob: 40b30281909f471cdea6c9a80fc9089ac7966a5b [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
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050030/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050031 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050032 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040033
Kevin O'Connor27065322015-11-28 14:25:41 -050034struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050035 /* length of the TCPA log buffer */
36 u32 log_area_minimum_length;
37
38 /* start address of TCPA log buffer */
39 u8 * log_area_start_address;
40
41 /* number of log entries written */
42 u32 entry_count;
43
44 /* address to write next log entry to */
45 u8 * log_area_next_entry;
46
47 /* address of last entry written (need for TCG_StatusCheck) */
48 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050049} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050050
Stefan Bergerdf46d102017-11-14 15:03:47 -050051static int tpm_set_log_area(u8 *log_area_start_address,
52 u32 log_area_minimum_length)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050053{
Kevin O'Connor27065322015-11-28 14:25:41 -050054 if (!log_area_start_address || !log_area_minimum_length)
55 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050056
Kevin O'Connor27065322015-11-28 14:25:41 -050057 memset(log_area_start_address, 0, log_area_minimum_length);
58 tpm_state.log_area_start_address = log_area_start_address;
59 tpm_state.log_area_minimum_length = log_area_minimum_length;
60 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050061 tpm_state.log_area_last_entry = NULL;
62 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -050063 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050064}
65
Stefan Bergerdf46d102017-11-14 15:03:47 -050066static int
67tpm_tcpa_probe(void)
68{
69 struct tcpa_descriptor_rev2 *tcpa = find_acpi_table(TCPA_SIGNATURE);
70 if (!tcpa)
71 return -1;
72
73 dprintf(DEBUG_tcg, "TCGBIOS: TCPA: LASA = %p, LAML = %u\n",
74 (u8 *)(long)tcpa->log_area_start_address,
75 tcpa->log_area_minimum_length);
76
77 return tpm_set_log_area((u8*)(long)tcpa->log_area_start_address,
78 tcpa->log_area_minimum_length);
79}
80
81static int
82tpm_tpm2_probe(void)
83{
84 struct tpm2_descriptor_rev2 *tpm2 = find_acpi_table(TPM2_SIGNATURE);
85 if (!tpm2)
86 return -1;
87
88 if (tpm2->length < 76)
89 return -1;
90
91 dprintf(DEBUG_tcg, "TCGBIOS: TPM2: LASA = %p, LAML = %u\n",
92 (u8 *)(long)tpm2->log_area_start_address,
93 tpm2->log_area_minimum_length);
94
95 return tpm_set_log_area((u8*)(long)tpm2->log_area_start_address,
96 tpm2->log_area_minimum_length);
97}
98
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050099/*
100 * Extend the ACPI log with the given entry by copying the
101 * entry data into the log.
102 * Input
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400103 * entry : The header data to use (including the variable length digest)
104 * digest_len : Length of the digest in 'entry'
105 * event : Pointer to the event body to be copied into the log
106 * event_len : Length of 'event'
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500107 *
108 * Output:
109 * Returns an error code in case of faiure, 0 in case of success
110 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500111static int
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400112tpm_log_event(struct tpm_log_header *entry, int digest_len
113 , const void *event, int event_len)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500114{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500115 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
116 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
117
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500118 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500119 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500120
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400121 u32 size = (sizeof(*entry) + digest_len
122 + sizeof(struct tpm_log_trailer) + event_len);
Kevin O'Connor93784032016-02-05 22:28:17 -0500123 u32 logsize = (tpm_state.log_area_next_entry + size
124 - tpm_state.log_area_start_address);
125 if (logsize > tpm_state.log_area_minimum_length) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500126 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500127 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500128 }
129
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400130 void *dest = tpm_state.log_area_next_entry;
131 memcpy(dest, entry, sizeof(*entry) + digest_len);
132 struct tpm_log_trailer *t = dest + sizeof(*entry) + digest_len;
133 t->eventdatasize = event_len;
134 memcpy(t->event, event, event_len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500135
136 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
137 tpm_state.log_area_next_entry += size;
138 tpm_state.entry_count++;
139
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500140 return 0;
141}
142
143
144/****************************************************************
Kevin O'Connor01669932016-08-10 16:15:43 -0400145 * Digest formatting
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500146 ****************************************************************/
147
Kevin O'Connor01669932016-08-10 16:15:43 -0400148static TPMVersion TPM_version;
149static u32 tpm20_pcr_selection_size;
150static struct tpml_pcr_selection *tpm20_pcr_selection;
Stefan Berger115d0082016-01-07 12:02:49 -0500151
Stefan Bergera99de5c2016-08-05 11:07:11 -0400152// A 'struct tpm_log_entry' is a local data structure containing a
153// 'tpm_log_header' followed by space for the maximum supported
154// digest. (The digest is a sha1 hash on tpm1.2 or a series of
155// tpm2_digest_value structs on tpm2.0)
156struct tpm_log_entry {
157 struct tpm_log_header hdr;
158 u8 pad[sizeof(struct tpm2_digest_values)
159 + 5 * sizeof(struct tpm2_digest_value)
160 + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE
161 + SHA512_BUFSIZE + SM3_256_BUFSIZE];
162} PACKED;
163
164static int
165tpm20_get_hash_buffersize(u16 hashAlg)
166{
167 switch (hashAlg) {
168 case TPM2_ALG_SHA1:
169 return SHA1_BUFSIZE;
170 case TPM2_ALG_SHA256:
171 return SHA256_BUFSIZE;
172 case TPM2_ALG_SHA384:
173 return SHA384_BUFSIZE;
174 case TPM2_ALG_SHA512:
175 return SHA512_BUFSIZE;
176 case TPM2_ALG_SM3_256:
177 return SM3_256_BUFSIZE;
178 default:
179 return -1;
180 }
181}
182
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400183// Add an entry at the start of the log describing digest formats
184static int
185tpm20_write_EfiSpecIdEventStruct(void)
186{
187 if (!tpm20_pcr_selection)
188 return -1;
189
190 struct {
191 struct TCG_EfiSpecIdEventStruct hdr;
192 u8 pad[256];
193 } event = {
194 .hdr.signature = "Spec ID Event03",
195 .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
196 .hdr.specVersionMinor = 0,
197 .hdr.specVersionMajor = 2,
198 .hdr.specErrata = 0,
199 .hdr.uintnSize = 2,
200 };
201
202 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
203 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
204
205 u32 count;
206 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
207 u8 sizeOfSelect = sel->sizeOfSelect;
208
209 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
210 if (nsel > end)
211 break;
212
213 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
214 if (hsize < 0) {
215 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
216 be16_to_cpu(sel->hashAlg));
217 return -1;
218 }
219
220 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
221 , digestSizes[count+1]);
222 if (event_size > sizeof(event) - sizeof(u32)) {
223 dprintf(DEBUG_tcg, "EfiSpecIdEventStruct pad too small\n");
224 return -1;
225 }
226
227 event.hdr.digestSizes[count].algorithmId = be16_to_cpu(sel->hashAlg);
228 event.hdr.digestSizes[count].digestSize = hsize;
229
230 sel = nsel;
231 }
232
233 if (sel != end) {
234 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
235 return -1;
236 }
237
238 event.hdr.numberOfAlgorithms = count;
239 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
240 , digestSizes[count]);
241 u32 *vendorInfoSize = (void*)&event + event_size;
242 *vendorInfoSize = 0;
243 event_size += sizeof(*vendorInfoSize);
244
245 struct tpm_log_entry le = {
246 .hdr.eventtype = EV_NO_ACTION,
247 };
248 return tpm_log_event(&le.hdr, SHA1_BUFSIZE, &event, event_size);
249}
250
Stefan Bergera99de5c2016-08-05 11:07:11 -0400251/*
252 * Build the TPM2 tpm2_digest_values data structure from the given hash.
253 * Follow the PCR bank configuration of the TPM and write the same hash
254 * in either truncated or zero-padded form in the areas of all the other
255 * hashes. For example, write the sha1 hash in the area of the sha256
256 * hash and fill the remaining bytes with zeros. Or truncate the sha256
257 * hash when writing it in the area of the sha1 hash.
258 *
259 * le: the log entry to build the digest in
260 * sha1: the sha1 hash value to use
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500261 * bigEndian: whether to build in big endian format for the TPM or
262 * little endian for the log
Stefan Bergera99de5c2016-08-05 11:07:11 -0400263 *
264 * Returns the digest size; -1 on fatal error
265 */
266static int
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500267tpm20_build_digest(struct tpm_log_entry *le, const u8 *sha1, int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400268{
269 if (!tpm20_pcr_selection)
270 return -1;
271
272 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
273 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
274 void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values);
275
276 u32 count;
277 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
278 u8 sizeOfSelect = sel->sizeOfSelect;
279
280 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
281 if (nsel > end)
282 break;
283
284 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
285 if (hsize < 0) {
286 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
287 be16_to_cpu(sel->hashAlg));
288 return -1;
289 }
290
291 /* buffer size sanity check before writing */
292 struct tpm2_digest_value *v = dest;
293 if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) {
294 dprintf(DEBUG_tcg, "tpm_log_entry is too small\n");
295 return -1;
296 }
297
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500298 if (bigEndian)
299 v->hashAlg = sel->hashAlg;
300 else
301 v->hashAlg = be16_to_cpu(sel->hashAlg);
302
Stefan Bergera99de5c2016-08-05 11:07:11 -0400303 memset(v->hash, 0, hsize);
304 memcpy(v->hash, sha1, hsize > SHA1_BUFSIZE ? SHA1_BUFSIZE : hsize);
305
306 dest += sizeof(*v) + hsize;
307 sel = nsel;
308 }
309
310 if (sel != end) {
311 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
312 return -1;
313 }
314
315 struct tpm2_digest_values *v = (void*)le->hdr.digest;
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500316 if (bigEndian)
317 v->count = cpu_to_be32(count);
318 else
319 v->count = count;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400320
321 return dest - (void*)le->hdr.digest;
322}
323
324static int
325tpm12_build_digest(struct tpm_log_entry *le, const u8 *sha1)
326{
327 // On TPM 1.2 the digest contains just the SHA1 hash
328 memcpy(le->hdr.digest, sha1, SHA1_BUFSIZE);
329 return SHA1_BUFSIZE;
330}
331
332static int
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500333tpm_build_digest(struct tpm_log_entry *le, const u8 *sha1, int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400334{
335 switch (TPM_version) {
336 case TPM_VERSION_1_2:
337 return tpm12_build_digest(le, sha1);
338 case TPM_VERSION_2:
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500339 return tpm20_build_digest(le, sha1, bigEndian);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400340 }
341 return -1;
342}
343
Kevin O'Connor01669932016-08-10 16:15:43 -0400344
345/****************************************************************
346 * TPM hardware command wrappers
347 ****************************************************************/
348
Kevin O'Connor846fd312016-08-10 18:15:13 -0400349// Helper function for sending tpm commands that take a single
350// optional parameter (0, 1, or 2 bytes) and have no special response.
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500351static int
Kevin O'Connor846fd312016-08-10 18:15:13 -0400352tpm_simple_cmd(u8 locty, u32 ordinal
353 , int param_size, u16 param, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400354{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500355 struct {
356 struct tpm_req_header trqh;
Kevin O'Connor846fd312016-08-10 18:15:13 -0400357 u16 param;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500358 } PACKED req = {
Kevin O'Connor846fd312016-08-10 18:15:13 -0400359 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500360 .trqh.ordinal = cpu_to_be32(ordinal),
Kevin O'Connor846fd312016-08-10 18:15:13 -0400361 .param = param_size == 2 ? cpu_to_be16(param) : param,
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500362 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500363 switch (TPM_version) {
364 case TPM_VERSION_1_2:
365 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
366 break;
367 case TPM_VERSION_2:
368 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
369 break;
370 }
371
Stefan Bergerece25612015-11-12 10:14:46 -0500372 u8 obuffer[64];
Kevin O'Connor846fd312016-08-10 18:15:13 -0400373 struct tpm_rsp_header *trsh = (void*)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400374 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400375 memset(obuffer, 0x0, sizeof(obuffer));
376
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500377 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
378 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connor846fd312016-08-10 18:15:13 -0400379 dprintf(DEBUG_tcg, "Return from tpm_simple_cmd(%x, %x) = %x\n",
380 ordinal, param, ret);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500381 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400382}
383
Stefan Bergere444dce2016-02-02 13:09:17 -0500384static int
Stefan Berger74544fa2016-08-05 11:07:08 -0400385tpm20_getcapability(u32 capability, u32 property, u32 count,
386 struct tpm_rsp_header *rsp, u32 rsize)
387{
388 struct tpm2_req_getcapability trg = {
389 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
390 .hdr.totlen = cpu_to_be32(sizeof(trg)),
391 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
392 .capability = cpu_to_be32(capability),
393 .property = cpu_to_be32(property),
394 .propertycount = cpu_to_be32(count),
395 };
396
397 u32 resp_size = rsize;
398 int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
399 TPM_DURATION_TYPE_SHORT);
400 ret = (ret ||
401 rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
402
403 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
404 ret);
405
406 return ret;
407}
408
409static int
410tpm20_get_pcrbanks(void)
411{
412 u8 buffer[128];
413 struct tpm2_res_getcapability *trg =
414 (struct tpm2_res_getcapability *)&buffer;
415
416 int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
417 sizeof(buffer));
418 if (ret)
419 return ret;
420
421 u32 size = be32_to_cpu(trg->hdr.totlen) -
422 offsetof(struct tpm2_res_getcapability, data);
423 tpm20_pcr_selection = malloc_high(size);
424 if (tpm20_pcr_selection) {
425 memcpy(tpm20_pcr_selection, &trg->data, size);
426 tpm20_pcr_selection_size = size;
427 } else {
428 warn_noalloc();
429 ret = -1;
430 }
431
432 return ret;
433}
434
435static int
Kevin O'Connor01669932016-08-10 16:15:43 -0400436tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
437{
438 struct tpm_req_getcap trgc = {
439 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
440 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
441 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
442 .capArea = cpu_to_be32(cap),
443 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
444 .subCap = cpu_to_be32(subcap)
445 };
446 u32 resp_size = rsize;
447 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
448 TPM_DURATION_TYPE_SHORT);
449 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
450 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
451 " = %x\n", cap, subcap, ret);
452 return ret;
453}
454
455static int
456tpm12_read_permanent_flags(char *buf, int buf_len)
457{
458 memset(buf, 0, buf_len);
459
460 struct tpm_res_getcap_perm_flags pf;
461 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
462 , &pf.hdr, sizeof(pf));
463 if (ret)
464 return -1;
465
466 memcpy(buf, &pf.perm_flags, buf_len);
467
468 return 0;
469}
470
471static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500472tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400473{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400474 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500475 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
476 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500477 if (ret)
478 return ret;
479
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400480 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500481 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
482 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500483 if (ret)
484 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400485
Kevin O'Connorca606362015-12-29 14:21:29 -0500486 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400487 for (i = 0; i < 3; i++)
488 durations.durations[i] = be32_to_cpu(durations.durations[i]);
489
490 for (i = 0; i < 4; i++)
491 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
492
493 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
494 timeouts.timeouts[0],
495 timeouts.timeouts[1],
496 timeouts.timeouts[2],
497 timeouts.timeouts[3]);
498
499 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
500 durations.durations[0],
501 durations.durations[1],
502 durations.durations[2]);
503
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500504 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400505
506 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400507}
508
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500509static void
510tpm20_set_timeouts(void)
511{
512 u32 durations[3] = {
513 TPM2_DEFAULT_DURATION_SHORT,
514 TPM2_DEFAULT_DURATION_MEDIUM,
515 TPM2_DEFAULT_DURATION_LONG,
516 };
517 u32 timeouts[4] = {
518 TIS2_DEFAULT_TIMEOUT_A,
519 TIS2_DEFAULT_TIMEOUT_B,
520 TIS2_DEFAULT_TIMEOUT_C,
521 TIS2_DEFAULT_TIMEOUT_D,
522 };
523
524 tpmhw_set_timeouts(timeouts, durations);
525}
526
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500527static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400528tpm12_extend(struct tpm_log_entry *le, int digest_len)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500529{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500530 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500531 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
532 .hdr.totlen = cpu_to_be32(sizeof(tre)),
533 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400534 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500535 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400536 memcpy(tre.digest, le->hdr.digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500537
538 struct tpm_rsp_extend rsp;
539 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500540 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
541 TPM_DURATION_TYPE_SHORT);
542 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500543 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500544
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500545 return 0;
546}
547
Stefan Bergera99de5c2016-08-05 11:07:11 -0400548static int tpm20_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500549{
Stefan Berger0fb23c32016-08-05 11:07:09 -0400550 struct tpm2_req_extend tmp_tre = {
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500551 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400552 .hdr.totlen = cpu_to_be32(0),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500553 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400554 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Stefan Berger0fb23c32016-08-05 11:07:09 -0400555 .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500556 .authblock = {
557 .handle = cpu_to_be32(TPM2_RS_PW),
558 .noncesize = cpu_to_be16(0),
559 .contsession = TPM2_YES,
560 .pwdsize = cpu_to_be16(0),
561 },
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500562 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400563 u8 buffer[sizeof(tmp_tre) + sizeof(le->pad)];
Stefan Berger0fb23c32016-08-05 11:07:09 -0400564 struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
565
566 memcpy(tre, &tmp_tre, sizeof(tmp_tre));
Stefan Bergera99de5c2016-08-05 11:07:11 -0400567 memcpy(&tre->digest[0], le->hdr.digest, digest_len);
568
569 tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500570
571 struct tpm_rsp_header rsp;
572 u32 resp_length = sizeof(rsp);
Stefan Berger0fb23c32016-08-05 11:07:09 -0400573 int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length,
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500574 TPM_DURATION_TYPE_SHORT);
575 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
576 return -1;
577
578 return 0;
579}
580
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500581static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400582tpm_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger1d37d522016-02-02 13:09:11 -0500583{
Stefan Berger1d37d522016-02-02 13:09:11 -0500584 switch (TPM_version) {
585 case TPM_VERSION_1_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400586 return tpm12_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500587 case TPM_VERSION_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400588 return tpm20_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500589 }
590 return -1;
591}
592
Kevin O'Connor01669932016-08-10 16:15:43 -0400593static int
594tpm20_stirrandom(void)
595{
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400596 struct tpm2_req_stirrandom stir = {
597 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
598 .hdr.totlen = cpu_to_be32(sizeof(stir)),
599 .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),
Kevin O'Connor01669932016-08-10 16:15:43 -0400600 .size = cpu_to_be16(sizeof(stir.stir)),
601 .stir = rdtscll(),
602 };
603 /* set more bits to stir with */
604 stir.stir += swab64(rdtscll());
605
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400606 struct tpm_rsp_header rsp;
607 u32 resp_length = sizeof(rsp);
608 int ret = tpmhw_transmit(0, &stir.hdr, &rsp, &resp_length,
609 TPM_DURATION_TYPE_SHORT);
610 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
611 ret = -1;
Kevin O'Connor01669932016-08-10 16:15:43 -0400612
613 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
614 ret);
615
616 return ret;
617}
618
619static int
620tpm20_getrandom(u8 *buf, u16 buf_len)
621{
622 struct tpm2_res_getrandom rsp;
623
624 if (buf_len > sizeof(rsp.rnd.buffer))
625 return -1;
626
627 struct tpm2_req_getrandom trgr = {
628 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
629 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
630 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
631 .bytesRequested = cpu_to_be16(buf_len),
632 };
633 u32 resp_length = sizeof(rsp);
634
635 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
636 TPM_DURATION_TYPE_MEDIUM);
637 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
638 ret = -1;
639 else
640 memcpy(buf, rsp.rnd.buffer, buf_len);
641
642 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
643 ret);
644
645 return ret;
646}
647
648static int
649tpm20_hierarchycontrol(u32 hierarchy, u8 state)
650{
651 /* we will try to deactivate the TPM now - ignoring all errors */
652 struct tpm2_req_hierarchycontrol trh = {
653 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
654 .hdr.totlen = cpu_to_be32(sizeof(trh)),
655 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
656 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
657 .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
658 .authblock = {
659 .handle = cpu_to_be32(TPM2_RS_PW),
660 .noncesize = cpu_to_be16(0),
661 .contsession = TPM2_YES,
662 .pwdsize = cpu_to_be16(0),
663 },
664 .enable = cpu_to_be32(hierarchy),
665 .state = state,
666 };
667 struct tpm_rsp_header rsp;
668 u32 resp_length = sizeof(rsp);
669 int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
670 TPM_DURATION_TYPE_MEDIUM);
671 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
672 ret = -1;
673
674 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
675 ret);
676
677 return ret;
678}
679
680static int
681tpm20_hierarchychangeauth(u8 auth[20])
682{
683 struct tpm2_req_hierarchychangeauth trhca = {
684 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
685 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
686 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
687 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
688 .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
689 .authblock = {
690 .handle = cpu_to_be32(TPM2_RS_PW),
691 .noncesize = cpu_to_be16(0),
692 .contsession = TPM2_YES,
693 .pwdsize = cpu_to_be16(0),
694 },
695 .newAuth = {
696 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
697 },
698 };
699 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
700
701 struct tpm_rsp_header rsp;
702 u32 resp_length = sizeof(rsp);
703 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
704 TPM_DURATION_TYPE_MEDIUM);
705 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
706 ret = -1;
707
708 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
709 ret);
710
711 return ret;
712}
713
714
715/****************************************************************
716 * Setup and Measurements
717 ****************************************************************/
718
719static int TPM_has_physical_presence;
720u8 TPM_working VARLOW;
721
722static int
723tpm_is_working(void)
724{
725 return CONFIG_TCGBIOS && TPM_working;
726}
727
728static void
729tpm_set_failure(void)
730{
731 switch (TPM_version) {
732 case TPM_VERSION_1_2:
733 /*
734 * We will try to deactivate the TPM now - ignoring all errors
735 * Physical presence is asserted.
736 */
737
Kevin O'Connor846fd312016-08-10 18:15:13 -0400738 tpm_simple_cmd(0, TPM_ORD_SetTempDeactivated,
739 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connor01669932016-08-10 16:15:43 -0400740 break;
741 case TPM_VERSION_2:
742 tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
743 tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
744 break;
745 }
746
747 TPM_working = 0;
748}
749
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500750/*
751 * Add a measurement to the log; the data at data_seg:data/length are
752 * appended to the TCG_PCClientPCREventStruct
753 *
754 * Input parameters:
755 * pcrindex : which PCR to extend
756 * event_type : type of event; specs section on 'Event Types'
757 * event : pointer to info (e.g., string) to be added to log as-is
758 * event_length: length of the event
759 * hashdata : pointer to the data to be hashed
760 * hashdata_length: length of the data to be hashed
761 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500762static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500763tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
764 const char *event, u32 event_length,
765 const u8 *hashdata, u32 hashdata_length)
766{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500767 if (!tpm_is_working())
768 return;
769
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400770 u8 hash[SHA1_BUFSIZE];
771 sha1(hashdata, hashdata_length, hash);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400772
773 struct tpm_log_entry le = {
774 .hdr.pcrindex = pcrindex,
775 .hdr.eventtype = event_type,
776 };
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500777 int digest_len = tpm_build_digest(&le, hash, 1);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400778 if (digest_len < 0)
779 return;
780 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500781 if (ret) {
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500782 tpm_set_failure();
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500783 return;
784 }
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500785 tpm_build_digest(&le, hash, 0);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400786 tpm_log_event(&le.hdr, digest_len, event, event_length);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500787}
788
Kevin O'Connora6175422015-11-22 11:28:14 -0500789// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500790static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500791tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500792{
Kevin O'Connora6175422015-11-22 11:28:14 -0500793 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500794 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
795 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500796}
797
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500798/*
799 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
800 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500801static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500802tpm_add_event_separators(void)
803{
Kevin O'Connora6175422015-11-22 11:28:14 -0500804 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500805 u32 pcrIndex;
806 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
807 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
808 NULL, 0,
809 evt_separator,
810 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500811}
812
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500813static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500814tpm_smbios_measure(void)
815{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500816 struct pcctes pcctes = {
817 .eventid = 1,
818 .eventdatasize = SHA1_BUFSIZE,
819 };
820 struct smbios_entry_point *sep = SMBiosAddr;
821
822 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
823
824 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500825 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500826
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500827 sha1((const u8 *)sep->structure_table_address,
828 sep->structure_table_length, pcctes.digest);
829 tpm_add_measurement_to_log(1,
830 EV_EVENT_TAG,
831 (const char *)&pcctes, sizeof(pcctes),
832 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500833}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400834
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500835static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500836tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500837{
Kevin O'Connor846fd312016-08-10 18:15:13 -0400838 int ret = tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
839 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500840 if (!ret)
841 return 0;
842
843 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500844 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500845 if (ret)
846 return -1;
847
Stefan Bergera2206d32016-01-07 12:02:48 -0500848 /* check if hardware physical presence is supported */
849 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
850 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -0500851 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -0500852 }
853
Stefan Bergera2206d32016-01-07 12:02:48 -0500854 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
855 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Kevin O'Connor846fd312016-08-10 18:15:13 -0400856 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
857 2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500858
Kevin O'Connor846fd312016-08-10 18:15:13 -0400859 return tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
860 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -0500861 }
Stefan Bergere55e37f2016-01-07 12:02:47 -0500862 return -1;
863}
864
865static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500866tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400867{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400868 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connor846fd312016-08-10 18:15:13 -0400869 int ret = tpm_simple_cmd(0, TPM_ORD_Startup,
870 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500871 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400872 /* with other firmware on the system the TPM may already have been
873 * initialized
874 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500875 ret = 0;
876 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400877 goto err_exit;
878
Stefan Berger115d0082016-01-07 12:02:49 -0500879 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -0500880 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -0500881 if (!ret)
882 TPM_has_physical_presence = 1;
883
Stefan Berger1d37d522016-02-02 13:09:11 -0500884 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500885 if (ret)
Kevin O'Connord468d592016-08-10 16:23:02 -0400886 goto err_exit;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500887
Kevin O'Connor846fd312016-08-10 18:15:13 -0400888 ret = tpm_simple_cmd(0, TPM_ORD_SelfTestFull,
889 0, 0, TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500890 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400891 goto err_exit;
892
Kevin O'Connor846fd312016-08-10 18:15:13 -0400893 ret = tpm_simple_cmd(3, TSC_ORD_ResetEstablishmentBit,
894 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500895 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400896 goto err_exit;
897
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400898 return 0;
899
900err_exit:
901 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
902
Stefan Berger7fce1d92015-11-12 10:14:45 -0500903 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500904 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400905}
906
Stefan Berger1d37d522016-02-02 13:09:11 -0500907static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500908tpm20_startup(void)
909{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500910 tpm20_set_timeouts();
911
Kevin O'Connor846fd312016-08-10 18:15:13 -0400912 int ret = tpm_simple_cmd(0, TPM2_CC_Startup,
913 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500914
915 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
916 ret);
917
918 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
919 /* with other firmware on the system the TPM may already have been
920 * initialized
921 */
922 ret = 0;
923
924 if (ret)
925 goto err_exit;
926
Kevin O'Connor846fd312016-08-10 18:15:13 -0400927 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
928 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500929
930 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
931 ret);
932
933 if (ret)
934 goto err_exit;
935
Stefan Berger74544fa2016-08-05 11:07:08 -0400936 ret = tpm20_get_pcrbanks();
937 if (ret)
938 goto err_exit;
939
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400940 ret = tpm20_write_EfiSpecIdEventStruct();
941 if (ret)
942 goto err_exit;
943
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500944 return 0;
945
946err_exit:
947 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
948
949 tpm_set_failure();
950 return -1;
951}
952
953static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500954tpm_startup(void)
955{
956 switch (TPM_version) {
957 case TPM_VERSION_1_2:
958 return tpm12_startup();
959 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500960 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -0500961 }
962 return -1;
963}
964
Kevin O'Connord6aca442015-06-10 11:00:17 -0400965void
966tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400967{
968 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400969 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400970
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500971 TPM_version = tpmhw_probe();
972 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -0500973 return;
974
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500975 dprintf(DEBUG_tcg,
976 "TCGBIOS: Detected a TPM %s.\n",
977 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
978
Stefan Bergerdf46d102017-11-14 15:03:47 -0500979 int ret = tpm_tpm2_probe();
980 if (ret) {
981 ret = tpm_tcpa_probe();
982 if (ret)
983 return;
984 }
Kevin O'Connor27065322015-11-28 14:25:41 -0500985
986 TPM_working = 1;
987
Quan Xu67643952015-04-30 19:43:04 -0400988 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400989 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400990
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500991 ret = tpm_startup();
992 if (ret)
993 return;
994
995 tpm_smbios_measure();
996 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400997}
998
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500999static void
1000tpm20_prepboot(void)
1001{
1002 int ret = tpm20_stirrandom();
1003 if (ret)
1004 goto err_exit;
1005
1006 u8 auth[20];
1007 ret = tpm20_getrandom(&auth[0], sizeof(auth));
1008 if (ret)
1009 goto err_exit;
1010
1011 ret = tpm20_hierarchychangeauth(auth);
1012 if (ret)
1013 goto err_exit;
1014
1015 return;
1016
1017err_exit:
1018 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1019
1020 tpm_set_failure();
1021}
1022
Kevin O'Connord6aca442015-06-10 11:00:17 -04001023void
1024tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001025{
Stefan Berger8b902b82016-01-07 12:02:50 -05001026 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001027 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001028
Stefan Berger1d37d522016-02-02 13:09:11 -05001029 switch (TPM_version) {
1030 case TPM_VERSION_1_2:
1031 if (TPM_has_physical_presence)
Kevin O'Connor846fd312016-08-10 18:15:13 -04001032 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1033 2, TPM_PP_NOT_PRESENT_LOCK, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001034 break;
1035 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -05001036 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -05001037 break;
1038 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001039
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001040 tpm_add_action(4, "Calling INT 19h");
1041 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001042}
1043
Stefan Berger5aa2a752015-03-23 14:22:17 -04001044/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001045 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -04001046 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001047void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001048tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -04001049{
Kevin O'Connord559a232015-11-28 08:35:26 -05001050 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001051 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -05001052
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001053 struct pcctes_romex pcctes = {
1054 .eventid = 7,
1055 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -04001056 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001057 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001058 tpm_add_measurement_to_log(2,
1059 EV_EVENT_TAG,
1060 (const char *)&pcctes, sizeof(pcctes),
1061 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -05001062}
Stefan Berger5aa2a752015-03-23 14:22:17 -04001063
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001064void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001065tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1066{
Kevin O'Connord559a232015-11-28 08:35:26 -05001067 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001068 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001069
Stefan Berger4cdbc412015-11-30 11:14:18 -05001070 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001071 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -05001072
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001073 const char *string = "Booting BCV device 00h (Floppy)";
1074 if (bootdrv == 0x80)
1075 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001076 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001077
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001078 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1079 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001080 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001081 tpm_add_measurement_to_log(4, EV_IPL,
1082 string, strlen(string),
1083 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001084
1085 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1086 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001087 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1088 string, strlen(string),
1089 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001090}
1091
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001092void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001093tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1094{
Kevin O'Connord559a232015-11-28 08:35:26 -05001095 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001096 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001097
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001098 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001099
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001100 /* specs: see section 'El Torito' */
1101 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001102 tpm_add_measurement_to_log(4, EV_IPL,
1103 string, strlen(string),
1104 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001105}
1106
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001107void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001108tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1109{
Kevin O'Connord559a232015-11-28 08:35:26 -05001110 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001111 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001112
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001113 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001114
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001115 /* specs: see section 'El Torito' */
1116 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001117 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1118 string, strlen(string),
1119 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001120}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001121
Kevin O'Connord6aca442015-06-10 11:00:17 -04001122void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001123tpm_s3_resume(void)
1124{
Kevin O'Connord559a232015-11-28 08:35:26 -05001125 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001126 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001127
1128 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1129
Stefan Berger1d37d522016-02-02 13:09:11 -05001130 int ret = -1;
1131
1132 switch (TPM_version) {
1133 case TPM_VERSION_1_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001134 ret = tpm_simple_cmd(0, TPM_ORD_Startup,
1135 2, TPM_ST_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001136 break;
1137 case TPM_VERSION_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001138 ret = tpm_simple_cmd(0, TPM2_CC_Startup,
1139 2, TPM2_SU_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001140
1141 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
1142 ret);
1143
1144 if (ret)
1145 goto err_exit;
1146
1147
Kevin O'Connor846fd312016-08-10 18:15:13 -04001148 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
1149 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001150
1151 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
1152 ret);
1153
Stefan Berger1d37d522016-02-02 13:09:11 -05001154 break;
1155 }
1156
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001157 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001158 goto err_exit;
1159
Kevin O'Connord6aca442015-06-10 11:00:17 -04001160 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001161
1162err_exit:
1163 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1164
Stefan Berger7fce1d92015-11-12 10:14:45 -05001165 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001166}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001167
1168
1169/****************************************************************
1170 * BIOS interface
1171 ****************************************************************/
1172
Kevin O'Connor59076132015-11-28 13:55:09 -05001173u8 TPM_interface_shutdown VARLOW;
1174
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001175static inline void *input_buf32(struct bregs *regs)
1176{
1177 return MAKE_FLATPTR(regs->es, regs->di);
1178}
1179
1180static inline void *output_buf32(struct bregs *regs)
1181{
1182 return MAKE_FLATPTR(regs->ds, regs->si);
1183}
1184
1185static u32
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001186hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
1187 , void *event, int extend)
1188{
1189 if (pcpes->pcrindex >= 24)
1190 return TCG_INVALID_INPUT_PARA;
1191 if (hashdata)
1192 sha1(hashdata, hashdata_length, pcpes->digest);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001193
1194 struct tpm_log_entry le = {
1195 .hdr.pcrindex = pcpes->pcrindex,
1196 .hdr.eventtype = pcpes->eventtype,
1197 };
Stefan Berger7b7b49e2016-11-23 11:19:43 -05001198 int digest_len = tpm_build_digest(&le, pcpes->digest, 1);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001199 if (digest_len < 0)
1200 return TCG_GENERAL_ERROR;
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001201 if (extend) {
Stefan Bergera99de5c2016-08-05 11:07:11 -04001202 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001203 if (ret)
1204 return TCG_TCG_COMMAND_ERROR;
1205 }
Stefan Berger7b7b49e2016-11-23 11:19:43 -05001206 tpm_build_digest(&le, pcpes->digest, 0);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001207 int ret = tpm_log_event(&le.hdr, digest_len
1208 , pcpes->event, pcpes->eventdatasize);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001209 if (ret)
1210 return TCG_PC_LOGOVERFLOW;
1211 return 0;
1212}
1213
1214static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001215hash_log_extend_event_int(const struct hleei_short *hleei_s,
1216 struct hleeo *hleeo)
1217{
1218 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001219 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1220 const void *logdataptr;
1221 u32 logdatalen;
1222 struct pcpes *pcpes;
1223 u32 pcrindex;
1224
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001225 /* short or long version? */
1226 switch (hleei_s->ipblength) {
1227 case sizeof(struct hleei_short):
1228 /* short */
1229 logdataptr = hleei_s->logdataptr;
1230 logdatalen = hleei_s->logdatalen;
1231 pcrindex = hleei_s->pcrindex;
1232 break;
1233
1234 case sizeof(struct hleei_long):
1235 /* long */
1236 logdataptr = hleei_l->logdataptr;
1237 logdatalen = hleei_l->logdatalen;
1238 pcrindex = hleei_l->pcrindex;
1239 break;
1240
1241 default:
1242 /* bad input block */
1243 rc = TCG_INVALID_INPUT_PARA;
1244 goto err_exit;
1245 }
1246
1247 pcpes = (struct pcpes *)logdataptr;
1248
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001249 if (pcpes->pcrindex != pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001250 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001251 rc = TCG_INVALID_INPUT_PARA;
1252 goto err_exit;
1253 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001254 rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
1255 , pcpes->event, 1);
1256 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001257 goto err_exit;
1258
1259 hleeo->opblength = sizeof(struct hleeo);
1260 hleeo->reserved = 0;
Kevin O'Connor1ef72ab2017-09-02 21:42:12 -04001261 hleeo->eventnumber = tpm_state.entry_count;
Stefan Berger2b237502016-01-07 12:02:46 -05001262 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001263
1264err_exit:
1265 if (rc != 0) {
1266 hleeo->opblength = 4;
1267 hleeo->reserved = 0;
1268 }
1269
1270 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001271}
1272
1273static u32
1274pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1275{
1276 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001277 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001278
Stefan Berger7092de32016-02-02 13:09:19 -05001279 if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001280 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1281 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001282 rc = TCG_INVALID_INPUT_PARA;
1283 goto err_exit;
1284 }
1285
Stefan Berger7092de32016-02-02 13:09:19 -05001286 u16 tag = be16_to_cpu(trh->tag);
1287
1288 switch (TPM_version) {
1289 case TPM_VERSION_1_2:
1290 if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
1291 && tag != TPM_TAG_RQU_AUTH2_CMD) {
1292 rc = TCG_INVALID_INPUT_PARA;
1293 goto err_exit;
1294 }
1295 break;
1296 case TPM_VERSION_2:
1297 if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
1298 rc = TCG_INVALID_INPUT_PARA;
1299 goto err_exit;
1300 }
1301 }
1302
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001303 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001304 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1305 TPM_DURATION_TYPE_LONG /* worst case */);
1306 if (ret) {
1307 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001308 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001309 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001310
1311 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1312 pttto->reserved = 0;
1313
1314err_exit:
1315 if (rc != 0) {
1316 pttto->opblength = 4;
1317 pttto->reserved = 0;
1318 }
1319
1320 return rc;
1321}
1322
1323static u32
1324shutdown_preboot_interface(void)
1325{
Kevin O'Connor59076132015-11-28 13:55:09 -05001326 TPM_interface_shutdown = 1;
1327 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001328}
1329
1330static u32
1331hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1332{
1333 u32 rc = 0;
1334 u16 size;
1335 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001336
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001337 size = hlei->ipblength;
1338 if (size != sizeof(*hlei)) {
1339 rc = TCG_INVALID_INPUT_PARA;
1340 goto err_exit;
1341 }
1342
1343 pcpes = (struct pcpes *)hlei->logdataptr;
1344
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001345 if (pcpes->pcrindex != hlei->pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001346 || pcpes->eventtype != hlei->logeventtype
1347 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001348 rc = TCG_INVALID_INPUT_PARA;
1349 goto err_exit;
1350 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001351 rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
1352 , pcpes->event, 0);
1353 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001354 goto err_exit;
1355
1356 /* updating the log was fine */
1357 hleo->opblength = sizeof(struct hleo);
1358 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001359 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001360
1361err_exit:
1362 if (rc != 0) {
1363 hleo->opblength = 2;
1364 hleo->reserved = 0;
1365 }
1366
1367 return rc;
1368}
1369
1370static u32
1371hash_all_int(const struct hai *hai, u8 *hash)
1372{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001373 if (hai->ipblength != sizeof(struct hai) ||
1374 hai->hashdataptr == 0 ||
1375 hai->hashdatalen == 0 ||
1376 hai->algorithmid != TPM_ALG_SHA)
1377 return TCG_INVALID_INPUT_PARA;
1378
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001379 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1380 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001381}
1382
1383static u32
1384tss_int(struct ti *ti, struct to *to)
1385{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001386 to->opblength = sizeof(struct to);
1387 to->reserved = 0;
1388
Kevin O'Connor59076132015-11-28 13:55:09 -05001389 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001390}
1391
1392static u32
1393compact_hash_log_extend_event_int(u8 *buffer,
1394 u32 info,
1395 u32 length,
1396 u32 pcrindex,
1397 u32 *edx_ptr)
1398{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001399 struct pcpes pcpes = {
1400 .pcrindex = pcrindex,
1401 .eventtype = EV_COMPACT_HASH,
1402 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001403 };
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001404 u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
1405 if (rc)
1406 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001407
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001408 *edx_ptr = tpm_state.entry_count;
1409 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001410}
1411
1412void VISIBLE32FLAT
1413tpm_interrupt_handler32(struct bregs *regs)
1414{
1415 if (!CONFIG_TCGBIOS)
1416 return;
1417
1418 set_cf(regs, 0);
1419
Kevin O'Connor59076132015-11-28 13:55:09 -05001420 if (TPM_interface_shutdown && regs->al) {
1421 regs->eax = TCG_INTERFACE_SHUTDOWN;
1422 return;
1423 }
1424
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001425 switch ((enum irq_ids)regs->al) {
1426 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001427 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001428 /* no TPM available */
1429 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1430 } else {
1431 regs->eax = 0;
1432 regs->ebx = TCG_MAGIC;
1433 regs->ch = TCG_VERSION_MAJOR;
1434 regs->cl = TCG_VERSION_MINOR;
1435 regs->edx = 0x0;
1436 regs->esi = (u32)tpm_state.log_area_start_address;
1437 regs->edi = (u32)tpm_state.log_area_last_entry;
1438 }
1439 break;
1440
1441 case TCG_HashLogExtendEvent:
1442 regs->eax =
1443 hash_log_extend_event_int(
1444 (struct hleei_short *)input_buf32(regs),
1445 (struct hleeo *)output_buf32(regs));
1446 break;
1447
1448 case TCG_PassThroughToTPM:
1449 regs->eax =
1450 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1451 (struct pttto *)output_buf32(regs));
1452 break;
1453
1454 case TCG_ShutdownPreBootInterface:
1455 regs->eax = shutdown_preboot_interface();
1456 break;
1457
1458 case TCG_HashLogEvent:
1459 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1460 (struct hleo*)output_buf32(regs));
1461 break;
1462
1463 case TCG_HashAll:
1464 regs->eax =
1465 hash_all_int((struct hai*)input_buf32(regs),
1466 (u8 *)output_buf32(regs));
1467 break;
1468
1469 case TCG_TSS:
1470 regs->eax = tss_int((struct ti*)input_buf32(regs),
1471 (struct to*)output_buf32(regs));
1472 break;
1473
1474 case TCG_CompactHashLogExtendEvent:
1475 regs->eax =
1476 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1477 regs->esi,
1478 regs->ecx,
1479 regs->edx,
1480 &regs->edx);
1481 break;
1482
1483 default:
1484 set_cf(regs, 1);
1485 }
1486
1487 return;
1488}
Stefan Berger320df852015-11-30 11:14:19 -05001489
Kevin O'Connor26e36172015-12-29 12:20:23 -05001490
1491/****************************************************************
1492 * TPM Configuration Menu
1493 ****************************************************************/
1494
Kevin O'Connor01669932016-08-10 16:15:43 -04001495typedef u8 tpm_ppi_code;
1496
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001497static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001498tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001499{
Stefan Berger320df852015-11-30 11:14:19 -05001500 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001501 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1502 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001503 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001504 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001505
1506 *has_owner = oauth.flag;
1507
1508 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001509}
1510
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001511static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001512tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001513{
Stefan Berger320df852015-11-30 11:14:19 -05001514 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001515 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001516 if (ret)
1517 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001518
1519 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1520 return 0;
1521
Kevin O'Connor846fd312016-08-10 18:15:13 -04001522 ret = tpm_simple_cmd(0, enable ? TPM_ORD_PhysicalEnable
1523 : TPM_ORD_PhysicalDisable,
1524 0, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001525 if (ret) {
1526 if (enable)
1527 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1528 else
1529 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1530 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001531 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001532}
1533
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001534static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001535tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001536{
Stefan Berger320df852015-11-30 11:14:19 -05001537 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001538 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001539 if (ret)
1540 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001541
1542 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1543 return 0;
1544
1545 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1546 return 0;
1547
Kevin O'Connor846fd312016-08-10 18:15:13 -04001548 ret = tpm_simple_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1549 1, activate ? 0x00 : 0x01, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001550 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001551 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001552
1553 if (activate && allow_reset) {
1554 if (verbose) {
1555 printf("Requiring a reboot to activate the TPM.\n");
1556
1557 msleep(2000);
1558 }
1559 reset();
1560 }
1561
1562 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001563}
1564
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001565static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001566tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001567{
Stefan Berger1d37d522016-02-02 13:09:11 -05001568 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001569 if (ret)
1570 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001571
Stefan Berger1d37d522016-02-02 13:09:11 -05001572 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001573}
1574
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001575static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001576tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1577 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001578{
Stefan Berger320df852015-11-30 11:14:19 -05001579 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001580 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001581 if (ret)
1582 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001583 if (!has_owner) {
1584 if (verbose)
1585 printf("TPM does not have an owner.\n");
1586 return 0;
1587 }
1588
1589 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001590 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001591 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001592 dprintf(DEBUG_tcg,
1593 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001594 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001595 }
1596 }
1597
Kevin O'Connor846fd312016-08-10 18:15:13 -04001598 ret = tpm_simple_cmd(0, TPM_ORD_ForceClear,
1599 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001600 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001601 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001602
1603 if (!enable_activate_after) {
1604 if (verbose)
1605 printf("Owner successfully cleared.\n"
1606 "You will need to enable/activate the TPM again.\n\n");
1607 return 0;
1608 }
1609
Stefan Berger1d37d522016-02-02 13:09:11 -05001610 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001611}
1612
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001613static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001614tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001615{
Stefan Berger320df852015-11-30 11:14:19 -05001616 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001617 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001618 if (ret)
1619 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001620 if (has_owner) {
1621 if (verbose)
1622 printf("Must first remove owner.\n");
1623 return 0;
1624 }
1625
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001626 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001627 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001628 if (ret)
1629 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001630
1631 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1632 if (verbose)
1633 printf("TPM must first be enable.\n");
1634 return 0;
1635 }
1636
Kevin O'Connor846fd312016-08-10 18:15:13 -04001637 ret = tpm_simple_cmd(0, TPM_ORD_SetOwnerInstall,
1638 1, allow ? 0x01 : 0x00, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001639 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001640 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001641
1642 if (verbose)
1643 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1644
1645 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001646}
1647
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001648static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001649tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001650{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001651 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001652
1653 switch (msgCode) {
1654 case TPM_PPI_OP_NOOP: /* no-op */
1655 break;
1656
1657 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001658 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001659 break;
1660
1661 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001662 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001663 break;
1664
1665 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001666 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001667 break;
1668
1669 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001670 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001671 break;
1672
1673 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001674 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001675 break;
1676
1677 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001678 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001679 break;
1680
1681 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001682 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001683 break;
1684
1685 default:
1686 break;
1687 }
1688
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001689 if (ret)
1690 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001691
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001692 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001693}
1694
1695static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001696tpm20_clearcontrol(u8 disable, int verbose)
1697{
1698 struct tpm2_req_clearcontrol trc = {
1699 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1700 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1701 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1702 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1703 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1704 .authblock = {
1705 .handle = cpu_to_be32(TPM2_RS_PW),
1706 .noncesize = cpu_to_be16(0),
1707 .contsession = TPM2_YES,
1708 .pwdsize = cpu_to_be16(0),
1709 },
1710 .disable = disable,
1711 };
1712 struct tpm_rsp_header rsp;
1713 u32 resp_length = sizeof(rsp);
1714 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1715 TPM_DURATION_TYPE_SHORT);
1716 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1717 ret = -1;
1718
1719 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1720 ret);
1721
1722 return ret;
1723}
1724
1725static int
1726tpm20_clear(void)
1727{
1728 struct tpm2_req_clear trq = {
1729 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1730 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1731 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1732 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1733 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1734 .authblock = {
1735 .handle = cpu_to_be32(TPM2_RS_PW),
1736 .noncesize = cpu_to_be16(0),
1737 .contsession = TPM2_YES,
1738 .pwdsize = cpu_to_be16(0),
1739 },
1740 };
1741 struct tpm_rsp_header rsp;
1742 u32 resp_length = sizeof(rsp);
1743 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1744 TPM_DURATION_TYPE_MEDIUM);
1745 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1746 ret = -1;
1747
1748 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1749 ret);
1750
1751 return ret;
1752}
1753
1754static int
1755tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1756{
1757 int ret = 0;
1758
1759 switch (msgCode) {
1760 case TPM_PPI_OP_NOOP: /* no-op */
1761 break;
1762
1763 case TPM_PPI_OP_CLEAR:
1764 ret = tpm20_clearcontrol(0, verbose);
1765 if (!ret)
1766 ret = tpm20_clear();
1767 break;
1768 }
1769
1770 if (ret)
1771 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
1772
1773 return ret;
1774}
1775
1776static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001777tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05001778{
1779 int state = 0;
1780 struct tpm_permanent_flags pf;
1781 int has_owner;
1782
Stefan Berger1d37d522016-02-02 13:09:11 -05001783 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
1784 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05001785 return ~0;
1786
1787 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1788 state |= TPM_STATE_ENABLED;
1789
1790 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1791 state |= TPM_STATE_ACTIVE;
1792
1793 if (has_owner) {
1794 state |= TPM_STATE_OWNED;
1795 } else {
1796 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1797 state |= TPM_STATE_OWNERINSTALL;
1798 }
1799
1800 return state;
1801}
1802
1803static void
Stefan Berger1d37d522016-02-02 13:09:11 -05001804tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05001805{
1806 int i = 0;
1807
1808 printf("\nThe current state of the TPM is:\n");
1809
1810 if (state & TPM_STATE_ENABLED)
1811 printf(" Enabled");
1812 else
1813 printf(" Disabled");
1814
1815 if (state & TPM_STATE_ACTIVE)
1816 printf(" and active\n");
1817 else
1818 printf(" and deactivated\n");
1819
1820 if (state & TPM_STATE_OWNED)
1821 printf(" Ownership has been taken\n");
1822 else {
1823 printf(" Ownership has not been taken\n");
1824 if (state & TPM_STATE_OWNERINSTALL)
1825 printf(" A user can take ownership of the TPM\n");
1826 else
1827 printf(" Taking ownership of the TPM has been disabled\n");
1828 }
1829
1830 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1831 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1832 printf("\nNote: To make use of all functionality, the TPM must be "
1833 "enabled and active.\n");
1834 }
1835
1836 printf("\nAvailable options are:\n");
1837 if (state & TPM_STATE_ENABLED) {
1838 printf(" d. Disable the TPM\n");
1839 next_scancodes[i++] = 32;
1840
1841 if (state & TPM_STATE_ACTIVE) {
1842 printf(" v. Deactivate the TPM\n");
1843 next_scancodes[i++] = 47;
1844
1845 if (state & TPM_STATE_OWNERINSTALL) {
1846 printf(" p. Prevent installation of an owner\n");
1847 next_scancodes[i++] = 25;
1848 } else {
1849 printf(" s. Allow installation of an owner\n");
1850 next_scancodes[i++] = 31;
1851 }
1852 } else {
1853 printf(" a. Activate the TPM\n");
1854 next_scancodes[i++] = 30;
1855 }
1856
1857 } else {
1858 printf(" e. Enable the TPM\n");
1859 next_scancodes[i++] = 18;
1860 }
1861
1862 if (state & TPM_STATE_OWNED) {
1863 printf(" c. Clear ownership\n");
1864 next_scancodes[i++] = 46;
1865 }
1866
1867 next_scancodes[i++] = 0;
1868}
1869
Stefan Berger1d37d522016-02-02 13:09:11 -05001870static void
1871tpm12_menu(void)
Stefan Berger320df852015-11-30 11:14:19 -05001872{
Stefan Berger320df852015-11-30 11:14:19 -05001873 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001874 tpm_ppi_code msgCode;
1875 int state = 0, i;
1876 int waitkey;
1877
Stefan Berger320df852015-11-30 11:14:19 -05001878 printf("The Trusted Platform Module (TPM) is a hardware device in "
1879 "this machine.\n"
1880 "It can help verify the integrity of system software.\n\n");
1881
1882 for (;;) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001883 if ((state = tpm12_get_tpm_state()) != ~0) {
1884 tpm12_show_tpm_menu(state, next_scancodes);
Stefan Berger320df852015-11-30 11:14:19 -05001885 } else {
1886 printf("TPM is not working correctly.\n");
1887 return;
1888 }
1889
1890 printf("\nIf no change is desired or if this menu was reached by "
1891 "mistake, press ESC to\n"
1892 "reboot the machine.\n");
1893
1894 msgCode = TPM_PPI_OP_NOOP;
1895
1896 waitkey = 1;
1897
1898 while (waitkey) {
1899 while ((scancode = get_keystroke(1000)) == ~0)
1900 ;
1901
1902 switch (scancode) {
1903 case 1:
1904 // ESC
1905 reset();
1906 break;
1907 case 18: /* e. enable */
1908 msgCode = TPM_PPI_OP_ENABLE;
1909 break;
1910 case 32: /* d. disable */
1911 msgCode = TPM_PPI_OP_DISABLE;
1912 break;
1913 case 30: /* a. activate */
1914 msgCode = TPM_PPI_OP_ACTIVATE;
1915 break;
1916 case 47: /* v. deactivate */
1917 msgCode = TPM_PPI_OP_DEACTIVATE;
1918 break;
1919 case 46: /* c. clear owner */
1920 msgCode = TPM_PPI_OP_CLEAR;
1921 break;
1922 case 25: /* p. prevent ownerinstall */
1923 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1924 break;
1925 case 31: /* s. allow ownerinstall */
1926 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1927 break;
1928 default:
1929 continue;
1930 }
1931
1932 /*
1933 * Using the next_scancodes array, check whether the
1934 * pressed key is currently a valid option.
1935 */
1936 for (i = 0; i < sizeof(next_scancodes); i++) {
1937 if (next_scancodes[i] == 0)
1938 break;
1939
1940 if (next_scancodes[i] == scancode) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001941 tpm12_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001942 waitkey = 0;
1943 break;
1944 }
1945 }
1946 }
1947 }
1948}
Stefan Berger1d37d522016-02-02 13:09:11 -05001949
Stefan Berger7d596dc2016-02-02 13:09:16 -05001950static void
1951tpm20_menu(void)
1952{
1953 int scan_code;
1954 tpm_ppi_code msgCode;
1955
1956 for (;;) {
1957 printf("1. Clear TPM\n");
1958
1959 printf("\nIf no change is desired or if this menu was reached by "
1960 "mistake, press ESC to\n"
1961 "reboot the machine.\n");
1962
1963 msgCode = TPM_PPI_OP_NOOP;
1964
1965 while ((scan_code = get_keystroke(1000)) == ~0)
1966 ;
1967
1968 switch (scan_code) {
1969 case 1:
1970 // ESC
1971 reset();
1972 break;
1973 case 2:
1974 msgCode = TPM_PPI_OP_CLEAR;
1975 break;
1976 default:
1977 continue;
1978 }
1979
1980 tpm20_process_cfg(msgCode, 0);
1981 }
1982}
1983
Stefan Berger1d37d522016-02-02 13:09:11 -05001984void
1985tpm_menu(void)
1986{
1987 if (!CONFIG_TCGBIOS)
1988 return;
1989
1990 while (get_keystroke(0) >= 0)
1991 ;
1992 wait_threads();
1993
1994 switch (TPM_version) {
1995 case TPM_VERSION_1_2:
1996 tpm12_menu();
1997 break;
1998 case TPM_VERSION_2:
Stefan Berger7d596dc2016-02-02 13:09:16 -05001999 tpm20_menu();
Stefan Berger1d37d522016-02-02 13:09:11 -05002000 break;
2001 }
2002}
Kevin O'Connor01669932016-08-10 16:15:43 -04002003
2004int
2005tpm_can_show_menu(void)
2006{
2007 switch (TPM_version) {
2008 case TPM_VERSION_1_2:
2009 return tpm_is_working() && TPM_has_physical_presence;
2010 case TPM_VERSION_2:
2011 return tpm_is_working();
2012 }
2013 return 0;
2014}