blob: cd2b228710a17bbccee257628bc2a1a78c60482c [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
Stefan Berger2aff1c12015-05-26 15:48:33 -04002// described in specs found at
3// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
Stefan Bergerb310dfa2015-03-23 14:22:16 -04004//
Stefan Berger2aff1c12015-05-26 15:48:33 -04005// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
Stefan Bergerb310dfa2015-03-23 14:22:16 -04006//
7// Authors:
8// Stefan Berger <stefanb@linux.vnet.ibm.com>
9//
10// This file may be distributed under the terms of the GNU LGPLv3 license.
11
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050012#include "bregs.h" // struct bregs
Stefan Bergerb310dfa2015-03-23 14:22:16 -040013#include "byteorder.h" // cpu_to_*
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050014#include "config.h" // CONFIG_TCGBIOS
Stefan Bergerb310dfa2015-03-23 14:22:16 -040015#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050016#include "fw/paravirt.h" // runningOnXen
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "output.h" // dprintf
19#include "sha1.h" // sha1
20#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
21#include "std/smbios.h" // struct smbios_entry_point
22#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
Stefan Bergerb310dfa2015-03-23 14:22:16 -040023#include "string.h" // checksum
24#include "tcgbios.h"// tpm_*, prototypes
25#include "util.h" // printf, get_keystroke
Stefan Berger320df852015-11-30 11:14:19 -050026#include "stacks.h" // wait_threads, reset
Stefan Bergerb310dfa2015-03-23 14:22:16 -040027
Stefan Bergerf53b93b2016-02-02 13:09:12 -050028/****************************************************************
29 * TPM 1.2 commands
30 ****************************************************************/
31
Stefan Berger0d289b52015-06-09 19:56:29 -040032static const u8 Startup_ST_CLEAR[] = { 0x00, TPM_ST_CLEAR };
33static const u8 Startup_ST_STATE[] = { 0x00, TPM_ST_STATE };
Stefan Bergerb310dfa2015-03-23 14:22:16 -040034
Stefan Berger0d289b52015-06-09 19:56:29 -040035static const u8 PhysicalPresence_CMD_ENABLE[] = { 0x00, 0x20 };
36static const u8 PhysicalPresence_CMD_DISABLE[] = { 0x01, 0x00 };
37static 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
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050080static struct tcpa_descriptor_rev2 *
81find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
82{
Kevin O'Connor27065322015-11-28 14:25:41 -050083 if (!rsdp) {
84 dprintf(DEBUG_tcg,
85 "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
86 return NULL;
87 }
88 struct rsdt_descriptor *rsdt = (void*)rsdp->rsdt_physical_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050089 if (!rsdt)
90 return NULL;
91
Kevin O'Connor27065322015-11-28 14:25:41 -050092 u32 length = rsdt->length;
93 u16 off = offsetof(struct rsdt_descriptor, entry);
94 u32 ctr = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050095 while ((off + sizeof(rsdt->entry[0])) <= length) {
96 /* try all pointers to structures */
Kevin O'Connor27065322015-11-28 14:25:41 -050097 struct tcpa_descriptor_rev2 *tcpa = (void*)rsdt->entry[ctr];
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050098
99 /* valid TCPA ACPI table ? */
Kevin O'Connor27065322015-11-28 14:25:41 -0500100 if (tcpa->signature == TCPA_SIGNATURE
101 && checksum(tcpa, tcpa->length) == 0)
102 return tcpa;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500103
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500104 off += sizeof(rsdt->entry[0]);
105 ctr++;
106 }
107
Kevin O'Connor27065322015-11-28 14:25:41 -0500108 dprintf(DEBUG_tcg, "TCGBIOS: TCPA ACPI was NOT found!\n");
109 return NULL;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500110}
111
Kevin O'Connor27065322015-11-28 14:25:41 -0500112static int
113tpm_tcpa_probe(void)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500114{
Kevin O'Connor27065322015-11-28 14:25:41 -0500115 struct tcpa_descriptor_rev2 *tcpa = find_tcpa_by_rsdp(RsdpAddr);
116 if (!tcpa)
117 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500118
Kevin O'Connor27065322015-11-28 14:25:41 -0500119 u8 *log_area_start_address = (u8*)(long)tcpa->log_area_start_address;
120 u32 log_area_minimum_length = tcpa->log_area_minimum_length;
121 if (!log_area_start_address || !log_area_minimum_length)
122 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500123
Kevin O'Connor27065322015-11-28 14:25:41 -0500124 memset(log_area_start_address, 0, log_area_minimum_length);
125 tpm_state.log_area_start_address = log_area_start_address;
126 tpm_state.log_area_minimum_length = log_area_minimum_length;
127 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500128 tpm_state.log_area_last_entry = NULL;
129 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -0500130 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500131}
132
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500133/*
134 * Extend the ACPI log with the given entry by copying the
135 * entry data into the log.
136 * Input
137 * pcpes : Pointer to the event 'header' to be copied into the log
138 * event : Pointer to the event 'body' to be copied into the log
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500139 *
140 * Output:
141 * Returns an error code in case of faiure, 0 in case of success
142 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500143static int
Kevin O'Connor4e7cf9c2015-11-22 18:51:31 -0500144tpm_log_event(struct pcpes *pcpes, const void *event)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500145{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500146 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
147 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
148
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500149 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500150 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500151
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500152 u32 size = sizeof(*pcpes) + pcpes->eventdatasize;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500153
154 if ((tpm_state.log_area_next_entry + size - tpm_state.log_area_start_address) >
155 tpm_state.log_area_minimum_length) {
156 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500157 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500158 }
159
Kevin O'Connorbad6f962015-11-23 22:32:09 -0500160 memcpy(tpm_state.log_area_next_entry, pcpes, sizeof(*pcpes));
161 memcpy(tpm_state.log_area_next_entry + sizeof(*pcpes),
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500162 event, pcpes->eventdatasize);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500163
164 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
165 tpm_state.log_area_next_entry += size;
166 tpm_state.entry_count++;
167
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500168 return 0;
169}
170
171
172/****************************************************************
173 * Helper functions
174 ****************************************************************/
175
Kevin O'Connord559a232015-11-28 08:35:26 -0500176u8 TPM_working VARLOW;
177
Stefan Berger115d0082016-01-07 12:02:49 -0500178static int
Kevin O'Connord559a232015-11-28 08:35:26 -0500179tpm_is_working(void)
180{
181 return CONFIG_TCGBIOS && TPM_working;
182}
183
Stefan Berger115d0082016-01-07 12:02:49 -0500184int
185tpm_can_show_menu(void)
186{
Stefan Berger1d37d522016-02-02 13:09:11 -0500187 switch (TPM_version) {
188 case TPM_VERSION_1_2:
189 return tpm_is_working() && TPM_has_physical_presence;
190 case TPM_VERSION_2:
191 return tpm_is_working();
192 }
193 return 0;
Stefan Berger115d0082016-01-07 12:02:49 -0500194}
195
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400196/*
197 * Send a TPM command with the given ordinal. Append the given buffer
198 * containing all data in network byte order to the command (this is
199 * the custom part per command) and expect a response of the given size.
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400200 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500201static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500202tpm_build_and_send_cmd(u8 locty, u32 ordinal, const u8 *append,
203 u32 append_size, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400204{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500205 struct {
206 struct tpm_req_header trqh;
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500207 u8 cmd[10];
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500208 } PACKED req = {
209 .trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
Kevin O'Connor7ba05682015-11-22 18:21:45 -0500210 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + append_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500211 .trqh.ordinal = cpu_to_be32(ordinal),
212 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500213
214 switch (TPM_version) {
215 case TPM_VERSION_1_2:
216 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
217 break;
218 case TPM_VERSION_2:
219 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
220 break;
221 }
222
Stefan Bergerece25612015-11-12 10:14:46 -0500223 u8 obuffer[64];
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400224 struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400225 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400226 memset(obuffer, 0x0, sizeof(obuffer));
227
Kevin O'Connor71479612015-12-29 14:32:19 -0500228 if (append_size > sizeof(req.cmd)) {
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500229 warn_internalerror();
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500230 return -1;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500231 }
232 if (append_size)
233 memcpy(req.cmd, append, append_size);
234
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500235 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
236 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500237 dprintf(DEBUG_tcg, "Return from build_and_send_cmd(%x, %x %x) = %x\n",
238 ordinal, req.cmd[0], req.cmd[1], ret);
239 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400240}
241
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500242static void
243tpm_set_failure(void)
244{
Stefan Berger1d37d522016-02-02 13:09:11 -0500245 switch (TPM_version) {
246 case TPM_VERSION_1_2:
247 /*
248 * We will try to deactivate the TPM now - ignoring all errors
249 * Physical presence is asserted.
250 */
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500251
Stefan Berger1d37d522016-02-02 13:09:11 -0500252 tpm_build_and_send_cmd(0, TPM_ORD_SetTempDeactivated,
253 NULL, 0, TPM_DURATION_TYPE_SHORT);
254 break;
255 case TPM_VERSION_2:
256 // FIXME: missing code
257 break;
258 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500259
Kevin O'Connord559a232015-11-28 08:35:26 -0500260 TPM_working = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500261}
262
Kevin O'Connorca606362015-12-29 14:21:29 -0500263static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500264tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
Kevin O'Connorca606362015-12-29 14:21:29 -0500265{
266 struct tpm_req_getcap trgc = {
267 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
268 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
269 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
270 .capArea = cpu_to_be32(cap),
271 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
272 .subCap = cpu_to_be32(subcap)
273 };
274 u32 resp_size = rsize;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500275 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
276 TPM_DURATION_TYPE_SHORT);
277 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
Kevin O'Connorca606362015-12-29 14:21:29 -0500278 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
279 " = %x\n", cap, subcap, ret);
280 if (ret) {
281 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
282 tpm_set_failure();
283 }
284 return ret;
285}
286
287static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500288tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400289{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400290 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500291 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
292 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500293 if (ret)
294 return ret;
295
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400296 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500297 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
298 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500299 if (ret)
300 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400301
Kevin O'Connorca606362015-12-29 14:21:29 -0500302 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400303 for (i = 0; i < 3; i++)
304 durations.durations[i] = be32_to_cpu(durations.durations[i]);
305
306 for (i = 0; i < 4; i++)
307 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
308
309 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
310 timeouts.timeouts[0],
311 timeouts.timeouts[1],
312 timeouts.timeouts[2],
313 timeouts.timeouts[3]);
314
315 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
316 durations.durations[0],
317 durations.durations[1],
318 durations.durations[2]);
319
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500320 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400321
322 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400323}
324
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500325static void
326tpm20_set_timeouts(void)
327{
328 u32 durations[3] = {
329 TPM2_DEFAULT_DURATION_SHORT,
330 TPM2_DEFAULT_DURATION_MEDIUM,
331 TPM2_DEFAULT_DURATION_LONG,
332 };
333 u32 timeouts[4] = {
334 TIS2_DEFAULT_TIMEOUT_A,
335 TIS2_DEFAULT_TIMEOUT_B,
336 TIS2_DEFAULT_TIMEOUT_C,
337 TIS2_DEFAULT_TIMEOUT_D,
338 };
339
340 tpmhw_set_timeouts(timeouts, durations);
341}
342
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500343static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500344tpm12_extend(u32 pcrindex, const u8 *digest)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500345{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500346 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500347 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
348 .hdr.totlen = cpu_to_be32(sizeof(tre)),
349 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500350 .pcrindex = cpu_to_be32(pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500351 };
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500352 memcpy(tre.digest, digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500353
354 struct tpm_rsp_extend rsp;
355 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500356 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
357 TPM_DURATION_TYPE_SHORT);
358 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500359 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500360
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500361 return 0;
362}
363
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500364static int tpm20_extend(u32 pcrindex, const u8 *digest)
365{
366 struct tpm2_req_extend tre = {
367 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
368 .hdr.totlen = cpu_to_be32(sizeof(tre)),
369 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
370 .pcrindex = cpu_to_be32(pcrindex),
371 .authblocksize = cpu_to_be32(sizeof(tre.authblock)),
372 .authblock = {
373 .handle = cpu_to_be32(TPM2_RS_PW),
374 .noncesize = cpu_to_be16(0),
375 .contsession = TPM2_YES,
376 .pwdsize = cpu_to_be16(0),
377 },
378 .digest = {
379 .count = cpu_to_be32(1),
380 .hashalg = cpu_to_be16(TPM2_ALG_SHA1),
381 },
382 };
383 memcpy(tre.digest.sha1, digest, sizeof(tre.digest.sha1));
384
385 struct tpm_rsp_header rsp;
386 u32 resp_length = sizeof(rsp);
387 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
388 TPM_DURATION_TYPE_SHORT);
389 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
390 return -1;
391
392 return 0;
393}
394
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500395static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500396tpm_extend(u32 pcrindex, const u8 *digest)
397{
398 if (pcrindex >= 24)
399 return -1;
400
401 switch (TPM_version) {
402 case TPM_VERSION_1_2:
403 return tpm12_extend(pcrindex, digest);
404 case TPM_VERSION_2:
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500405 return tpm20_extend(pcrindex, digest);
Stefan Berger1d37d522016-02-02 13:09:11 -0500406 }
407 return -1;
408}
409
410static int
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500411tpm_log_extend_event(struct pcpes *pcpes, const void *event)
412{
413 int ret = tpm_extend(pcpes->pcrindex, pcpes->digest);
414 if (ret)
415 return -1;
416
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500417 return tpm_log_event(pcpes, event);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500418}
419
Kevin O'Connor92244402015-11-22 16:54:18 -0500420static void
421tpm_fill_hash(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length)
422{
423 if (hashdata)
424 sha1(hashdata, hashdata_length, pcpes->digest);
425}
426
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500427/*
428 * Add a measurement to the log; the data at data_seg:data/length are
429 * appended to the TCG_PCClientPCREventStruct
430 *
431 * Input parameters:
432 * pcrindex : which PCR to extend
433 * event_type : type of event; specs section on 'Event Types'
434 * event : pointer to info (e.g., string) to be added to log as-is
435 * event_length: length of the event
436 * hashdata : pointer to the data to be hashed
437 * hashdata_length: length of the data to be hashed
438 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500439static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500440tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
441 const char *event, u32 event_length,
442 const u8 *hashdata, u32 hashdata_length)
443{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500444 if (!tpm_is_working())
445 return;
446
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500447 struct pcpes pcpes = {
448 .pcrindex = pcrindex,
449 .eventtype = event_type,
Kevin O'Connor7bf77382015-11-22 17:28:36 -0500450 .eventdatasize = event_length,
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500451 };
Kevin O'Connor92244402015-11-22 16:54:18 -0500452 tpm_fill_hash(&pcpes, hashdata, hashdata_length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500453 int ret = tpm_log_extend_event(&pcpes, event);
454 if (ret)
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500455 tpm_set_failure();
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500456}
457
458
459/****************************************************************
460 * Setup and Measurements
461 ****************************************************************/
462
Kevin O'Connora6175422015-11-22 11:28:14 -0500463// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500464static void
Kevin O'Connora6175422015-11-22 11:28:14 -0500465tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500466{
Kevin O'Connora6175422015-11-22 11:28:14 -0500467 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500468 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
469 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500470}
471
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500472/*
473 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
474 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500475static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500476tpm_add_event_separators(void)
477{
Kevin O'Connora6175422015-11-22 11:28:14 -0500478 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500479 u32 pcrIndex;
480 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
481 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
482 NULL, 0,
483 evt_separator,
484 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500485}
486
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500487static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500488tpm_smbios_measure(void)
489{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500490 struct pcctes pcctes = {
491 .eventid = 1,
492 .eventdatasize = SHA1_BUFSIZE,
493 };
494 struct smbios_entry_point *sep = SMBiosAddr;
495
496 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
497
498 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500499 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500500
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500501 sha1((const u8 *)sep->structure_table_address,
502 sep->structure_table_length, pcctes.digest);
503 tpm_add_measurement_to_log(1,
504 EV_EVENT_TAG,
505 (const char *)&pcctes, sizeof(pcctes),
506 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500507}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400508
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500509static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500510tpm12_read_permanent_flags(char *buf, int buf_len)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500511{
512 memset(buf, 0, buf_len);
513
514 struct tpm_res_getcap_perm_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500515 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
516 , &pf.hdr, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500517 if (ret)
518 return -1;
519
520 memcpy(buf, &pf.perm_flags, buf_len);
521
522 return 0;
523}
524
525static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500526tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -0500527{
Stefan Berger1d37d522016-02-02 13:09:11 -0500528 int ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
529 PhysicalPresence_PRESENT,
530 sizeof(PhysicalPresence_PRESENT),
531 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500532 if (!ret)
533 return 0;
534
535 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -0500536 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -0500537 if (ret)
538 return -1;
539
Stefan Bergera2206d32016-01-07 12:02:48 -0500540 /* check if hardware physical presence is supported */
541 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
542 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -0500543 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -0500544 }
545
Stefan Bergera2206d32016-01-07 12:02:48 -0500546 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
547 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Stefan Berger1d37d522016-02-02 13:09:11 -0500548 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
549 PhysicalPresence_CMD_ENABLE,
550 sizeof(PhysicalPresence_CMD_ENABLE),
551 TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -0500552
Stefan Berger1d37d522016-02-02 13:09:11 -0500553 return tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
554 PhysicalPresence_PRESENT,
555 sizeof(PhysicalPresence_PRESENT),
556 TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -0500557 }
Stefan Bergere55e37f2016-01-07 12:02:47 -0500558 return -1;
559}
560
561static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500562tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400563{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400564 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Stefan Berger1d37d522016-02-02 13:09:11 -0500565 int ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
566 Startup_ST_CLEAR,
567 sizeof(Startup_ST_CLEAR),
568 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500569 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400570 /* with other firmware on the system the TPM may already have been
571 * initialized
572 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500573 ret = 0;
574 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400575 goto err_exit;
576
Stefan Berger115d0082016-01-07 12:02:49 -0500577 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -0500578 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -0500579 if (!ret)
580 TPM_has_physical_presence = 1;
581
Stefan Berger1d37d522016-02-02 13:09:11 -0500582 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -0500583 if (ret)
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500584 return -1;
Stefan Bergerec42c8d2015-11-21 14:54:41 -0500585
Stefan Berger1d37d522016-02-02 13:09:11 -0500586 ret = tpm_build_and_send_cmd(0, TPM_ORD_SelfTestFull, NULL, 0,
587 TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500588 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400589 goto err_exit;
590
Stefan Berger1d37d522016-02-02 13:09:11 -0500591 ret = tpm_build_and_send_cmd(3, TSC_ORD_ResetEstablishmentBit, NULL, 0,
592 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500593 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400594 goto err_exit;
595
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400596 return 0;
597
598err_exit:
599 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
600
Stefan Berger7fce1d92015-11-12 10:14:45 -0500601 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500602 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400603}
604
Stefan Berger1d37d522016-02-02 13:09:11 -0500605static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500606tpm20_startup(void)
607{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500608 tpm20_set_timeouts();
609
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500610 int ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
611 Startup_SU_CLEAR,
612 sizeof(Startup_SU_CLEAR),
613 TPM_DURATION_TYPE_SHORT);
614
615 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
616 ret);
617
618 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
619 /* with other firmware on the system the TPM may already have been
620 * initialized
621 */
622 ret = 0;
623
624 if (ret)
625 goto err_exit;
626
627 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
628 TPM2_SelfTest_YES,
629 sizeof(TPM2_SelfTest_YES),
630 TPM_DURATION_TYPE_LONG);
631
632 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
633 ret);
634
635 if (ret)
636 goto err_exit;
637
638 return 0;
639
640err_exit:
641 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
642
643 tpm_set_failure();
644 return -1;
645}
646
647static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500648tpm_startup(void)
649{
650 switch (TPM_version) {
651 case TPM_VERSION_1_2:
652 return tpm12_startup();
653 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500654 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -0500655 }
656 return -1;
657}
658
Kevin O'Connord6aca442015-06-10 11:00:17 -0400659void
660tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400661{
662 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400663 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400664
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500665 TPM_version = tpmhw_probe();
666 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -0500667 return;
668
Stefan Bergerefc49cf2016-02-02 13:09:09 -0500669 dprintf(DEBUG_tcg,
670 "TCGBIOS: Detected a TPM %s.\n",
671 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
672
673 int ret = tpm_tcpa_probe();
Kevin O'Connor27065322015-11-28 14:25:41 -0500674 if (ret)
675 return;
676
677 TPM_working = 1;
678
Quan Xu67643952015-04-30 19:43:04 -0400679 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400680 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400681
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500682 ret = tpm_startup();
683 if (ret)
684 return;
685
686 tpm_smbios_measure();
687 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400688}
689
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500690static int
691tpm20_stirrandom(void)
692{
693 struct tpm2b_stir stir = {
694 .size = cpu_to_be16(sizeof(stir.stir)),
695 .stir = rdtscll(),
696 };
697 /* set more bits to stir with */
698 stir.stir += swab64(rdtscll());
699
700 int ret = tpm_build_and_send_cmd(0, TPM2_CC_StirRandom,
701 (u8 *)&stir, sizeof(stir),
702 TPM_DURATION_TYPE_SHORT);
703
704 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
705 ret);
706
707 return ret;
708}
709
710static int
711tpm20_getrandom(u8 *buf, u16 buf_len)
712{
713 struct tpm2_res_getrandom rsp;
714
715 if (buf_len > sizeof(rsp.rnd.buffer))
716 return -1;
717
718 struct tpm2_req_getrandom trgr = {
719 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
720 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
721 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
722 .bytesRequested = cpu_to_be16(buf_len),
723 };
724 u32 resp_length = sizeof(rsp);
725
726 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
727 TPM_DURATION_TYPE_MEDIUM);
728 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
729 ret = -1;
730 else
731 memcpy(buf, rsp.rnd.buffer, buf_len);
732
733 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
734 ret);
735
736 return ret;
737}
738
739static int
740tpm20_hierarchychangeauth(u8 auth[20])
741{
742 struct tpm2_req_hierarchychangeauth trhca = {
743 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
744 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
745 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
746 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
747 .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
748 .authblock = {
749 .handle = cpu_to_be32(TPM2_RS_PW),
750 .noncesize = cpu_to_be16(0),
751 .contsession = TPM2_YES,
752 .pwdsize = cpu_to_be16(0),
753 },
754 .newAuth = {
755 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
756 },
757 };
758 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
759
760 struct tpm_rsp_header rsp;
761 u32 resp_length = sizeof(rsp);
762 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
763 TPM_DURATION_TYPE_MEDIUM);
764 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
765 ret = -1;
766
767 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
768 ret);
769
770 return ret;
771}
772
773static void
774tpm20_prepboot(void)
775{
776 int ret = tpm20_stirrandom();
777 if (ret)
778 goto err_exit;
779
780 u8 auth[20];
781 ret = tpm20_getrandom(&auth[0], sizeof(auth));
782 if (ret)
783 goto err_exit;
784
785 ret = tpm20_hierarchychangeauth(auth);
786 if (ret)
787 goto err_exit;
788
789 return;
790
791err_exit:
792 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
793
794 tpm_set_failure();
795}
796
Kevin O'Connord6aca442015-06-10 11:00:17 -0400797void
798tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400799{
Stefan Berger8b902b82016-01-07 12:02:50 -0500800 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -0400801 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400802
Stefan Berger1d37d522016-02-02 13:09:11 -0500803 switch (TPM_version) {
804 case TPM_VERSION_1_2:
805 if (TPM_has_physical_presence)
806 tpm_build_and_send_cmd(0, TPM_ORD_PhysicalPresence,
807 PhysicalPresence_NOT_PRESENT_LOCK,
808 sizeof(PhysicalPresence_NOT_PRESENT_LOCK),
809 TPM_DURATION_TYPE_SHORT);
810 break;
811 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -0500812 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -0500813 break;
814 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400815
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500816 tpm_add_action(4, "Calling INT 19h");
817 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400818}
819
Stefan Berger5aa2a752015-03-23 14:22:17 -0400820/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500821 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -0400822 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500823void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500824tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -0400825{
Kevin O'Connord559a232015-11-28 08:35:26 -0500826 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500827 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -0500828
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500829 struct pcctes_romex pcctes = {
830 .eventid = 7,
831 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -0400832 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500833 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500834 tpm_add_measurement_to_log(2,
835 EV_EVENT_TAG,
836 (const char *)&pcctes, sizeof(pcctes),
837 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -0500838}
Stefan Berger5aa2a752015-03-23 14:22:17 -0400839
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500840void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400841tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
842{
Kevin O'Connord559a232015-11-28 08:35:26 -0500843 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500844 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400845
Stefan Berger4cdbc412015-11-30 11:14:18 -0500846 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500847 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -0500848
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500849 const char *string = "Booting BCV device 00h (Floppy)";
850 if (bootdrv == 0x80)
851 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500852 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400853
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500854 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
855 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -0500856 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500857 tpm_add_measurement_to_log(4, EV_IPL,
858 string, strlen(string),
859 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500860
861 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
862 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500863 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
864 string, strlen(string),
865 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400866}
867
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500868void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400869tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
870{
Kevin O'Connord559a232015-11-28 08:35:26 -0500871 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500872 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400873
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500874 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400875
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500876 /* specs: see section 'El Torito' */
877 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500878 tpm_add_measurement_to_log(4, EV_IPL,
879 string, strlen(string),
880 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400881}
882
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500883void
Stefan Berger2aff1c12015-05-26 15:48:33 -0400884tpm_add_cdrom_catalog(const u8 *addr, u32 length)
885{
Kevin O'Connord559a232015-11-28 08:35:26 -0500886 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500887 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -0400888
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500889 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -0400890
Kevin O'Connor7ea191b2015-11-22 11:15:51 -0500891 /* specs: see section 'El Torito' */
892 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -0500893 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
894 string, strlen(string),
895 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -0400896}
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400897
Kevin O'Connord6aca442015-06-10 11:00:17 -0400898void
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400899tpm_s3_resume(void)
900{
Kevin O'Connord559a232015-11-28 08:35:26 -0500901 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -0400902 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400903
904 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
905
Stefan Berger1d37d522016-02-02 13:09:11 -0500906 int ret = -1;
907
908 switch (TPM_version) {
909 case TPM_VERSION_1_2:
910 ret = tpm_build_and_send_cmd(0, TPM_ORD_Startup,
911 Startup_ST_STATE,
912 sizeof(Startup_ST_STATE),
913 TPM_DURATION_TYPE_SHORT);
914 break;
915 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500916 ret = tpm_build_and_send_cmd(0, TPM2_CC_Startup,
917 Startup_SU_STATE,
918 sizeof(Startup_SU_STATE),
919 TPM_DURATION_TYPE_SHORT);
920
921 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
922 ret);
923
924 if (ret)
925 goto err_exit;
926
927
928 ret = tpm_build_and_send_cmd(0, TPM2_CC_SelfTest,
929 TPM2_SelfTest_YES, sizeof(TPM2_SelfTest_YES),
930 TPM_DURATION_TYPE_LONG);
931
932 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
933 ret);
934
Stefan Berger1d37d522016-02-02 13:09:11 -0500935 break;
936 }
937
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500938 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400939 goto err_exit;
940
Kevin O'Connord6aca442015-06-10 11:00:17 -0400941 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400942
943err_exit:
944 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
945
Stefan Berger7fce1d92015-11-12 10:14:45 -0500946 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400947}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500948
949
950/****************************************************************
951 * BIOS interface
952 ****************************************************************/
953
Kevin O'Connor59076132015-11-28 13:55:09 -0500954u8 TPM_interface_shutdown VARLOW;
955
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500956static inline void *input_buf32(struct bregs *regs)
957{
958 return MAKE_FLATPTR(regs->es, regs->di);
959}
960
961static inline void *output_buf32(struct bregs *regs)
962{
963 return MAKE_FLATPTR(regs->ds, regs->si);
964}
965
966static u32
967hash_log_extend_event_int(const struct hleei_short *hleei_s,
968 struct hleeo *hleeo)
969{
970 u32 rc = 0;
971 struct hleo hleo;
972 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
973 const void *logdataptr;
974 u32 logdatalen;
975 struct pcpes *pcpes;
976 u32 pcrindex;
977
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500978 /* short or long version? */
979 switch (hleei_s->ipblength) {
980 case sizeof(struct hleei_short):
981 /* short */
982 logdataptr = hleei_s->logdataptr;
983 logdatalen = hleei_s->logdatalen;
984 pcrindex = hleei_s->pcrindex;
985 break;
986
987 case sizeof(struct hleei_long):
988 /* long */
989 logdataptr = hleei_l->logdataptr;
990 logdatalen = hleei_l->logdatalen;
991 pcrindex = hleei_l->pcrindex;
992 break;
993
994 default:
995 /* bad input block */
996 rc = TCG_INVALID_INPUT_PARA;
997 goto err_exit;
998 }
999
1000 pcpes = (struct pcpes *)logdataptr;
1001
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001002 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != pcrindex
1003 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001004 rc = TCG_INVALID_INPUT_PARA;
1005 goto err_exit;
1006 }
1007
Kevin O'Connor92244402015-11-22 16:54:18 -05001008 tpm_fill_hash(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001009 int ret = tpm_log_extend_event(pcpes, pcpes->event);
1010 if (ret) {
1011 rc = TCG_TCG_COMMAND_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001012 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001013 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001014
1015 hleeo->opblength = sizeof(struct hleeo);
1016 hleeo->reserved = 0;
1017 hleeo->eventnumber = hleo.eventnumber;
Stefan Berger2b237502016-01-07 12:02:46 -05001018 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001019
1020err_exit:
1021 if (rc != 0) {
1022 hleeo->opblength = 4;
1023 hleeo->reserved = 0;
1024 }
1025
1026 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001027}
1028
1029static u32
1030pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1031{
1032 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001033 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001034
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001035 if (pttti->ipblength < sizeof(struct pttti) + sizeof(trh)
1036 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1037 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001038 rc = TCG_INVALID_INPUT_PARA;
1039 goto err_exit;
1040 }
1041
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001042 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001043 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1044 TPM_DURATION_TYPE_LONG /* worst case */);
1045 if (ret) {
1046 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001047 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001048 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001049
1050 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1051 pttto->reserved = 0;
1052
1053err_exit:
1054 if (rc != 0) {
1055 pttto->opblength = 4;
1056 pttto->reserved = 0;
1057 }
1058
1059 return rc;
1060}
1061
1062static u32
1063shutdown_preboot_interface(void)
1064{
Kevin O'Connor59076132015-11-28 13:55:09 -05001065 TPM_interface_shutdown = 1;
1066 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001067}
1068
1069static u32
1070hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1071{
1072 u32 rc = 0;
1073 u16 size;
1074 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001075
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001076 size = hlei->ipblength;
1077 if (size != sizeof(*hlei)) {
1078 rc = TCG_INVALID_INPUT_PARA;
1079 goto err_exit;
1080 }
1081
1082 pcpes = (struct pcpes *)hlei->logdataptr;
1083
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001084 if (pcpes->pcrindex >= 24 || pcpes->pcrindex != hlei->pcrindex
1085 || pcpes->eventtype != hlei->logeventtype
1086 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001087 rc = TCG_INVALID_INPUT_PARA;
1088 goto err_exit;
1089 }
1090
Kevin O'Connor92244402015-11-22 16:54:18 -05001091 tpm_fill_hash(pcpes, hlei->hashdataptr, hlei->hashdatalen);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001092 int ret = tpm_log_event(pcpes, pcpes->event);
1093 if (ret) {
1094 rc = TCG_PC_LOGOVERFLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001095 goto err_exit;
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001096 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001097
1098 /* updating the log was fine */
1099 hleo->opblength = sizeof(struct hleo);
1100 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001101 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001102
1103err_exit:
1104 if (rc != 0) {
1105 hleo->opblength = 2;
1106 hleo->reserved = 0;
1107 }
1108
1109 return rc;
1110}
1111
1112static u32
1113hash_all_int(const struct hai *hai, u8 *hash)
1114{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001115 if (hai->ipblength != sizeof(struct hai) ||
1116 hai->hashdataptr == 0 ||
1117 hai->hashdatalen == 0 ||
1118 hai->algorithmid != TPM_ALG_SHA)
1119 return TCG_INVALID_INPUT_PARA;
1120
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001121 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1122 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001123}
1124
1125static u32
1126tss_int(struct ti *ti, struct to *to)
1127{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001128 to->opblength = sizeof(struct to);
1129 to->reserved = 0;
1130
Kevin O'Connor59076132015-11-28 13:55:09 -05001131 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001132}
1133
1134static u32
1135compact_hash_log_extend_event_int(u8 *buffer,
1136 u32 info,
1137 u32 length,
1138 u32 pcrindex,
1139 u32 *edx_ptr)
1140{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001141 struct pcpes pcpes = {
1142 .pcrindex = pcrindex,
1143 .eventtype = EV_COMPACT_HASH,
1144 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001145 };
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001146
Kevin O'Connor92244402015-11-22 16:54:18 -05001147 tpm_fill_hash(&pcpes, buffer, length);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001148 int ret = tpm_log_extend_event(&pcpes, &info);
1149 if (ret)
1150 return TCG_TCG_COMMAND_ERROR;
1151 *edx_ptr = tpm_state.entry_count;
1152 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001153}
1154
1155void VISIBLE32FLAT
1156tpm_interrupt_handler32(struct bregs *regs)
1157{
1158 if (!CONFIG_TCGBIOS)
1159 return;
1160
1161 set_cf(regs, 0);
1162
Kevin O'Connor59076132015-11-28 13:55:09 -05001163 if (TPM_interface_shutdown && regs->al) {
1164 regs->eax = TCG_INTERFACE_SHUTDOWN;
1165 return;
1166 }
1167
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001168 switch ((enum irq_ids)regs->al) {
1169 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001170 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001171 /* no TPM available */
1172 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1173 } else {
1174 regs->eax = 0;
1175 regs->ebx = TCG_MAGIC;
1176 regs->ch = TCG_VERSION_MAJOR;
1177 regs->cl = TCG_VERSION_MINOR;
1178 regs->edx = 0x0;
1179 regs->esi = (u32)tpm_state.log_area_start_address;
1180 regs->edi = (u32)tpm_state.log_area_last_entry;
1181 }
1182 break;
1183
1184 case TCG_HashLogExtendEvent:
1185 regs->eax =
1186 hash_log_extend_event_int(
1187 (struct hleei_short *)input_buf32(regs),
1188 (struct hleeo *)output_buf32(regs));
1189 break;
1190
1191 case TCG_PassThroughToTPM:
1192 regs->eax =
1193 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1194 (struct pttto *)output_buf32(regs));
1195 break;
1196
1197 case TCG_ShutdownPreBootInterface:
1198 regs->eax = shutdown_preboot_interface();
1199 break;
1200
1201 case TCG_HashLogEvent:
1202 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1203 (struct hleo*)output_buf32(regs));
1204 break;
1205
1206 case TCG_HashAll:
1207 regs->eax =
1208 hash_all_int((struct hai*)input_buf32(regs),
1209 (u8 *)output_buf32(regs));
1210 break;
1211
1212 case TCG_TSS:
1213 regs->eax = tss_int((struct ti*)input_buf32(regs),
1214 (struct to*)output_buf32(regs));
1215 break;
1216
1217 case TCG_CompactHashLogExtendEvent:
1218 regs->eax =
1219 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1220 regs->esi,
1221 regs->ecx,
1222 regs->edx,
1223 &regs->edx);
1224 break;
1225
1226 default:
1227 set_cf(regs, 1);
1228 }
1229
1230 return;
1231}
Stefan Berger320df852015-11-30 11:14:19 -05001232
Kevin O'Connor26e36172015-12-29 12:20:23 -05001233
1234/****************************************************************
1235 * TPM Configuration Menu
1236 ****************************************************************/
1237
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001238static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001239tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001240{
Stefan Berger320df852015-11-30 11:14:19 -05001241 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001242 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1243 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001244 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001245 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001246
1247 *has_owner = oauth.flag;
1248
1249 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001250}
1251
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001252static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001253tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001254{
Stefan Berger320df852015-11-30 11:14:19 -05001255 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001256 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001257 if (ret)
1258 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001259
1260 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1261 return 0;
1262
Stefan Berger1d37d522016-02-02 13:09:11 -05001263 ret = tpm_build_and_send_cmd(0, enable ? TPM_ORD_PhysicalEnable
1264 : TPM_ORD_PhysicalDisable,
1265 NULL, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001266 if (ret) {
1267 if (enable)
1268 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1269 else
1270 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1271 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001272 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001273}
1274
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001275static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001276tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001277{
Stefan Berger320df852015-11-30 11:14:19 -05001278 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001279 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001280 if (ret)
1281 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001282
1283 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1284 return 0;
1285
1286 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1287 return 0;
1288
Stefan Berger1d37d522016-02-02 13:09:11 -05001289 ret = tpm_build_and_send_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1290 activate ? CommandFlag_FALSE
1291 : CommandFlag_TRUE,
1292 activate ? sizeof(CommandFlag_FALSE)
1293 : sizeof(CommandFlag_TRUE),
1294 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001295 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001296 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001297
1298 if (activate && allow_reset) {
1299 if (verbose) {
1300 printf("Requiring a reboot to activate the TPM.\n");
1301
1302 msleep(2000);
1303 }
1304 reset();
1305 }
1306
1307 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001308}
1309
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001310static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001311tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001312{
Stefan Berger1d37d522016-02-02 13:09:11 -05001313 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001314 if (ret)
1315 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001316
Stefan Berger1d37d522016-02-02 13:09:11 -05001317 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001318}
1319
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001320static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001321tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1322 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001323{
Stefan Berger320df852015-11-30 11:14:19 -05001324 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001325 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001326 if (ret)
1327 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001328 if (!has_owner) {
1329 if (verbose)
1330 printf("TPM does not have an owner.\n");
1331 return 0;
1332 }
1333
1334 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001335 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001336 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001337 dprintf(DEBUG_tcg,
1338 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001339 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001340 }
1341 }
1342
Stefan Berger1d37d522016-02-02 13:09:11 -05001343 ret = tpm_build_and_send_cmd(0, TPM_ORD_ForceClear,
1344 NULL, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001345 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001346 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001347
1348 if (!enable_activate_after) {
1349 if (verbose)
1350 printf("Owner successfully cleared.\n"
1351 "You will need to enable/activate the TPM again.\n\n");
1352 return 0;
1353 }
1354
Stefan Berger1d37d522016-02-02 13:09:11 -05001355 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001356}
1357
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001358static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001359tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001360{
Stefan Berger320df852015-11-30 11:14:19 -05001361 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001362 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001363 if (ret)
1364 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001365 if (has_owner) {
1366 if (verbose)
1367 printf("Must first remove owner.\n");
1368 return 0;
1369 }
1370
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001371 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001372 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001373 if (ret)
1374 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001375
1376 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1377 if (verbose)
1378 printf("TPM must first be enable.\n");
1379 return 0;
1380 }
1381
Stefan Berger1d37d522016-02-02 13:09:11 -05001382 ret = tpm_build_and_send_cmd(0, TPM_ORD_SetOwnerInstall,
1383 (allow) ? CommandFlag_TRUE
1384 : CommandFlag_FALSE,
1385 sizeof(CommandFlag_TRUE),
1386 TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001387 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001388 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001389
1390 if (verbose)
1391 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1392
1393 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001394}
1395
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001396static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001397tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001398{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001399 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001400
1401 switch (msgCode) {
1402 case TPM_PPI_OP_NOOP: /* no-op */
1403 break;
1404
1405 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001406 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001407 break;
1408
1409 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001410 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001411 break;
1412
1413 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001414 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001415 break;
1416
1417 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001418 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001419 break;
1420
1421 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001422 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001423 break;
1424
1425 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001426 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001427 break;
1428
1429 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001430 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001431 break;
1432
1433 default:
1434 break;
1435 }
1436
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001437 if (ret)
1438 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001439
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001440 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001441}
1442
1443static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001444tpm20_clearcontrol(u8 disable, int verbose)
1445{
1446 struct tpm2_req_clearcontrol trc = {
1447 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1448 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1449 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1450 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1451 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1452 .authblock = {
1453 .handle = cpu_to_be32(TPM2_RS_PW),
1454 .noncesize = cpu_to_be16(0),
1455 .contsession = TPM2_YES,
1456 .pwdsize = cpu_to_be16(0),
1457 },
1458 .disable = disable,
1459 };
1460 struct tpm_rsp_header rsp;
1461 u32 resp_length = sizeof(rsp);
1462 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1463 TPM_DURATION_TYPE_SHORT);
1464 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1465 ret = -1;
1466
1467 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1468 ret);
1469
1470 return ret;
1471}
1472
1473static int
1474tpm20_clear(void)
1475{
1476 struct tpm2_req_clear trq = {
1477 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1478 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1479 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1480 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1481 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1482 .authblock = {
1483 .handle = cpu_to_be32(TPM2_RS_PW),
1484 .noncesize = cpu_to_be16(0),
1485 .contsession = TPM2_YES,
1486 .pwdsize = cpu_to_be16(0),
1487 },
1488 };
1489 struct tpm_rsp_header rsp;
1490 u32 resp_length = sizeof(rsp);
1491 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1492 TPM_DURATION_TYPE_MEDIUM);
1493 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1494 ret = -1;
1495
1496 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1497 ret);
1498
1499 return ret;
1500}
1501
1502static int
1503tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1504{
1505 int ret = 0;
1506
1507 switch (msgCode) {
1508 case TPM_PPI_OP_NOOP: /* no-op */
1509 break;
1510
1511 case TPM_PPI_OP_CLEAR:
1512 ret = tpm20_clearcontrol(0, verbose);
1513 if (!ret)
1514 ret = tpm20_clear();
1515 break;
1516 }
1517
1518 if (ret)
1519 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
1520
1521 return ret;
1522}
1523
1524static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001525tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05001526{
1527 int state = 0;
1528 struct tpm_permanent_flags pf;
1529 int has_owner;
1530
Stefan Berger1d37d522016-02-02 13:09:11 -05001531 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
1532 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05001533 return ~0;
1534
1535 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
1536 state |= TPM_STATE_ENABLED;
1537
1538 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
1539 state |= TPM_STATE_ACTIVE;
1540
1541 if (has_owner) {
1542 state |= TPM_STATE_OWNED;
1543 } else {
1544 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
1545 state |= TPM_STATE_OWNERINSTALL;
1546 }
1547
1548 return state;
1549}
1550
1551static void
Stefan Berger1d37d522016-02-02 13:09:11 -05001552tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05001553{
1554 int i = 0;
1555
1556 printf("\nThe current state of the TPM is:\n");
1557
1558 if (state & TPM_STATE_ENABLED)
1559 printf(" Enabled");
1560 else
1561 printf(" Disabled");
1562
1563 if (state & TPM_STATE_ACTIVE)
1564 printf(" and active\n");
1565 else
1566 printf(" and deactivated\n");
1567
1568 if (state & TPM_STATE_OWNED)
1569 printf(" Ownership has been taken\n");
1570 else {
1571 printf(" Ownership has not been taken\n");
1572 if (state & TPM_STATE_OWNERINSTALL)
1573 printf(" A user can take ownership of the TPM\n");
1574 else
1575 printf(" Taking ownership of the TPM has been disabled\n");
1576 }
1577
1578 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
1579 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
1580 printf("\nNote: To make use of all functionality, the TPM must be "
1581 "enabled and active.\n");
1582 }
1583
1584 printf("\nAvailable options are:\n");
1585 if (state & TPM_STATE_ENABLED) {
1586 printf(" d. Disable the TPM\n");
1587 next_scancodes[i++] = 32;
1588
1589 if (state & TPM_STATE_ACTIVE) {
1590 printf(" v. Deactivate the TPM\n");
1591 next_scancodes[i++] = 47;
1592
1593 if (state & TPM_STATE_OWNERINSTALL) {
1594 printf(" p. Prevent installation of an owner\n");
1595 next_scancodes[i++] = 25;
1596 } else {
1597 printf(" s. Allow installation of an owner\n");
1598 next_scancodes[i++] = 31;
1599 }
1600 } else {
1601 printf(" a. Activate the TPM\n");
1602 next_scancodes[i++] = 30;
1603 }
1604
1605 } else {
1606 printf(" e. Enable the TPM\n");
1607 next_scancodes[i++] = 18;
1608 }
1609
1610 if (state & TPM_STATE_OWNED) {
1611 printf(" c. Clear ownership\n");
1612 next_scancodes[i++] = 46;
1613 }
1614
1615 next_scancodes[i++] = 0;
1616}
1617
Stefan Berger1d37d522016-02-02 13:09:11 -05001618static void
1619tpm12_menu(void)
Stefan Berger320df852015-11-30 11:14:19 -05001620{
Stefan Berger320df852015-11-30 11:14:19 -05001621 int scancode, next_scancodes[7];
Stefan Berger320df852015-11-30 11:14:19 -05001622 tpm_ppi_code msgCode;
1623 int state = 0, i;
1624 int waitkey;
1625
Stefan Berger320df852015-11-30 11:14:19 -05001626 printf("The Trusted Platform Module (TPM) is a hardware device in "
1627 "this machine.\n"
1628 "It can help verify the integrity of system software.\n\n");
1629
1630 for (;;) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001631 if ((state = tpm12_get_tpm_state()) != ~0) {
1632 tpm12_show_tpm_menu(state, next_scancodes);
Stefan Berger320df852015-11-30 11:14:19 -05001633 } else {
1634 printf("TPM is not working correctly.\n");
1635 return;
1636 }
1637
1638 printf("\nIf no change is desired or if this menu was reached by "
1639 "mistake, press ESC to\n"
1640 "reboot the machine.\n");
1641
1642 msgCode = TPM_PPI_OP_NOOP;
1643
1644 waitkey = 1;
1645
1646 while (waitkey) {
1647 while ((scancode = get_keystroke(1000)) == ~0)
1648 ;
1649
1650 switch (scancode) {
1651 case 1:
1652 // ESC
1653 reset();
1654 break;
1655 case 18: /* e. enable */
1656 msgCode = TPM_PPI_OP_ENABLE;
1657 break;
1658 case 32: /* d. disable */
1659 msgCode = TPM_PPI_OP_DISABLE;
1660 break;
1661 case 30: /* a. activate */
1662 msgCode = TPM_PPI_OP_ACTIVATE;
1663 break;
1664 case 47: /* v. deactivate */
1665 msgCode = TPM_PPI_OP_DEACTIVATE;
1666 break;
1667 case 46: /* c. clear owner */
1668 msgCode = TPM_PPI_OP_CLEAR;
1669 break;
1670 case 25: /* p. prevent ownerinstall */
1671 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_FALSE;
1672 break;
1673 case 31: /* s. allow ownerinstall */
1674 msgCode = TPM_PPI_OP_SET_OWNERINSTALL_TRUE;
1675 break;
1676 default:
1677 continue;
1678 }
1679
1680 /*
1681 * Using the next_scancodes array, check whether the
1682 * pressed key is currently a valid option.
1683 */
1684 for (i = 0; i < sizeof(next_scancodes); i++) {
1685 if (next_scancodes[i] == 0)
1686 break;
1687
1688 if (next_scancodes[i] == scancode) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001689 tpm12_process_cfg(msgCode, 1);
Stefan Berger320df852015-11-30 11:14:19 -05001690 waitkey = 0;
1691 break;
1692 }
1693 }
1694 }
1695 }
1696}
Stefan Berger1d37d522016-02-02 13:09:11 -05001697
Stefan Berger7d596dc2016-02-02 13:09:16 -05001698static void
1699tpm20_menu(void)
1700{
1701 int scan_code;
1702 tpm_ppi_code msgCode;
1703
1704 for (;;) {
1705 printf("1. Clear TPM\n");
1706
1707 printf("\nIf no change is desired or if this menu was reached by "
1708 "mistake, press ESC to\n"
1709 "reboot the machine.\n");
1710
1711 msgCode = TPM_PPI_OP_NOOP;
1712
1713 while ((scan_code = get_keystroke(1000)) == ~0)
1714 ;
1715
1716 switch (scan_code) {
1717 case 1:
1718 // ESC
1719 reset();
1720 break;
1721 case 2:
1722 msgCode = TPM_PPI_OP_CLEAR;
1723 break;
1724 default:
1725 continue;
1726 }
1727
1728 tpm20_process_cfg(msgCode, 0);
1729 }
1730}
1731
Stefan Berger1d37d522016-02-02 13:09:11 -05001732void
1733tpm_menu(void)
1734{
1735 if (!CONFIG_TCGBIOS)
1736 return;
1737
1738 while (get_keystroke(0) >= 0)
1739 ;
1740 wait_threads();
1741
1742 switch (TPM_version) {
1743 case TPM_VERSION_1_2:
1744 tpm12_menu();
1745 break;
1746 case TPM_VERSION_2:
Stefan Berger7d596dc2016-02-02 13:09:16 -05001747 tpm20_menu();
Stefan Berger1d37d522016-02-02 13:09:11 -05001748 break;
1749 }
1750}